diff --git a/.dir-locals.el b/.dir-locals.el index bd65e5345441f..feea22ea295c1 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -2,7 +2,7 @@ ; ; This source file is part of the Swift.org open source project ; -; Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +; Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors ; Licensed under Apache License v2.0 with Runtime Library Exception ; ; See http://swift.org/LICENSE.txt for license information diff --git a/CHANGELOG.md b/CHANGELOG.md index fc79f27731e14..9f9c92edcdba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ -Latest ------- + +Swift 3 +------- + +* Curried function syntax has been removed, and now produces a compile-time + error. + + +Swift 2.2 +--------- + +* Associated types in protocols can now be specified with a new 'associatedtype' + declaration, to replace the use of 'typealias': + + protocol P { + associatedtype Ty + } + + The typealias keyword is still allowed (but deprecated and produces a warning) + in Swift 2.2. This warning will become an error in Swift 3. + +* Curried function syntax has been deprecated, and is slated to be removed in + Swift 3. + +* The ++ and -- operators have been deprecated, and are slated to be removed in + Swift 3.0. As a replacement, please use "x += 1" on integer or floating point + types, and "x = x.successor()" on Index types. + +* The operator identifier lexer grammar has been revised to simplify the rules + for operators that start with a dot ("."). The new rule is that an operator + that starts with a dot may contain other dots in it, but operators that start + with some other character may not contain dots. For example: + + ``` + x....foo --> "x" "...." "foo" + x&%^.foo --> "x" "&%^" ".foo" + ``` + + This eliminates a special case for the ..< operator, folding it into a simple + and consistent rule. + +* The "C-style for loop", which is spelled `for init; comparison; increment {}` + has been deprecated and is slated for removal in Swift 3.0. See + [SE-0007](https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md) + for more information. + * Three new doc comment fields, namely `- keyword:`, `- recommended:` and `- recommendedover:`, allow Swift users to cooperate with code completion engine to deliver more effective code completion results. @@ -31,7 +75,8 @@ Latest * `ArraySlice.removeFirst()` now preserves element indices. * Global `anyGenerator()` functions have been changed into initializers on - `AnyGenerator`, making the API more intuitive and idiomatic. + `AnyGenerator`, making the API more intuitive and idiomatic. They have been + deprecated in Swift 2.2, and will be removed in Swift 3. * Closures appearing inside generic types and generic methods can now be converted to C function pointers as long as no generic type parameters @@ -58,6 +103,78 @@ Latest **(rdar://problem/21683348)** +* Argument labels and parameter names can now be any keyword except + `var`, `let`, or `inout`. For example: + + NSURLProtectionSpace(host: "somedomain.com", port: 443, protocol: "https", realm: "Some Domain", authenticationMethod: "Basic") + + would previously have required `protocol` to be surrounded in + back-ticks. For more information, see + [SE-0001](https://github.com/apple/swift-evolution/blob/master/proposals/0001-keywords-as-argument-labels.md). + +* Tuples (up to arity 6) whose elements are all `Comparable` or `Equatable` now + implement the full set of comparison/equality operators. The comparison + operators are defined in terms of [lexicographical order][]. See [SE-0015][] + for more information. + +[lexicographical order]: https://en.wikipedia.org/wiki/Lexicographical_order +[SE-0015]: https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md + +* The `@objc(SomeName)` attribute is now supported on enums and enum cases to + rename the generated Objective-C declaration. + + **(rdar://problem/21930334)** + +* When referencing a function or initializer, one can provide the + complete name, including argument labels. For example: + + let fn1 = someView.insertSubview(_:at:) + let fn2 = someView.insertSubview(_:aboveSubview:) + + let buttonFactory = UIButton.init(type:) + + For more information, see [SE-0021](https://github.com/apple/swift-evolution/blob/master/proposals/0021-generalized-naming.md). + +* There is a new build configuration function, `#if swift(>=x.y)`, which + tests if the current Swift language version is at least `x.y`. This + allows you to conditionally compile code for multiple language + versions in the same file, even with different syntax, by deactivating + parsing in inactive code blocks. For example: + + ```swift + #if swift(>=2.2) + // Only this code will be parsed in Swift 3 + func foo(x: Int) -> (y: Int) -> () {} + #else + // This code is ignored entirely. + func foo(x: Int)(y: Int) {} + #endif + ``` + + For more information, see [SE-0020](https://github.com/apple/swift-evolution/blob/master/proposals/0020-if-swift-version.md). + +* The Objective-C selector of a Swift method can now be determined + directly with the #selector expression, e.g.,: + + let sel = #selector(insertSubview(_:aboveSubview:)) // sel has type Selector + + Along with this change, the use of string literals as selectors has + been deprecated, e.g., + + let sel: Selector = "insertSubview:aboveSubview:" + + Generally, such string literals should be replaced with uses of + `#selector`, and the compiler will provide Fix-Its that use + `#selector`. In cases where they is not possible (e.g., when referring + to the getter of a property), one can still directly construct + selectors, e.g.,: + + let sel = Selector("propertyName") + + Note that the compiler is now checking the string literals used to + construct Selectors to ensure that they are well-formed Objective-C + selectors and that there is an '@objc' method with that selector. + 2015-09-17 [Xcode 7.1, Swift 2.1] ---------- @@ -67,7 +184,7 @@ Latest allows you to use C enum pattern matching in switch statements with no additional code. **(17287720)** -* The `NSNumberunsignedIntegerValue` property now has the type `UInt` instead +* The `NSNumber.unsignedIntegerValue` property now has the type `UInt` instead of `Int`, as do other methods and properties that use the `NSUInteger` type in Objective-C and whose names contain `unsigned..`. Most other uses of `NSUInteger` in system frameworks are imported as `Int` as they were in @@ -1342,7 +1459,7 @@ Latest unique elements with full value semantics. It bridges with `NSSet`, providing functionality analogous to `Array` and `Dictionary`. **(14661754)** -* The `if–let` construct has been expanded to allow testing multiple optionals +* The `if-let` construct has been expanded to allow testing multiple optionals and guarding conditions in a single `if` (or `while`) statement using syntax similar to generic constraints: @@ -1356,7 +1473,7 @@ Latest conditions, without introducing undesirable nesting (for instance, to avoid the optional unwrapping _"pyramid of doom"_). - Further, `if–let` now also supports a single leading boolean condition along + Further, `if-let` now also supports a single leading boolean condition along with optional binding `let` clauses. For example: ```swift @@ -1366,7 +1483,7 @@ Latest **(19797158, 19382942)** -* The `if–let` syntax has been extended to support a single leading boolean +* The `if-let` syntax has been extended to support a single leading boolean condition along with optional binding `let` clauses. For example: @@ -3865,9 +3982,9 @@ Latest themselves. Overall, a property now may either be "stored" (the default), "computed" - (have a `get:` and optionally a `set:` specifier), or a observed + (have a `get:` and optionally a `set:` specifier), or an observed (`willSet`/`didSet`) property. It is not possible to have a custom getter - or setter on a observed property, since they have storage. + or setter on an observed property, since they have storage. Two known-missing bits are: - **(rdar://problem/15920332) didSet/willSet variables need to allow initializers** diff --git a/CMakeLists.txt b/CMakeLists.txt index 916e3afc3dbff..83abf47494762 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,10 @@ option(SWIFT_STDLIB_ASSERTIONS "Enable internal checks for the Swift standard library (useful for debugging the library itself, does not affect checks required for safety)" "${SWIFT_STDLIB_ASSERTIONS_default}") +option(SWIFT_SERIALIZE_STDLIB_UNITTEST + "Compile the StdlibUnittest module with -sil-serialize-all to increase the test coverage for the optimizer" + FALSE) + option(SWIFT_BUILD_TOOLS "Build the Swift compiler and other tools" TRUE) @@ -44,9 +48,9 @@ option(SWIFT_BUILD_STATIC_STDLIB "Build static variants of the Swift standard library and SDK overlay" FALSE) -option(SWIFT_INCLUDE_BENCHMARKS - "Create targets for running swift benchmarks" - TRUE) +option(SWIFT_BUILD_PERF_TESTSUITE + "Create targets for swift performance benchmarks." + FALSE) option(SWIFT_INCLUDE_TESTS "Create targets for building/running tests." TRUE) @@ -54,7 +58,7 @@ option(SWIFT_INCLUDE_DOCS "Create targets for building docs." TRUE) -set(SWIFT_VERSION "2.2" CACHE STRING +set(SWIFT_VERSION "3.0" CACHE STRING "The user-visible version of the Swift compiler") set(SWIFT_VENDOR "" CACHE STRING "The vendor name of the Swift compiler") @@ -69,7 +73,7 @@ set(SWIFT_ENABLE_GOLD_LINKER FALSE CACHE BOOL "Enable using the gold linker when available") set(_SWIFT_KNOWN_INSTALL_COMPONENTS - "compiler;clang-builtin-headers;clang-resource-dir-symlink;clang-builtin-headers-in-clang-resource-dir;stdlib;stdlib-experimental;sdk-overlay;editor-integration;tools;testsuite-tools;dev;sourcekit-xpc-service;sourcekit-inproc") + "compiler;clang-builtin-headers;clang-resource-dir-symlink;clang-builtin-headers-in-clang-resource-dir;stdlib;stdlib-experimental;sdk-overlay;editor-integration;tools;testsuite-tools;dev;license;sourcekit-xpc-service;sourcekit-inproc") # Set the SWIFT_INSTALL_COMPONENTS variable to the default value if it is not passed in via -D set(SWIFT_INSTALL_COMPONENTS "${_SWIFT_KNOWN_INSTALL_COMPONENTS}" CACHE STRING @@ -125,6 +129,9 @@ option(SWIFT_RUNTIME_CRASH_REPORTER_CLIENT "Whether to enable CrashReporter integration" FALSE) +set(SWIFT_DARWIN_XCRUN_TOOLCHAIN "XcodeDefault" CACHE STRING + "The name of the toolchain to pass to 'xcrun'") + set(SWIFT_DARWIN_ICU_INCLUDE_PATH "" CACHE STRING "Path to the directory where the ICU headers are located") @@ -151,7 +158,7 @@ option(SWIFT_AST_VERIFIER "Enable the AST verifier in the built compiler, and run it on every compilation" TRUE) -option(SWIFT_VERIFY_ALL +option(SWIFT_SIL_VERIFY_ALL "Run SIL verification after each transform when building Swift files in the build process" FALSE) @@ -180,11 +187,7 @@ set(SWIFT_EXPERIMENTAL_EXTRA_REGEXP_FLAGS "" CACHE STRING "A list of [module_regexp1;flags1;module_regexp2;flags2,...] which can be used to apply specific flags to modules that match a cmake regexp. It always applies the first regexp that matches.") set(SWIFT_EXPERIMENTAL_EXTRA_NEGATIVE_REGEXP_FLAGS "" CACHE STRING - "A list of [module_regexp1;flags1;module_regexp2;flags2,...] which can be used to apply specific flags to modules that do not match a cmake regexp. It always applies the first regexp that does not matche. The reason this is necessary is that cmake does not provide negative matches in the regex. Instead you have to use NOT in the if statement requiring a separate variable.") - -option(SWIFT_RUNTIME_ENABLE_DTRACE - "Should the runtime be built with dtrace instrumentation enabled" - FALSE) + "A list of [module_regexp1;flags1;module_regexp2;flags2,...] which can be used to apply specific flags to modules that do not match a cmake regexp. It always applies the first regexp that does not match. The reason this is necessary is that cmake does not provide negative matches in the regex. Instead you have to use NOT in the if statement requiring a separate variable.") option(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER "Should the runtime be built with support for non-thread-safe leak detecting entrypoints" @@ -222,9 +225,6 @@ endif() option(SWIFT_BUILD_SOURCEKIT "Build SourceKit" ${SWIFT_BUILD_SOURCEKIT_default}) -# Force updating the cache, remove the following after a couple of weeks or so. -set(SWIFT_BUILD_SOURCEKIT ${SWIFT_BUILD_SOURCEKIT_default} - CACHE BOOL "Build SourceKit" FORCE) # # Include CMake modules @@ -398,6 +398,11 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") configure_sdk_unix(LINUX "Linux" "linux" "linux" "x86_64" "x86_64-unknown-linux-gnu") set(SWIFT_HOST_VARIANT_ARCH "x86_64") set(SWIFT_PRIMARY_VARIANT_ARCH_default "x86_64") + # FIXME: This only matches ARMv6l (by far the most common variant). + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") + configure_sdk_unix(LINUX "Linux" "linux" "linux" "armv6" "armv6-unknown-linux-gnueabihf") + set(SWIFT_HOST_VARIANT_ARCH "armv6") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "armv6") # FIXME: This only matches ARMv7l (by far the most common variant). elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") configure_sdk_unix(LINUX "Linux" "linux" "linux" "armv7" "armv7-unknown-linux-gnueabihf") @@ -407,6 +412,14 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") configure_sdk_unix(LINUX "Linux" "linux" "linux" "aarch64" "aarch64-unknown-linux-gnu") set(SWIFT_HOST_VARIANT_ARCH "aarch64") set(SWIFT_PRIMARY_VARIANT_ARCH_default "aarch64") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") + configure_sdk_unix(LINUX "Linux" "linux" "linux" "powerpc64" "powerpc64-unknown-linux-gnu") + set(SWIFT_HOST_VARIANT_ARCH "powerpc64") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "powerpc64") + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") + configure_sdk_unix(LINUX "Linux" "linux" "linux" "powerpc64le" "powerpc64le-unknown-linux-gnu") + set(SWIFT_HOST_VARIANT_ARCH "powerpc64le") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "powerpc64le") else() message(FATAL_ERROR "Unknown or unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -461,7 +474,7 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") endif() if(XCODE) - # FIXME: Can not cross-compile stdlib using Xcode. Xcode insists on + # FIXME: Cannot cross-compile stdlib using Xcode. Xcode insists on # passing -mmacosx-version-min to the compiler, and we want to pass # -mios-version-min. Clang sees both options and complains. set(swift_can_crosscompile_stdlib FALSE) @@ -584,6 +597,11 @@ endif() set(SWIFT_PRIMARY_VARIANT_SUFFIX "-${SWIFT_SDK_${SWIFT_PRIMARY_VARIANT_SDK}_LIB_SUBDIR}-${SWIFT_PRIMARY_VARIANT_ARCH}") +# Clear universal library names to prevent adding duplicates +foreach(sdk ${SWIFT_SDKS}) + unset(UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR} CACHE) +endforeach() + message(STATUS "Building host Swift tools for ${SWIFT_HOST_VARIANT_SDK} ${SWIFT_HOST_VARIANT_ARCH}") message(STATUS " Build type: ${CMAKE_BUILD_TYPE}") message(STATUS " Assertions: ${LLVM_ENABLE_ASSERTIONS}") @@ -610,6 +628,10 @@ if(LIBXML2_FOUND) set(SWIFT_HAVE_LIBXML 1) endif() +if (LLVM_ENABLE_DOXYGEN) + message(STATUS "Doxygen: enabled") +endif() + # # Set up global CMake variables for API notes. # @@ -633,7 +655,7 @@ if(SWIFT_BUILD_TOOLS) endif() add_subdirectory(utils) add_subdirectory(stdlib) -if(SWIFT_INCLUDE_BENCHMARKS) +if(SWIFT_BUILD_PERF_TESTSUITE) add_subdirectory(benchmark) endif() if(SWIFT_INCLUDE_TESTS) @@ -644,6 +666,10 @@ if(SWIFT_INCLUDE_DOCS) add_subdirectory(docs) endif() +swift_install_in_component(license + FILES "LICENSE.txt" + DESTINATION "share/swift") + # Add a documentation target so that documentation shows up in the # Xcode project. if(XCODE) diff --git a/README.md b/README.md index ec5d9470ea915..070dd10827e2d 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,9 @@ with version 2 shipped with Ubuntu. If you are building on Ubuntu 14.04 LTS, you'll need to upgrade your clang compiler for C++14 support and create a symlink: - sudo apt-get install clang-3.6 - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100 + sudo apt-get install clang-3.6 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100 ### Getting Sources for Swift and Related Projects diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 360f26884a7da..7ef0477f168db 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -1,13 +1,10 @@ -option(SWIFT_INCLUDE_PERF_TESTSUITE "Create targets for swift performance benchmarks." NO) if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") # Performance test harness only builds on Darwin. - if (SWIFT_INCLUDE_PERF_TESTSUITE) - set(PERF_TESTSUITE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/PerfTestSuite" CACHE STRING "Path to swift performance testsuite repo.") - if(EXISTS ${PERF_TESTSUITE_DIR}/CMakeLists.txt) - add_subdirectory(${PERF_TESTSUITE_DIR}) - else() - message(FATAL_ERROR "Can't find the Swift performance suite at ${PERF_TESTSUITE_DIR}/.") - endif() + set(PERF_TESTSUITE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/PerfTestSuite" CACHE STRING "Path to swift performance testsuite repo.") + if(EXISTS ${PERF_TESTSUITE_DIR}/CMakeLists.txt) + add_subdirectory(${PERF_TESTSUITE_DIR}) + else() + message(FATAL_ERROR "Can't find the Swift performance suite at ${PERF_TESTSUITE_DIR}/.") endif() endif() diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng index 6ee793715ff33..468efa042537e 100644 --- a/bindings/xml/comment-xml-schema.rng +++ b/bindings/xml/comment-xml-schema.rng @@ -767,6 +767,9 @@ + + + diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 9af22f6a23067..2da4d1582771f 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -47,9 +47,9 @@ function(compute_library_subdir result_var_name sdk arch) set("${result_var_name}" "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}" PARENT_SCOPE) endfunction() - function(_add_variant_c_compile_link_flags - sdk arch build_type enable_assertions result_var_name) + sdk arch build_type enable_assertions analyze_code_coverage + result_var_name) set(result ${${result_var_name}} "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}") @@ -62,13 +62,19 @@ function(_add_variant_c_compile_link_flags "-arch" "${arch}" "-F" "${SWIFT_SDK_${sdk}_PATH}/../../../Developer/Library/Frameworks" "-m${SWIFT_SDK_${sdk}_VERSION_MIN_NAME}-version-min=${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}") + + if(analyze_code_coverage) + list(APPEND result "-fprofile-instr-generate=swift-%p.profraw" + "-fcoverage-mapping") + endif() endif() set("${result_var_name}" "${result}" PARENT_SCOPE) endfunction() function(_add_variant_c_compile_flags - sdk arch build_type enable_assertions result_var_name) + sdk arch build_type enable_assertions analyze_code_coverage + result_var_name) set(result ${${result_var_name}}) _add_variant_c_compile_link_flags( @@ -76,6 +82,7 @@ function(_add_variant_c_compile_flags "${arch}" "${build_type}" "${enable_assertions}" + FALSE result) is_build_type_optimized("${build_type}" optimized) @@ -103,6 +110,11 @@ function(_add_variant_c_compile_flags list(APPEND result "-DNDEBUG") endif() + if(analyze_code_coverage) + list(APPEND result "-fprofile-instr-generate=swift-%p.profraw" + "-fcoverage-mapping") + endif() + set("${result_var_name}" "${result}" PARENT_SCOPE) endfunction() @@ -139,7 +151,8 @@ function(_add_variant_swift_compile_flags endfunction() function(_add_variant_link_flags - sdk arch build_type enable_assertions result_var_name) + sdk arch build_type enable_assertions analyze_code_coverage + result_var_name) if("${sdk}" STREQUAL "") message(FATAL_ERROR "Should specify an SDK") @@ -156,12 +169,19 @@ function(_add_variant_link_flags "${arch}" "${build_type}" "${enable_assertions}" + "${analyze_code_coverage}" result) if("${sdk}" STREQUAL "LINUX") - list(APPEND result "-lpthread" "-ldl") + if("${arch}" STREQUAL "armv7") + list(APPEND result "-lpthread" "-ldl" "-Wl,-Bsymbolic") + elseif("${arch}" STREQUAL "armv6") + list(APPEND result "-lpthread" "-ldl" "-Wl,-Bsymbolic") + else() + list(APPEND result "-lpthread" "-ldl") + endif() elseif("${sdk}" STREQUAL "FREEBSD") - # No extra libraries required. + list(APPEND result "-lpthread" "-Wl,-Bsymbolic") else() list(APPEND result "-lobjc") endif() @@ -298,7 +318,7 @@ function(_compile_swift_files dependency_target_out_var_name) # Don't include libarclite in any build products by default. list(APPEND swift_flags "-no-link-objc-runtime") - if(SWIFT_VERIFY_ALL) + if(SWIFT_SIL_VERIFY_ALL) list(APPEND swift_flags "-Xfrontend" "-sil-verify-all") endif() @@ -770,6 +790,11 @@ function(_add_swift_library_single target name) endif() endif() + if (SWIFT_COMPILER_VERSION) + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + set(SWIFTLIB_SINGLE_LINK_FLAGS "${SWIFTLIB_SINGLE_LINK_FLAGS}" "-Xlinker" "-current_version" "-Xlinker" "${SWIFT_COMPILER_VERSION}" "-Xlinker" "-compatibility_version" "-Xlinker" "1") + endif() + endif() if(XCODE) string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR}) @@ -896,8 +921,12 @@ function(_add_swift_library_single target name) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") set(install_name_dir "@rpath") + if(SWIFTLIB_SINGLE_IS_STDLIB) - set(install_name_dir "${SWIFT_DARWIN_STDLIB_INSTALL_NAME_DIR}") + # Always use @rpath for XCTest. + if(NOT "${module_name}" STREQUAL "XCTest") + set(install_name_dir "${SWIFT_DARWIN_STDLIB_INSTALL_NAME_DIR}") + endif() endif() set_target_properties("${target}" @@ -1041,18 +1070,21 @@ function(_add_swift_library_single target name) else() set(build_type "${CMAKE_BUILD_TYPE}") set(enable_assertions "${LLVM_ENABLE_ASSERTIONS}") + set(analyze_code_coverage "${SWIFT_ANALYZE_CODE_COVERAGE}") endif() _add_variant_c_compile_flags( "${SWIFTLIB_SINGLE_SDK}" "${SWIFTLIB_SINGLE_ARCHITECTURE}" "${build_type}" "${enable_assertions}" + "${analyze_code_coverage}" c_compile_flags) _add_variant_link_flags( "${SWIFTLIB_SINGLE_SDK}" "${SWIFTLIB_SINGLE_ARCHITECTURE}" "${build_type}" "${enable_assertions}" + "${analyze_code_coverage}" link_flags) # Handle gold linker flags for shared libraries. @@ -1445,6 +1477,12 @@ function(add_swift_library name) "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") endif() + # Cache universal libraries for dependency purposes + set(UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR} + ${UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR}} + ${UNIVERSAL_LIBRARY_NAME} + CACHE INTERNAL "UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR}") + set(lipo_target "${name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}") _add_swift_lipo_target( ${lipo_target} @@ -1513,6 +1551,11 @@ function(add_swift_library name) add_dependencies("swift-stdlib${VARIANT_SUFFIX}" ${lipo_target} ${lipo_target_static}) + if(NOT "${name}" STREQUAL "swiftStdlibCollectionUnittest") + add_dependencies("swift-test-stdlib${VARIANT_SUFFIX}" + ${lipo_target} + ${lipo_target_static}) + endif() endforeach() endif() endforeach() @@ -1612,14 +1655,14 @@ function(_add_swift_executable_single name) "${SWIFTEXE_SINGLE_ARCHITECTURE}" "${CMAKE_BUILD_TYPE}" "${LLVM_ENABLE_ASSERTIONS}" - FALSE + "${SWIFT_ANALYZE_CODE_COVERAGE}" c_compile_flags) _add_variant_link_flags( "${SWIFTEXE_SINGLE_SDK}" "${SWIFTEXE_SINGLE_ARCHITECTURE}" "${CMAKE_BUILD_TYPE}" "${LLVM_ENABLE_ASSERTIONS}" - FALSE + "${SWIFT_ANALYZE_CODE_COVERAGE}" link_flags) list(APPEND link_flags @@ -1847,37 +1890,3 @@ function(add_swift_executable name) ${SWIFTEXE_DONT_STRIP_NON_MAIN_SYMBOLS_FLAG} ${SWIFTEXE_DISABLE_ASLR_FLAG}) endfunction() - -function(add_swift_llvm_loadable_module name) - add_llvm_loadable_module(${name} ${ARGN}) - set(sdk "${SWIFT_HOST_VARIANT_SDK}") - set(arch "${SWIFT_HOST_VARIANT_ARCH}") - - # Determine compiler flags. - set(c_compile_flags) - _add_variant_c_compile_flags( - "${sdk}" - "${arch}" - "${CMAKE_BUILD_TYPE}" - "${LLVM_ENABLE_ASSERTIONS}" - FALSE - c_compile_flags) - - set(link_flags) - _add_variant_link_flags( - "${sdk}" - "${arch}" - "${CMAKE_BUILD_TYPE}" - "${LLVM_ENABLE_ASSERTIONS}" - FALSE - link_flags) - - # Convert variables to space-separated strings. - _list_escape_for_shell("${c_compile_flags}" c_compile_flags) - _list_escape_for_shell("${link_flags}" link_flags) - - set_property(TARGET ${name} APPEND_STRING PROPERTY - COMPILE_FLAGS " ${c_compile_flags}") - set_property(TARGET ${name} APPEND_STRING PROPERTY - LINK_FLAGS " ${link_flags}") -endfunction() diff --git a/cmake/modules/SwiftSetIfArchBitness.cmake b/cmake/modules/SwiftSetIfArchBitness.cmake index 83d80533f6792..5dc03cc89a6cc 100644 --- a/cmake/modules/SwiftSetIfArchBitness.cmake +++ b/cmake/modules/SwiftSetIfArchBitness.cmake @@ -7,13 +7,16 @@ function(set_if_arch_bitness var_name) ${ARGN}) if("${SIA_ARCH}" STREQUAL "i386" OR + "${SIA_ARCH}" STREQUAL "armv6" OR "${SIA_ARCH}" STREQUAL "armv7" OR "${SIA_ARCH}" STREQUAL "armv7k" OR "${SIA_ARCH}" STREQUAL "armv7s") set("${var_name}" "${SIA_CASE_32_BIT}" PARENT_SCOPE) elseif("${SIA_ARCH}" STREQUAL "x86_64" OR "${SIA_ARCH}" STREQUAL "arm64" OR - "${SIA_ARCH}" STREQUAL "aarch64") + "${SIA_ARCH}" STREQUAL "aarch64" OR + "${SIA_ARCH}" STREQUAL "powerpc64" OR + "${SIA_ARCH}" STREQUAL "powerpc64le") set("${var_name}" "${SIA_CASE_64_BIT}" PARENT_SCOPE) else() message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH}") diff --git a/cmake/modules/SwiftSharedCMakeConfig.cmake b/cmake/modules/SwiftSharedCMakeConfig.cmake index c1d96bceaf403..f9ed4f690f1ca 100644 --- a/cmake/modules/SwiftSharedCMakeConfig.cmake +++ b/cmake/modules/SwiftSharedCMakeConfig.cmake @@ -261,6 +261,11 @@ macro(swift_common_standalone_build_config product is_cross_compiling) set(LLVM_INCLUDE_TESTS TRUE) set(LLVM_INCLUDE_DOCS TRUE) + + option(LLVM_ENABLE_DOXYGEN "Enable doxygen support" FALSE) + if (LLVM_ENABLE_DOXYGEN) + find_package(Doxygen REQUIRED) + endif() endmacro() # Common cmake project config for unified builds. diff --git a/docs/ABI.rst b/docs/ABI.rst index 1c4edc8518b70..eac5ffa982c3f 100644 --- a/docs/ABI.rst +++ b/docs/ABI.rst @@ -410,7 +410,7 @@ contain the following fields: not factored into tuple metadata uniquing. - The **element vector** begins at **offset 3** and consists of a vector of - type–offset pairs. The metadata for the *n*\ th element's type is a pointer + type-offset pairs. The metadata for the *n*\ th element's type is a pointer at **offset 3+2*n**. The offset in bytes from the beginning of the tuple to the beginning of the *n*\ th element is at **offset 3+2*n+1**. @@ -743,15 +743,17 @@ Globals global ::= 'PA' .* // partial application forwarder global ::= 'PAo' .* // ObjC partial application forwarder global ::= 'w' value-witness-kind type // value witness - global ::= 'WV' type // value witness table - global ::= 'Wo' entity // witness table offset - global ::= 'Wv' directness entity // field offset - global ::= 'WP' protocol-conformance // protocol witness table global ::= 'Wa' protocol-conformance // protocol witness table accessor + global ::= 'WG' protocol-conformance // generic protocol witness table + global ::= 'WI' protocol-conformance // generic protocol witness table instantiation function global ::= 'Wl' type protocol-conformance // lazy protocol witness table accessor global ::= 'WL' protocol-conformance // lazy protocol witness table cache variable - global ::= 'WD' protocol-conformance // dependent proto witness table generator - global ::= 'Wd' protocol-conformance // dependent proto witness table template + global ::= 'Wo' entity // witness table offset + global ::= 'WP' protocol-conformance // protocol witness table + global ::= 'Wt' protocol-conformance identifier // associated type metadata accessor + global ::= 'WT' protocol-conformance identifier nominal-type // associated type witness table accessor + global ::= 'Wv' directness entity // field offset + global ::= 'WV' type // value witness table global ::= entity // some identifiable thing global ::= 'TO' global // ObjC-as-swift thunk global ::= 'To' global // swift-as-ObjC thunk @@ -939,6 +941,7 @@ Types nominal-type-kind ::= 'C' // class nominal-type-kind ::= 'O' // enum nominal-type-kind ::= 'V' // struct + declaration-name ::= context decl-name archetype ::= 'Q' index // archetype with depth=0, idx=N archetype ::= 'Qd' index index // archetype with depth=M+1, idx=N archetype ::= associated-type @@ -1175,12 +1178,12 @@ for the first time. The first argument type will mangle in long form, ``CC3zim4zang4zung``, and in doing so, ``zim`` will acquire substitution ``S_``, ``zim.zang`` will acquire substitution ``S0_``, and ``zim.zang.zung`` will acquire ``S1_``. The second argument is the same as the first and will mangle -using its substitution, ``CS1_``. The +using its substitution, ``S1_``. The third argument type will mangle using the substitution for ``zim``, ``CS_7zippity``. (It also acquires substitution ``S2_`` which would be used if it mangled again.) The result type will mangle using the substitution for -``zim.zang``, ``CS0_zoo`` (and acquire substitution ``S3_``). The full -function type thus mangles as ``fTCC3zim4zang4zungCS1_CS_7zippity_CS0_zoo``. +``zim.zang``, ``CS0_3zoo`` (and acquire substitution ``S3_``). The full +function type thus mangles as ``fTCC3zim4zang4zungS1_CS_7zippity_CS0_3zoo``. :: diff --git a/docs/ARCOptimization.rst b/docs/ARCOptimization.rst index 725d650610c73..edd04f8697551 100644 --- a/docs/ARCOptimization.rst +++ b/docs/ARCOptimization.rst @@ -137,7 +137,7 @@ lower directly to is_unique instructions in SIL. The is_unique instruction takes the address of a reference, and although it does not actually change the reference, the reference must appear mutable to the optimizer. This forces the optimizer to preserve -a retain distinct from what’s required to maintain lifetime for any of +a retain distinct from what's required to maintain lifetime for any of the reference's source-level copies, because the called function is allowed to replace the reference, thereby releasing the referent. Consider the following sequence of rules: @@ -225,6 +225,493 @@ these cases: - isUniqueOrPinned_native : (inout T[?]) -> Int1 These builtins perform an implicit cast to NativeObject before -checking uniqueness. There’s no way at SIL level to cast the address +checking uniqueness. There's no way at SIL level to cast the address of a reference, so we need to encapsulate this operation as part of the builtin. + +Semantic Tags +============= + +ARC takes advantage of certain semantic tags. This section documents these +semantics and their meanings. + +arc.programtermination_point +---------------------------- + +If this semantic tag is applied to a function, then we know that: + +- The function does not touch any reference counted objects. +- After the function is executed, all reference counted objects are leaked + (most likely in preparation for program termination). + +This allows one, when performing ARC code motion, to ignore blocks that contain +an apply to this function as long as the block does not have any other side +effect having instructions. + +ARC Sequence Optimization +========================= + +TODO: Fill this in. + +ARC Loop Hoisting +================= + +Abstract +-------- + +This section describes the ARCLoopHoisting algorithm that hoists retains and +releases out of loops. This is a high level description that justifies the +correction of the algorithm and describes its design. In the following +discussion we talk about the algorithm conceptually and show its safety and +considerations necessary for good performance. + +*NOTE* In the following when we refer to "hoisting", we are not just talking +about upward code motion of retains, but also downward code motion of releases. + +Loop Canonicalization +--------------------- + +In the following we assume that all loops are canonicalized such that: + +1. The loop has a pre-header. +2. The loop has one backedge. +3. All exiting edges have a unique exit block. + +Motiviation +----------- + +Consider the following simple loop:: + + bb0: + br bb1 + + bb1: + retain %x (1) + apply %f(%x) + apply %f(%x) + release %x (2) + cond_br ..., bb1, bb2 + + bb2: + return ... + +When it is safe to hoist (1),(2) out of the loop? Imagine if we know the trip +count of the loop is 3 and completely unroll the loop so the whole function is +one basic block. In such a case, we know the function looks as follows:: + + bb0: + # Loop Iteration 0 + retain %x + apply %f(%x) + apply %f(%x) + release %x (4) + + # Loop Iteration 1 + retain %x (5) + apply %f(%x) + apply %f(%x) + release %x (6) + + # Loop Iteration 2 + retain %x (7) + apply %f(%x) + apply %f(%x) + release %x + + return ... + +Notice how (3) can be paired with (4) and (5) can be paired with (6). Assume +that we eliminate those. Then the function looks as follows:: + + bb0: + # Loop Iteration 0 + retain %x + apply %f(%x) + apply %f(%x) + + # Loop Iteration 1 + apply %f(%x) + apply %f(%x) + + # Loop Iteration 2 + apply %f(%x) + apply %f(%x) + release %x + + return ... + +We can then re-roll the loop, yielding the following loop:: + + bb0: + retain %x (8) + br bb1 + + bb1: + apply %f(%x) + apply %f(%x) + cond_br ..., bb1, bb2 + + bb2: + release %x (9) + return ... + +Notice that this transformation is equivalent to just hoisting (1) and (2) out +of the loop in the original example. This form of hoisting is what is termed +"ARCLoopHoisting". What is key to notice is that even though we are performing +"hoisting" we are actually pairing releases from one iteration with retains in +the next iteration and then eliminating the pairs. This realization will guide +our further analysis. + +Correctness +----------- + +In this simple loop case, the proof of correctness is very simple to see +conceptually. But in a more general case, when is safe to perform this +optimization? We must consider three areas of concern: + +1. Are the retains/releases upon the same reference count? This can be found + conservatively by using RCIdentityAnalysis. + +2. Can we move retains, releases in the unrolled case as we have specified? + This is simple since it is always safe to move a retain earlier and a release + later in the dynamic execution of a program. This can only extend the life of + a variable which is a legal and generally profitable in terms of allowing for + this optimization. + +3. How do we pair all necessary retains/releases to ensure we do not unbalance + retain/release counts in the loop? Consider a set of retains and a set of + releases that we wish to hoist out of a loop. We can only hoist the retain, + release sets out of the loop if all paths in the given loop region from the + entrance to the backedge. have exactly one retain or release from this set. + +4. Any early exits that we must move a retain past or a release by must be + compensated appropriately. This will be discussed in the next section. + +Assuming that our optimization does all of these things, we should be able to +hoist with safety. + +Compensating Early Exits for Lost Dynamic Reference Counts +---------------------------------------------------------- + +Lets say that we have the following loop canonicalized SIL:: + + bb0(%0 : $Builtin.NativeObject): + br bb1 + + bb1: + strong_retain %0 : $Builtin.NativeObject + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject + cond_br ..., bb2, bb3 + + bb2: + cond_br ..., bb1, bb4 + + bb3: + br bb5 + + bb4: + br bb5 + + bb6: + return ... + +Can we hoist the retain/release pair here? Lets assume the loop is 3 iterations +and we completely unroll it. Then we have:: + + bb0: + strong_retain %0 : $Builtin.NativeObject (1) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (2) + cond_br ..., bb1, bb4 + + bb1: // preds: bb0 + strong_retain %0 : $Builtin.NativeObject (3) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (4) + cond_br ..., bb2, bb4 + + bb2: // preds: bb1 + strong_retain %0 : $Builtin.NativeObject (5) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (6) + cond_br ..., bb3, bb4 + + bb3: // preds: bb2 + br bb5 + + bb4: // preds: bb0, bb1, bb2 + br bb5 + + bb5: // preds: bb3, bb4 + return ... + +We want to be able to pair and eliminate (2)/(3) and (4)/(5). In order to do +that, we need to move (2) from bb0 into bb1 and (4) from bb1 into bb2. In order +to do this, we need to move a release along all paths into bb4 lest we lose +dynamic releases along that path. We also sink (6) in order to not have an extra +release along that path. This then give us:: + + bb0: + strong_retain %0 : $Builtin.NativeObject (1) + + bb1: + apply %f(%0) + apply %f(%0) + cond_br ..., bb2, bb3 + + bb2: + cond_br ..., bb1, bb4 + + bb3: + strong_release %0 : $Builtin.NativeObject (6*) + br bb5 + + bb4: + strong_release %0 : $Builtin.NativeObject (7*) + br bb5 + + bb5: // preds: bb3, bb4 + return ... + +An easy inductive proof follows. + +What if we have the opposite problem, that of moving a retain past an early +exit. Consider the following:: + + bb0(%0 : $Builtin.NativeObject): + br bb1 + + bb1: + cond_br ..., bb2, bb3 + + bb2: + strong_retain %0 : $Builtin.NativeObject + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject + cond_br ..., bb1, bb4 + + bb3: + br bb5 + + bb4: + br bb5 + + bb6: + return ... + +Lets unroll this loop:: + + bb0(%0 : $Builtin.NativeObject): + br bb1 + + # Iteration 1 + bb1: // preds: bb0 + cond_br ..., bb2, bb8 + + bb2: // preds: bb1 + strong_retain %0 : $Builtin.NativeObject (1) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (2) + br bb3 + + # Iteration 2 + bb3: // preds: bb2 + cond_br ..., bb4, bb8 + + bb4: // preds: bb3 + strong_retain %0 : $Builtin.NativeObject (3) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (4) + br bb5 + + # Iteration 3 + bb5: // preds: bb4 + cond_br ..., bb6, bb8 + + bb6: // preds: bb5 + strong_retain %0 : $Builtin.NativeObject (5) + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (6) + cond_br ..., bb7, bb8 + + bb7: // preds: bb6 + br bb9 + + bb8: // Preds: bb1, bb3, bb5, bb6 + br bb9 + + bb9: + return ... + +First we want to move the retain into the previous iteration. This means that we +have to move a retain over the cond_br in bb1, bb3, bb5. If we were to do that +then bb8 would have an extra dynamic retain along that path. In order to fix +that issue, we need to balance that release by putting a release in bb8. But we +cannot move a release into bb8 without considering the terminator of bb6 since +bb6 is also a predecessor of bb8. Luckily, we have (6). Notice that bb7 has one +predecessor to bb6 so we can safely move 1 release along that path as well. Thus +we perform that code motion, yielding the following:: + + bb0(%0 : $Builtin.NativeObject): + br bb1 + + # Iteration 1 + bb1: // preds: bb0 + strong_retain %0 : $Builtin.NativeObject (1) + cond_br ..., bb2, bb8 + + bb2: // preds: bb1 + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (2) + br bb3 + + # Iteration 2 + bb3: // preds: bb2 + strong_retain %0 : $Builtin.NativeObject (3) + cond_br ..., bb4, bb8 + + bb4: // preds: bb3 + apply %f(%0) + apply %f(%0) + strong_release %0 : $Builtin.NativeObject (4) + br bb5 + + # Iteration 3 + bb5: // preds: bb4 + strong_retain %0 : $Builtin.NativeObject (5) + cond_br ..., bb6, bb8 + + bb6: // preds: bb5 + apply %f(%0) + apply %f(%0) + cond_br ..., bb7, bb8 + + bb7: // preds: bb6 + strong_release %0 : $Builtin.NativeObject (7*) + br bb9 + + bb8: // Preds: bb1, bb3, bb5, bb6 + strong_release %0 : $Builtin.NativeObject (8*) + br bb9 + + bb9: + return ... + +Then we move (1), (3), (4) into the single predecessor of their parent block and +eliminate (3), (5) through a pairing with (2), (4) respectively. This yields +then:: + + bb0(%0 : $Builtin.NativeObject): + strong_retain %0 : $Builtin.NativeObject (1) + br bb1 + + # Iteration 1 + bb1: // preds: bb0 + cond_br ..., bb2, bb8 + + bb2: // preds: bb1 + apply %f(%0) + apply %f(%0) + br bb3 + + # Iteration 2 + bb3: // preds: bb2 + cond_br ..., bb4, bb8 + + bb4: // preds: bb3 + apply %f(%0) + apply %f(%0) + br bb5 + + # Iteration 3 + bb5: // preds: bb4 + cond_br ..., bb6, bb8 + + bb6: // preds: bb5 + apply %f(%0) + apply %f(%0) + cond_br ..., bb7, bb8 + + bb7: // preds: bb6 + strong_release %0 : $Builtin.NativeObject (7*) + br bb9 + + bb8: // Preds: bb1, bb3, bb5, bb6 + strong_release %0 : $Builtin.NativeObject (8*) + br bb9 + + bb9: + return ... + +Then we finish by rerolling the loop:: + + bb0(%0 : $Builtin.NativeObject): + strong_retain %0 : $Builtin.NativeObject (1) + br bb1 + + # Iteration 1 + bb1: // preds: bb0 + cond_br ..., bb2, bb8 + + bb2: + apply %f(%0) + apply %f(%0) + cond_br bb1, bb7 + + bb7: + strong_release %0 : $Builtin.NativeObject (7*) + br bb9 + + bb8: // Preds: bb1, bb3, bb5, bb6 + strong_release %0 : $Builtin.NativeObject (8*) + br bb9 + + bb9: + return ... + + +Uniqueness Check Complications +------------------------------ + +A final concern that we must consider is if we introduce extra copy on write +copies through our optimization. To see this, consider the following simple +IR sequence:: + + bb0(%0 : $Builtin.NativeObject): + // refcount(%0) == n + is_unique %0 : $Builtin.NativeObject + // refcount(%0) == n + strong_retain %0 : $Builtin.NativeObject + // refcount(%0) == n+1 + +If n is not 1, then trivially is_unique will return false. So assume that n is 1 +for our purposes so no copy is occurring here. Thus we have:: + + bb0(%0 : $Builtin.NativeObject): + // refcount(%0) == 1 + is_unique %0 : $Builtin.NativeObject + // refcount(%0) == 1 + strong_retain %0 : $Builtin.NativeObject + // refcount(%0) == 2 + +Now imagine that we move the strong_retain before the is_unique. Then we have:: + + bb0(%0 : $Builtin.NativeObject): + // refcount(%0) == 1 + strong_retain %0 : $Builtin.NativeObject + // refcount(%0) == 2 + is_unique %0 : $Builtin.NativeObject + +Thus is_unique is guaranteed to return false introducing a copy that was not +needed. We wish to avoid that if it is at all possible. + diff --git a/docs/AccessControlInStdlib.rst b/docs/AccessControlInStdlib.rst index 5b20b7699e0ef..9bf32bc54a97e 100644 --- a/docs/AccessControlInStdlib.rst +++ b/docs/AccessControlInStdlib.rst @@ -6,7 +6,7 @@ Scope and introduction This document defines the policy for applying access control modifiers and related naming conventions for the Swift standard library and overlays. -In this document, “stdlib” refers to the core standard library and +In this document, "stdlib" refers to the core standard library and overlays for system frameworks written in Swift. Swift has three levels of access control --- private, internal @@ -60,7 +60,7 @@ explicitly everywhere in the stdlib to avoid confusion. .. Note:: No declaration should omit an access -To create a “single point of truth” about whether a name is intended +To create a "single point of truth" about whether a name is intended for user consumption, the following names should all use the `leading underscore rule`_: @@ -77,7 +77,7 @@ underscore rule`_: `private` ========= -The `private` modifier can not be used in the stdlib at least until +The `private` modifier cannot be used in the stdlib at least until rdar://17631278 is fixed. Leading Underscore Rule diff --git a/docs/Arrays.rst b/docs/Arrays.rst index 766d30522b8bd..2204209a354af 100644 --- a/docs/Arrays.rst +++ b/docs/Arrays.rst @@ -53,34 +53,34 @@ Swift provides three generic array types, all of which have amortized O(1) growth. In this document, statements about **ArrayType** apply to all three of the components. -* ``ContiguousArray`` is the fastest and simplest of the three—use this - when you need "C array" performance. The elements of a +* ``ContiguousArray`` is the fastest and simplest of the three—use + this when you need "C array" performance. The elements of a ``ContiguousArray`` are always stored contiguously in memory. .. image:: ContiguousArray.png -* ``Array`` is like ``ContiguousArray``, but optimized for efficient - conversions from Cocoa and back—when ``T`` can be a class type, - ``Array`` can be backed by the (potentially non-contiguous) +* ``Array`` is like ``ContiguousArray``, but optimized for + efficient conversions from Cocoa and back—when ``Element`` can be a class + type, ``Array`` can be backed by the (potentially non-contiguous) storage of an arbitrary ``NSArray`` rather than by a Swift - ``ContiguousArray``. ``Array`` also supports up- and down- casts - between arrays of related class types. When ``T`` is known to be a - non-class type, the performance of ``Array`` is identical to that - of ``ContiguousArray``. + ``ContiguousArray``. ``Array`` also supports up- and downcasts + between arrays of related class types. When ``Element`` is known to be a + non-class type, the performance of ``Array`` is identical to that + of ``ContiguousArray``. .. image:: ArrayImplementation.png -* ``Slice`` is a subrange of some ``Array`` or - ``ContiguousArray``; it's the result of using slice notation, +* ``ArraySlice`` is a subrange of some ``Array`` or + ``ContiguousArray``; it's the result of using slice notation, e.g. ``a[7...21]`` on any Swift array ``a``. A slice always has contiguous storage and "C array" performance. Slicing an - *ArrayType* is O(1) unless the source is an ``Array`` backed by + *ArrayType* is O(1) unless the source is an ``Array`` backed by an ``NSArray`` that doesn't supply contiguous storage. - ``Slice`` is recommended for transient computations but not for + ``ArraySlice`` is recommended for transient computations but not for long-term storage. Since it references a sub-range of some shared - backing buffer, a ``Slice`` may artificially prolong the lifetime of - elements outside the ``Slice`` itself. + backing buffer, a ``ArraySlice`` may artificially prolong the lifetime of + elements outside the ``ArraySlice`` itself. .. image:: Slice.png @@ -169,43 +169,43 @@ conforms to ``_BridgedToObjectiveC``: .. _trivial bridging: -* **Trivial bridging** implicitly converts ``Base[]`` to +* **Trivial bridging** implicitly converts ``[Base]`` to ``NSArray`` in O(1). This is simply a matter of returning the Array's internal buffer, which is-a ``NSArray``. .. _trivial bridging back: * **Trivial bridging back** implicitly converts ``NSArray`` to - ``AnyObject[]`` in O(1) plus the cost of calling ``copy()`` on + ``[AnyObject]`` in O(1) plus the cost of calling ``copy()`` on the ``NSArray``. [#nocopy]_ * **Implicit conversions** between ``Array`` types - - **Implicit upcasting** implicitly converts ``Derived[]`` to - ``Base[]`` in O(1). - - **Implicit bridging** implicitly converts ``X[]`` to - ``X._ObjectiveCType[]`` in O(N). + - **Implicit upcasting** implicitly converts ``[Derived]`` to + ``[Base]`` in O(1). + - **Implicit bridging** implicitly converts ``[X]`` to + ``[X._ObjectiveCType]`` in O(N). .. Note:: Either type of implicit conversion may be combined with `trivial bridging`_ in an implicit conversion to ``NSArray``. -* **Checked conversions** convert ``T[]`` to ``U[]?`` in O(N) - via ``a as U[]``. +* **Checked conversions** convert ``[T]`` to ``[U]?`` in O(N) + via ``a as [U]``. - - **Checked downcasting** converts ``Base[]`` to ``Derived[]?``. - - **Checked bridging back** converts ``T[]`` to ``X[]?`` where + - **Checked downcasting** converts ``[Base]`` to ``[Derived]?``. + - **Checked bridging back** converts ``[T]`` to ``[X]?`` where ``X._ObjectiveCType`` is ``T`` or a trivial subtype thereof. -* **Forced conversions** convert ``AnyObject[]`` or ``NSArray`` to - ``T[]`` implicitly, in bridging thunks between Swift and Objective-C. +* **Forced conversions** convert ``[AnyObject]`` or ``NSArray`` to + ``[T]`` implicitly, in bridging thunks between Swift and Objective-C. - For example, when a user writes a Swift method taking ``NSView[]``, + For example, when a user writes a Swift method taking ``[NSView]``, it is exposed to Objective-C as a method taking ``NSArray``, which - is force-converted to ``NSView[]`` when called from Objective-C. + is force-converted to ``[NSView]`` when called from Objective-C. - - **Forced downcasting** converts ``AnyObject[]`` to ``Derived[]`` in + - **Forced downcasting** converts ``[AnyObject]`` to ``[Derived]`` in O(1) - - **Forced bridging back** converts ``AnyObject[]`` to ``X[]`` in O(N). + - **Forced bridging back** converts ``[AnyObject]`` to ``[X]`` in O(N). A forced conversion where any element fails to convert is considered a user programming error that may trap. In the case of forced @@ -225,7 +225,7 @@ Upcasts TODO: this section is outdated. -When up-casting an ``Derived[]`` to ``Base[]``, a buffer of +When up-casting an ``[Derived]`` to ``[Base]``, a buffer of ``Derived`` object can simply be ``unsafeBitCast``\ 'ed to a buffer of elements of type ``Base``—as long as the resulting buffer is never mutated. For example, we cannot allow a ``Base`` element to be @@ -234,11 +234,11 @@ the elements with the (incorrect) static presumption that they have ``Derived`` type. Furthermore, we can't (logically) copy the buffer just prior to -mutation, since the ``Base[]`` may be copied prior to mutation, +mutation, since the ``[Base]`` may be copied prior to mutation, and our shared subscript assignment semantics imply that all copies must observe its subscript assignments. -Therefore, converting ``T[]`` to ``U[]`` is akin to +Therefore, converting ``[T]`` to ``[U]`` is akin to resizing: the new ``Array`` becomes logically independent. To avoid an immediate O(N) conversion cost, and preserve shared subscript assignment semantics, we use a layer of indirection in the data diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index d94e7b94cc560..d91a99b772ea6 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -82,7 +82,7 @@ if(LITRE_EXECUTABLE) VERBATIM ) - # Only update the real top-level CMakeLists.txt if something changed + # Only update the real top-level CMakeLists.txt if something changed add_custom_command( OUTPUT "litre-tests/CMakeLists.txt" diff --git a/docs/DebuggingTheCompiler.rst b/docs/DebuggingTheCompiler.rst index 3241542440e36..52cc8d405d053 100644 --- a/docs/DebuggingTheCompiler.rst +++ b/docs/DebuggingTheCompiler.rst @@ -136,7 +136,7 @@ and check for the function name in the breakpoint condition:: (lldb) br set -c 'hasName("_TFC3nix1Xd")' -f SILFunction.cpp -l 91 -Sometimes you want to know which optimization does insert, remove or move a +Sometimes you may want to know which optimization inserts, removes or moves a certain instruction. To find out, set a breakpoint in ``ilist_traits::addNodeToList`` or ``ilist_traits::removeNodeFromList``, which are defined in diff --git a/docs/ErrorHandling.rst b/docs/ErrorHandling.rst index 547af4def253a..a7b14bd387477 100644 --- a/docs/ErrorHandling.rst +++ b/docs/ErrorHandling.rst @@ -578,7 +578,7 @@ of failability. One limitation of this approach is that we need to be able to reconstruct the selector to use when an overload of a method is introduced. For this -reason, the import is likely to be limited to methods where the error +reason, the import is likely to be limited to methods where the error parameter is the last one and the corresponding selector chunk is either ``error:`` or the first chunk (see below). Empirically, this seems to do the right thing for all but two sets of APIs in the diff --git a/docs/ErrorHandlingRationale.rst b/docs/ErrorHandlingRationale.rst index 9ea61ca5277b0..bb25f838843e4 100644 --- a/docs/ErrorHandlingRationale.rst +++ b/docs/ErrorHandlingRationale.rst @@ -1,6 +1,8 @@ Error Handling Rationale and Proposal ************************************* +.. contents:: + This paper surveys the error-handling world, analyzes various ideas which have been proposed or are in practice in other languages, and ultimately proposes an error-handling scheme for Swift together @@ -389,7 +391,7 @@ options as a programmer: function called by your function. - You can carefully arrange your function so that there are no - critical sections where an universal error can leave things in an + critical sections where a universal error can leave things in an unwanted state. There are techniques for making the second more palatable. Chiefly, @@ -636,7 +638,7 @@ of the disadvantages and investigate ways to ameliorate them: - There are many situations where errors are not actually possible because the programmer has carefully restricted the input. For - example, matching :code:``/[0-9]{4}/`` and then parsing the result + example, matching ``/[0-9]{4}/`` and then parsing the result as an integer. It needs to be convenient to do this in a context that cannot actually propagate errors, but the facility to do this needs to be carefully designed to discourage use for swallowing @@ -741,8 +743,8 @@ This approach is therefore relatively even-handed about the error vs. the non-error path, although it requires some care in order to minimize code-size penalties for parallel error paths. -``setjmp`` / ``longmp`` -~~~~~~~~~~~~~~~~~~~~~~~ +``setjmp`` / ``longjmp`` +~~~~~~~~~~~~~~~~~~~~~~~~ Another strategy to is to dynamically maintain a thread-local stack of interesting frames. A function with an interesting frame must save @@ -1043,9 +1045,9 @@ C++ has exceptions. Exceptions can have almost any type in the language. Propagation typing is tied only to declarations; an indirect function pointer is generally assumed to be able to throw. Propagation typing used to allow functions to be specific about the -kinds of exceptions they could throw (:code:``throws +kinds of exceptions they could throw (``throws (std::exception)``), but this is deprecated in favor of just indicating -whether a function can throw (:code:``noexcept(false)``). +whether a function can throw (``noexcept(false)``). C++ aspires to making out-of-memory a recoverable condition, and so allocation can throw. Therefore, it is essentially compulsory for the @@ -1316,16 +1318,16 @@ generalized ``do`` statement:: } Swift should also provide some tools for doing manual propagation. We -should have a standard Rust-like :code:``Result`` enum in the +should have a standard Rust-like ``Result`` enum in the library, as well as a rich set of tools, e.g.: - A function to evaluate an error-producing closure and capture the - result as a :code:``Result``. + result as a ``Result``. -- A function to unpack a :code:``Result`` by either returning its +- A function to unpack a ``Result`` by either returning its value or propagating the error in the current context. -- A futures library that traffics in :code:``Result`` when +- A futures library that traffics in ``Result`` when applicable. - An overload of ``dispatch_sync`` which takes an error-producing @@ -1359,7 +1361,7 @@ declaration or type:: return try stream.readInt() } - // ‘throws’ is written before the arrow to give a sensible and + // 'throws' is written before the arrow to give a sensible and // consistent grammar for function types and implicit () result types. func baz() throws { if let byte = try stream.getOOB() where byte == PROTO_RESET { @@ -1367,7 +1369,7 @@ declaration or type:: } } - // ‘throws’ appears in a consistent position in function types. + // 'throws' appears in a consistent position in function types. func fred(callback: (UInt8) throws -> ()) throws { while true { let code = try stream.readByte() @@ -1380,7 +1382,7 @@ declaration or type:: // this function has type: // (Int) -> (Int) throws -> Int func jerry(i: Int)(j: Int) throws -> Int { - // It’s not an error to use ‘throws’ on a function that can’t throw. + // It's not an error to use 'throws' on a function that can't throw. return i + j } diff --git a/docs/Generics.rst b/docs/Generics.rst index 7ba13d3f560d0..bd6808c8fb38f 100644 --- a/docs/Generics.rst +++ b/docs/Generics.rst @@ -51,7 +51,7 @@ The alternatives to generics tend to lead to poor solutions: * Object-oriented languages tend to use "top" types (id in Objective-C, java.lang.Object in pre-generics Java, etc.) for their containers and - algorithms, which gives up static type safety. Pre- generics Java forced the + algorithms, which gives up static type safety. Pre-generics Java forced the user to introduce run-time-checked type casts when interacting with containers (which is overly verbose), while Objective-C relies on id's unsound implicit conversion behavior to eliminate the need for casts. @@ -242,7 +242,7 @@ us to cleanly describe a protocol for collections:: protocol Collection { typealias Element - func forEach(callback : (value : Element) -> void) + func forEach(callback : (value : Element) -> Void) func add(value : Element) } @@ -313,7 +313,7 @@ also know how to "draw!":: It is unlikely that Cowboy is meant to conform to Shape, but the method name and signatures match, so implicit conformance deduces that Cowboy conforms to Shape. Random collisions between types are fairly rare. However, when one is -using protocol inheritance with fine- grained (semantic or mostly-semantic) +using protocol inheritance with fine-grained (semantic or mostly-semantic) differences between protocols in the hierarchy, they become more common. See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1798.html for examples of this problem as it surfaced with C++ concepts. It is not clear at this time @@ -330,7 +330,7 @@ type:: struct EmployeeList : Collection { // EmployeeList is a collection typealias Element = T - func forEach(callback : (value : Element) -> void) { /* Implement this */ } + func forEach(callback : (value : Element) -> Void) { /* Implement this */ } func add(value : Element) { /* Implement this */ } } @@ -367,7 +367,7 @@ extensions, e.g.,:: extension String : Collection { typealias Element = char - func forEach(callback : (value : Element) -> void) { /* use existing String routines to enumerate characters */ } + func forEach(callback : (value : Element) -> Void) { /* use existing String routines to enumerate characters */ } func add(value : Element) { self += value /* append character */ } } @@ -579,7 +579,7 @@ OrderedCollection>) are just sugar for a where clause. For example, the above find() signature is equivalent to:: func find( - collection : C, value : C.Element)-> Int + collection : C, value : C.Element) -> Int Note that find is shorthand for (and equivalent to) find, since every type conforms to the Any protocol composition. @@ -594,7 +594,7 @@ lets us describe an iteration of values of some given value type:: func next() -> Element } -Now, we want to express the notion of an enumerable collection, which provides a +Now, we want to express the notion of an enumerable collection, which provides iteration, which we do by adding requirements into the protocol:: protocol EnumerableCollection : Collection { @@ -835,7 +835,7 @@ cannot disambiguate the tokens:: i.e.,:: - identifier operator identifier operator unspaced_lparen integer- literal comma integer-literal rparen + identifier operator identifier operator unspaced_lparen integer-literal comma integer-literal rparen which can be interpreted as either:: diff --git a/docs/GitWorkflows.rst b/docs/GitWorkflows.rst index 24e5ce8e23760..9f6dc650d4d72 100644 --- a/docs/GitWorkflows.rst +++ b/docs/GitWorkflows.rst @@ -11,7 +11,7 @@ transition to Git this document helps to address questions about how common SVN workflows we use today translate to their Git counterparts as well as to discuss Git workflow practices we plan on having — at least initially — after the Git transition. Notably we will follow a model where commits to trunk — which is -the ‘master’ branch in Git — has commits land (in the common case) via rebasing +the 'master' branch in Git — has commits land (in the common case) via rebasing instead of merging. This model is open to evolution later, but this mimics the workflow we have today with SVN. @@ -114,7 +114,7 @@ By default when updating, Git will attempt to merge the remote changes and your local changes. Ignoring what that sentence means, this is not an SVN-esque model. Instead we want any local changes that we have to be applied on top of any new remote changes. The 'branch.autosetuprebase' flag causes this to be done -automatically when ever one updates the local repository. +automatically whenever one updates the local repository. Update ------ @@ -261,7 +261,7 @@ command:: $ git log -To see a oneline summary that includes just the title of the commit and its +To see an oneline summary that includes just the title of the commit and its hash, pass the '--oneline' command:: $ git log --oneline diff --git a/docs/HighLevelSILOptimizations.rst b/docs/HighLevelSILOptimizations.rst index b35c26063c94f..1ff20558230eb 100644 --- a/docs/HighLevelSILOptimizations.rst +++ b/docs/HighLevelSILOptimizations.rst @@ -132,7 +132,8 @@ Array The following semantic tags describe Array operations. The operations are first described in terms of the Array "state". Relations between the operations are formally defined below. 'Array' refers to the standard library -Array, ContigousArray, and ArraySlice data-structures. +Array, ContiguousArray, and ArraySlice +data-structures. We consider the array state to consist of a set of disjoint elements and a storage descriptor that encapsulates nonelement data such as the @@ -156,7 +157,7 @@ array.init may act as a guard to other potentially mutating operations, such as ``get_element_address``. -array.uninitialized(count: Builtin.Word) -> (Array, Builtin.RawPointer) +array.uninitialized(count: Builtin.Word) -> (Array, Builtin.RawPointer) Creates an array with the specified number of elements. It initializes the storage descriptor but not the array elements. The returned tuple @@ -166,9 +167,9 @@ array.uninitialized(count: Builtin.Word) -> (Array, Builtin.RawPointer) array.props.isCocoa/needsElementTypeCheck -> Bool Reads storage descriptors properties (isCocoa, needsElementTypeCheck). This is not control dependent or guarded. The optimizer has - semantic knowledge of the state transfer those properties can not make: - An array that is not ``isCocoa`` can not transfer to ``isCocoa``. - An array that is not ``needsElementTypeCheck`` can not transfer to + semantic knowledge of the state transfer those properties cannot make: + An array that is not ``isCocoa`` cannot transfer to ``isCocoa``. + An array that is not ``needsElementTypeCheck`` cannot transfer to ``needsElementTypeCheck``. array.get_element(index: Int) -> Element @@ -262,7 +263,7 @@ check_subscript guards get_element, get_element_address make_mutable interferes-with props.isCocoa/needsElementTypeCheck get_elt_addr interferes-with get_element, get_element_address, props.isCocoa/needsElementTypeCheck -mutate_unknown itereferes-with get_element, check_subscript, get_count, +mutate_unknown interferes-with get_element, check_subscript, get_count, get_capacity, get_element_address, props.isCocoa/needsElementTypeCheck ================ =============== ========================================== diff --git a/docs/IndexInvalidation.rst b/docs/IndexInvalidation.rst index 26f809a0ef5e5..aaa2de169a49b 100644 --- a/docs/IndexInvalidation.rst +++ b/docs/IndexInvalidation.rst @@ -128,7 +128,7 @@ Consequences: any indices. Indices are composites of offsets, so replacing the value does not change the shape of the data structure and preserves offsets. -- A value type mutable linked list can not conform to +- A value type mutable linked list cannot conform to ``MutableCollectionType``. An index for a linked list has to be implemented as a pointer to the list node to provide O(1) element access. Mutating an element of a non-uniquely referenced linked list will create a copy of the diff --git a/docs/Lexicon.rst b/docs/Lexicon.rst new file mode 100644 index 0000000000000..9461930ce1430 --- /dev/null +++ b/docs/Lexicon.rst @@ -0,0 +1,205 @@ +:orphan: + +.. title:: Lexicon +.. default-role:: term + +.. @raise litre.TestsAreMissing + +This file defines several terms used by the Swift compiler and standard library +source code, tests, and commit messages. See also the `LLVM lexicon`_. + +.. _LLVM lexicon: http://llvm.org/docs/Lexicon.html + +.. note:: + + This document uses Sphinx-specific features. If you are viewing this on + GitHub, you'll have to use raw mode, or download and build the docs + yourself. + +.. glossary:: + + archetype + A placeholder for a generic parameter or an associated type within a + generic context. + + canonical SIL + SIL after the + `mandatory passes ` have run. + This can be used as input to IRGen to generate LLVM IR or object files. + + Clang importer + The part of the compiler that reads C and Objective-C declarations and + exposes them as Swift. Essentially contains a small instance of Clang + running inside the Swift compiler, which is also used during IRGen. + + conformance + A construct detailing how a particular type conforms to a particular + protocol. Represented in the compiler by the ProtocolConformance type at + the AST level. See also `witness table`. + + DI (definite initialization / definitive initialization) + The feature that no uninitialized variables, constants, or properties will + be read by a program, or the analysis pass that operates on SIL to + guarantee this. This was `discussed on Apple's Swift blog`__. + + __ https://developer.apple.com/swift/blog/?id=28 + + existential + A value whose type is a protocol composition (including a single protocol + and *zero* protocols; the latter is the ``Any`` type). + + fragile + Describes a type or function where making changes will break binary + compatibility. See :doc:`LibraryEvolution.rst `. + + IUO (implicitly unwrapped optional) + A type like Optional, but it implicitly converts to its wrapped type. If + the value is ``nil`` during such a conversion, the program traps just as + it would when a normal Optional is force-unwrapped. IUOs implicitly + convert to and from normal Optionals with the same wrapped type. + + main module + The module for the file or files currently being compiled. + + mandatory passes / mandatory optimizations + Transformations over SIL that run immediately after SIL generation. Once + all mandatory passes have run (and if no errors are found), the SIL is + considered `canonical `. + + metatype + The type of a value representing a type. Greg Parker has a good + explanation of `Objective-C's "metaclasses"`__; because Swift has types + that are *not* classes, a more general term is used. + + We also sometimes refer to a value representing a type as a "metatype + object" or just "metatype", usually within low-level contexts like IRGen + and LLDB. This is technically incorrect (it's just a "type object"), but + the malapropism happened early in the project and has stuck around. + + __ http://sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html + + model + A type that conforms to a particular protocol. Sometimes "concrete + model". Example: "Array and Set are both models of CollectionType". + + module + Has *many* uses in the Swift world. We may want to rename some of them. + #1 and #2 are the most common. + + 1. A unit of API distribution and grouping. The ``import`` declaration + brings modules into scope. Represented as ModuleDecl in the compiler. + 2. A compilation unit; that is, source files that are compiled together. + These files may contain cross-references. Represented as "the main + module" (a specific ModuleDecl). + 3. (as "SIL module") A container for SIL to be compiled together, along + with various context for the compilation. + 4. (as "LLVM module") A collection of LLVM IR to be compiled together. + Always created in an LLVMContext. + 5. A file containing serialized AST and SIL information for a source file + or entire compilation unit. Often "swiftmodule file", with "swiftmodule" + pronounced as a single word. + 6. (as "Clang module") A set of self-contained C-family header files. + Represented by a ClangModuleUnit in the Swift compiler, each of which is + contained in its own ModuleDecl. For more information, see + `Clang's documentation for Modules`__. + 7. Shorthand for a "precompiled module file"; effectively "precompiled + headers" for an entire Clang module. Never used directly by Swift. + See also `module cache`. + + __ http://clang.llvm.org/docs/Modules.html + + module cache + Clang's cache directory for precompiled module files. As cache files, these + are not forward-compatible, and so cannot be loaded by different versions + of Clang (or programs using Clang, like the Swift compiler). Normally this + is fine, but occasionally a development compiler will not have proper + version information and may try to load older module files, resulting in + crashes in ``clang::ASTReader``. + + open existential + An `existential` value with its dynamic type pulled out, so that the + compiler can do something with it. + + PR + 1. "Problem Report": An issue reported in `LLVM's bug tracker`__. + See also `SR`. + 2. "pull request" + + __ https://llvm.org/bugs/ + + primary file + The file currently being compiled, as opposed to the other files that are + only needed for context. See also + `Whole-Module Optimization `. + + Radar + `Apple's bug-tracking system`__, or an issue reported on that system. + + __ https://bugreport.apple.com + + raw SIL + SIL just after being generated, not yet in a form that can be used for + IR generation. + See `mandatory passes `. + + resilient + Describes a type or function where making certain changes will not break + binary compatibility. See :doc:`LibraryEvolution.rst `. + + script mode + The parsing mode that allows top-level imperative code in a source file. + + SIL + "Swift Intermediate Language". A high-level IR used by the Swift compiler + for flow-sensitive diagnostics, optimization, and LLVM IR generation. + + -sil-serialize-all + A mode where all functions in a library are made available for inlining by + any client, regardless of access control. Also called "magic performance + mode" as a reminder of how this drastically changes compilation. Not + guaranteed to work on arbitrary code. + + SR + An issue reported on `bugs.swift.org `_. A + backronym for "Swift Report"; really the name is derived from LLVM's + idiomatic use of "PR" ("Problem Report") for its bugs. We didn't go with + "PR" for Swift because we wanted to be able to unambiguously reference + LLVM bugs. + + trap + A deterministic runtime failure. Can be used as both as a noun ("Using an + out-of-bounds index on an Array results in a trap") and a verb + ("Force-unwrapping a nil Optional will trap"). + + type metadata + The runtime representation of a type, and everything you can do with it. + Like a ``Class`` in Objective-C, but for any type. + + value witness table + A runtime structure that describes how to do basic operations on an unknown + value, like "assign", "copy", and "destroy". (For example, does copying + this value require any retains?) + + Only conceptually related to a `witness table`. + + vtable (virtual dispatch table) + A map attached to a class of which implementation to use for each + overridable method in the class. Unlike an Objective-C method table, + vtable keys are just offsets, making lookup much simpler at the cost of + dynamism and duplicated information about *non*-overridden methods. + + witness + The value or type that satisfies a protocol requirement. + + witness table + The SIL (and runtime) representation of a `conformance`; essentially a + `vtable ` but for a protocol instead of + a class. + + Only conceptually related to a `value witness table`. + + WMO (whole-module optimization) + A compilation mode where all files in a module are compiled in a single + process. In this mode there is no `primary file`; all files are parsed, + type-checked, and optimized together at the SIL level. LLVM optimization + and object file generation may happen all together or in separate threads. \ No newline at end of file diff --git a/docs/LibraryEvolution.rst b/docs/LibraryEvolution.rst index d20044a9077c4..3ef5616aba833 100644 --- a/docs/LibraryEvolution.rst +++ b/docs/LibraryEvolution.rst @@ -44,12 +44,8 @@ We also intend to provide tools to detect inadvertent changes in interfaces. .. warning:: **This document is still in draft stages.** Large additions and restructuring are still planned, including: - - * A summary for each declaration kind what changes are binary-compatible. - * A proper definition for "versioned entity". - * Several possible versioned attribute syntaxes, instead of just this one. + * A discussion of back-dating, and how it usually is not allowed. - * A brief discussion of the implementation issues for fixed-layout value types with resilient members, and with non-public members. * A revisal of the discussion on fixed-layout classes. * A brief discussion of "deployment files", which represent distribution groupings that are themselves versioned. (For example, OS X 10.10.3 contains Foundation version 1153.20.) Deployment files are likely to provide a concrete implementation of "resilience domains". * A way to specify "minimum deployment libraries", like today's minimum deployment targets. @@ -104,7 +100,7 @@ for fallback behavior when the requested library version is not present:: func scareMySiblings() { if #available(Magician 1.2) { - conjureDemons() + summonDemons() } else { print("BOO!!") } @@ -124,129 +120,151 @@ versions. Publishing Versioned API ======================== -A library's API is already marked with the ``public`` attribute. Versioning -information can be added to any ``public`` entity with the ``@available`` -attribute, this time specifying *only* a version number. This declares when the -entity was first exposed publicly in the current module. +A library's API is already marked with the ``public`` attribute, but if a +client wants to work with multiple releases of the library, the API needs +versioning information as well. A *versioned entity* represents anything with a +runtime presence that a client may rely on; its version records when the entity +was first exposed publicly in its library. Put another way, it is the oldest +version of the library where the entity may be used. + +- Classes, structs, enums, and protocols may all be versioned entities. +- Methods, properties, subscripts, and initializers may be versioned entities. +- Top-level functions, variables, and constants may be versioned entities. +- Protocol conformances may be versioned entities, despite not explicitly having + a declaration in Swift, because a client may depend on them + See `New Conformances`_, below. + +In a versioned library, any top-level public entity from the list above may not +be made ``public`` without an appropriate version. A public entity declared +within a versioned type (or an extension of a versioned type) will default to +having the same version as the type. + +Code within a library may generally use all other entities declared within the +library (barring their own availability checks), since the entire library is +shipped as a unit. That is, even if a particular API was introduced in v1.0, +its (non-public) implementation may refer to APIs introduced in later versions. + +Swift libraries are strongly encouraged to use `semantic versioning`_, but this +is not enforced by the language. + +.. _semantic versioning: http://semver.org + +Certain uses of ``internal`` entities require them to be part of a library's +binary interface, which means they need to be versioned as well. See +`Versioning Internal Declarations`_ below. + +The syntax for marking an entity as versioned has not yet been decided, but the +rest of this document will use syntax #1 described below. + +Syntax #1: Attributes +~~~~~~~~~~~~~~~~~~~~~ :: @available(1.2) - public func conjureDemons() - -.. admonition:: TODO + public func summonDemons() - Should this go on ``public`` instead? How does this play with SPI - ? + @available(1.0) @inlineable(1.2) + public func summonElves() Using the same attribute for both publishing and using versioned APIs helps tie -the feature together and enforces a consistent set of rules. The one difference -is that code within a library may always use all other entities declared within -the library (barring their own availability checks), since the entire library -is shipped as a unit. That is, even if a particular API was introduced in v1.0, -its (non-public) implementation may refer to APIs introduced in later versions. +the feature together and enforces a consistent set of rules. However, there are +several other annotations described later in this document that also need +versioning information, and it may not be obvious what the version number means +outside the context of ``available``. -Swift libraries are strongly encouraged to use `semantic versioning`_, but this -is not enforced by the language. -Some ``internal`` entities may also use ``@available``. See `Pinning`_ below. +Syntax #2: Version Blocks +~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _semantic versioning: http://semver.org +:: + #version(1.2) + public func summonDemons() -Giving Up Flexibility -===================== + #version(1.0) {} + #version(1.2) { @inlineable } + public func summonElves() -Fixed-layout Structs -~~~~~~~~~~~~~~~~~~~~ +Since there are potentially many annotations on a declaration that need +versioning information, it may make sense to group them together in some way. +Only certain annotations would support being versioned in this way. -By default, a library owner may add members to a public struct between releases -without breaking binary compatibility. This requires a certain amount of care -and indirection when dealing with values of struct type to account for the -struct's size and non-`trivial` fields not being known in advance, which of -course has performance implications. -To opt out of this flexibility, a struct may be marked ``@fixed_layout``. This -promises that no stored properties will be added to or removed from the struct, -even ``private`` or ``internal`` ones. Methods and computed properties may -still be added to the struct. +Syntax #3: The ``public`` modifier +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``@fixed_layout`` attribute takes a version number, just like -``@available``. This is so that clients can deploy against older versions of -the library, which may have a different layout for the struct. (In this case -the client must manipulate the struct as if the ``@fixed_layout`` attribute -were absent.) +:: -.. admonition:: TODO + public(1.2) func summonDemons() - There's a benefit to knowing that a struct was ``@fixed_layout`` since it - was first made available. How should that be spelled? + /* @inlineable ?? */ + public(1.0) func summonElves() +Putting the version on the public modifier is the most concise option. However, +there's no obvious syntax here for adding versions to other annotations that +may apply to a declaration. -Fixed-layout Classes? ---------------------- +(Also, at one point there was a proposal to tag API only intended for certain +clients using a similar syntax: ``public("Foundation")``, for example, for APIs +only meant to be used by Foundation. These could then be stripped out of the +public interface for a framework before being widely distributed. But that +could easily use an alternate syntax.) -There is some benefit to knowing that a class has a fixed layout---that is, -that the stored properties of the class and all its superclasses are guaranteed -not to change in future versions of a library. This would, for example, allow -the class's memory to be allocated on the stack, as long as it can be proven -that no references to the class escape. However, such a constraint is unlikely -to be provable in practice from outside the class's own module, where its -primary operations are opaquely defined. Thus, until a tangible benefit has -been demonstrated, the ``@fixed_layout`` attribute will not apply to classes. -(Another benefit would be to simplify the calculations needed for the offsets -of stored properties within classes. However, it's unclear that this would have -any significant benefit, particularly when most public properties are -manipulated through their accessors.) +Supported Evolution +=================== +This section describes the various changes that are safe to make when releasing +a new version of a library, i.e. changes that will not break binary +compatibility. They are organized by declaration type. -Closed Enums -~~~~~~~~~~~~ +Anything *not* listed in this document should be assumed unsafe. -By default, a library owner may add new cases to a public enum between releases -without breaking binary compatibility. As with structs, this results in a fair -amount of indirection when dealing with enum values, in order to potentially -accommodate new values. -.. note:: +Top-Level Functions +~~~~~~~~~~~~~~~~~~~ - If an enum value has a known case, or can be proven to belong to a set of - known cases, the compiler is of course free to use a more efficient - representation for the value, just as it may discard fields of structs that - are provably never accessed. +A versioned top-level function is fairly restricted in how it can be changed. +The following changes are permitted: -A library owner may opt out of this flexibility by marking the enum as -``@closed``. A "closed" enum may not have any ``private`` or ``internal`` cases -and may not add new cases in the future. This guarantees to clients that the -enum cases are exhaustive. +- Changing the body of the function. +- Changing *internal* parameter names (i.e. the names used within the function + body, not the labels that are part of the function's full name). +- Reordering generic requirements (but not the generic parameters themselves). +- Adding a default value to a parameter. +- Changing a default value is permitted but discouraged; it changes the meaning + of existing source code. .. note:: - Were a "closed" enum allowed to have non-public cases, clients of the - library would still have to treat the enum as opaque and would still have - to be able to handle unknown cases in their ``switch`` statements. + Today's implementation of default values puts the evaluation of the default + value expression in the library, rather than in the client like C++ or C#. + This is problematic if we want to allow adding new default values. -The ``@closed`` attribute takes a version number, just like ``@available``. -This is so that clients can deploy against older versions of the library, which -may have non-public cases in the enum. (In this case the client must manipulate -the enum as if the ``@closed`` attribute were absent.) +.. admonition:: TODO -Even for default "open" enums, adding new cases should not be done lightly. Any -clients attempting to do an exhaustive switch over all enum cases will likely -not handle new cases well. + Is *removing* a default value something we want to allow? It breaks source + compatibility, but not binary compatibility under the inlining model. That + said, changing a default value is discouraged, and removing + adding is the + same thing. -.. note:: +No other changes are permitted; the following are particularly of note: - One possibility would be a way to map new cases to older ones on older - clients. This would only be useful for certain kinds of enums, though, and - adds a lot of additional complexity, all of which would be tied up in - versions. Our generalized switch patterns probably make it hard to nail - down the behavior here. +- A versioned function may not change its parameters or return type. +- A versioned function may not change its generic requirements. +- A versioned function may not change its external parameter names (labels). +- A versioned function may not add, remove, or reorder parameters, whether or + not they have default values. + +.. admonition:: TODO + + Can a throwing function become non-throwing? It's a "safe" change but + it's hard to document how it used to behave for backwards-deployers. Inlineable Functions -~~~~~~~~~~~~~~~~~~~~ +-------------------- Functions are a very common example of resilience: the function's declaration is published as API, but its body may change between library versions as long @@ -260,11 +278,11 @@ are a few common reasons for this: save the overhead of a cross-library function call and allow further optimization of callers. -- The function accesses a fixed-layout struct with non-public members; this +- The function accesses a fixed-contents struct with non-public members; this allows the library author to preserve invariants while still allowing efficient access to the struct. -A public function marked with the ``@inlineable`` attribute makes its body +A versioned function marked with the ``@inlineable`` attribute makes its body available to clients as part of the module's public interface. The ``@inlineable`` attribute takes a version number, just like ``@available``; clients may not assume that the body of the function is suitable when deploying @@ -276,21 +294,24 @@ Clients are not required to inline a function marked ``@inlineable``. It is legal to change the implementation of an inlineable function in the next release of the library. However, any such change must be made with the - understanding that it may or may not affect existing clients. + understanding that it may or may not affect existing clients. Existing + clients may use the new implementation, or they may use the implementation + from the time they were compiled, or they may use both inconsistently. -Restrictions ------------- + +Restrictions on Inlineable Functions +------------------------------------ Because the body of an inlineable function (or method, accessor, initializer, or deinitializer) may be inlined into another module, it must not make any assumptions that rely on knowledge of the current module. Here is a trivial -example:: +example using methods:: public struct Point2D { var x, y: Double public init(x: Double, y: Double) { … } } - + extension Point2D { @inlineable public func distanceTo(other: Point2D) -> Double { let deltaX = self.x - other.x @@ -317,12 +338,13 @@ the following restrictions on the bodies of inlineable functions: functions declared within the inlineable function itself. - **They must not reference any** ``internal`` **entities except for those that - have been** `availability-pinned`_. See below for a discussion of pinning. + have been** `versioned`_. See below for a discussion of versioning internal + API. - **They must not reference any entities less available than the function itself.** -.. _availability-pinned: #pinning +.. _versioned: #versioning-internal-api An inlineable function is still emitted into its own module's binary. This makes it possible to take an existing function and make it inlineable, as long @@ -339,73 +361,89 @@ Local Functions --------------- If an inlineable function contains local functions or closures, these are -implicitly made inlineable as well. This is important in case you decide to -change the inlineable function later. If the inlineable function is emitted -into a client module as described above, the local functions must be as well. -(At the SIL level, these local functions are considered to have ``shared`` -linkage.) - -Pinning -------- - -An `availability-pinned` entity is simply an ``internal`` member, free -function, or global binding that has been marked ``@available``. This promises -that the entity will be available at link time in the containing module's -binary. This makes it safe to refer to such an entity from an inlineable -function. If a pinned entity is ever made ``public``, its availability should -not be changed. +implicitly made inlineable as well. This is important in case the library +author decides to change the inlineable function later. If the inlineable +function is emitted into a client module as described above, the local +functions must be as well. (At the SIL level, these local functions are +considered to have ``shared`` linkage.) -.. note:: +Local functions are subject to the same restrictions as the inlineable +functions containing them, as described above. - Why isn't this a special form of ``public``? Because we don't want it to - imply everything that ``public`` does, such as requiring overrides to be - ``public``. -Because a pinned class member may eventually be made public, it must be assumed -that new overrides may eventually appear from outside the module unless the -member is marked ``final`` or the class is not publicly subclassable. +Top-Level Variables and Constants +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We could do away with the entire "pinning" feature if we restricted inlineable -functions to only refer to public entities. However, this removes one of the -primary reasons to make something inlineable: to allow efficient access to a -type while still protecting its invariants. +Given a versioned module-scope variable declared with ``var``, the following +changes are permitted: -.. note:: +- Adding (but not removing) a public setter to a computed variable. +- Adding or removing a non-public, non-versioned setter. +- Changing from a stored variable to a computed variable, or vice versa, as + long as a previously-versioned setter is not removed. +- Changing the body of an accessor. +- Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from + an existing variable. This is effectively the same as modifying the body of a + setter. +- Changing the initial value of a stored variable. - Types are not allowed to be pinned because that would have many more ripple - effects. It's not technically impossible; it just requires a lot more - thought. +.. admonition:: TODO + We need to pin down how this interacts with the "Behaviors" proposal. + Behaviors that just change the accessors of a global are fine, but those + that provide new entry points are trickier. -A Unifying Theme -~~~~~~~~~~~~~~~~ +If a public setter is added after the property is first exposed (whether the +property is stored or computed), it must be versioned independently of the +property itself. -So far this proposal has talked about three separate ways to lock down on three -separate Swift entities: structs, enums, and functions. Each of these has a -different set of constraints it enforces on the library author and promises it -makes to clients. However, they all follow a common theme of giving up the -flexibility of future changes in exchange for improved performance and perhaps -some semantic guarantees. As such, we could consider using a common attribute, -say ``@fixed``, ``@inline``, or ``@fragile``; either way, all attributes in -this section can be referred to as "fragility attributes". +.. admonition:: TODO + This needs syntax. -Constants -~~~~~~~~~ +Additionally, for a module-scope constant declared with ``let``, the following +changes are permitted: + +- Changing the value of the constant. -The ``let`` keyword creates a named constant whose value will not change for -the lifetime of that entity; for a global or static constant, this lasts from -when the constant is first accessed (and lazily initialized) until the end of -program execution. However, different versions of the same library may choose -to have different values for a constant---say, a string describing the -library's copyright information. +It is *not* safe to change a ``let`` constant into a variable or vice versa. +Top-level constants are assumed not to change for the entire lifetime of the +program once they have been initialized. -In order to make use of a constant's value across library boundaries, the -library owner may mark the constant as ``@inlineable``. As when applied to -functions, the attribute takes a version number specifying which versions of -the library will behave correctly if the value is inlined into client code. +.. note:: We could make it safe to turn a read-only variable into a constant, + but currently do not promise that that is a binary-compatible change. -Note that if the constant's initial value expression has any observable side + +Giving Up Flexibility +--------------------- + +Both top-level constants and variables can be marked ``@inlineable`` to allow +clients to access them more efficiently. This restricts changes a fair amount: + +- Adding a versioned setter to a computed variable is still permitted. +- Adding or removing a non-public, non-versioned setter is still permitted. +- Changing from stored to computed or vice versa is forbidden, because it would + break existing clients. +- Changing the body of an accessor is permitted but discouraged; existing + clients may use the new implementations, or they may use the implementations + from the time they were compiled, or a mix of both. +- Adding/removing observing accessors is likewise permitted but discouraged, + for the same reason. +- Changing the initial value of a stored variable is still permitted. +- Changing the value of a constant is permitted but discouraged; like accessors, + existing clients may use the new value, or the value from when they were + compiled, or a mix of both. + +.. admonition:: TODO + + It Would Be Nice(tm) to allow marking the *getter* of a top-level variable + inlineable while still allowing the setter to change. This would need + syntax, though. + +Any inlineable accessors must follow the rules for `inlineable functions`_, +as described above. + +Note that if a constant's initial value expression has any observable side effects, including the allocation of class instances, it must not be treated as inlineable. A constant must always behave as if it is initialized exactly once. @@ -416,67 +454,450 @@ once. restricted to things that can be lowered to compile-time constants? -Properties -~~~~~~~~~~ +Structs +~~~~~~~ -By default, a stored property in a struct or class may be replaced by a -computed property in later versions of a library. As shown above, the -``@fixed_layout`` attribute promises that all stored properties currently in a -type will remain stored in all future library versions, but sometimes that -isn't a reasonable promise. In this case, a library owner may still want to -allow clients to rely on a *specific* stored property remaining stored, by -applying the ``@fixed`` attribute to the property. +Swift structs are a little more flexible than their C counterparts. By default, +the following changes are permitted: + +- Reordering any existing members, including stored properties. +- Adding any new members, including stored properties. +- Changing existing properties from stored to computed or vice versa. +- Changing the body of any methods, initializers, or accessors. +- Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from + an existing property. This is effectively the same as modifying the body of a + setter. +- Removing any non-public, non-versioned members, including stored properties. +- Adding a new protocol conformance (with proper availability annotations). +- Removing conformances to non-public protocols. + +The important most aspect of a Swift struct is its value semantics, not its +layout. .. admonition:: TODO - Is it valid for a fixed property to have observing accessors, or is it more - useful to promise that the setter is just a direct field access too? If it - were spelled ``@fragile``, I would assume that accessors are permitted but - they become inlineable, and so not having any accessors is just a - degenerate case of that. - - Is this feature sufficiently useful to be proposed initially at all, or is - it too granular? + We need to pin down how this, and the ``@fixed_contents`` attribute below, + interacts with the "Behaviors" proposal. Behaviors that just change the + accessors of a property are fine, but those that provide new entry points + are trickier. + +Like top-level constants, it is *not* safe to change a ``let`` property into a +variable or vice versa. Properties declared with ``let`` are assumed not to +change for the entire lifetime of the program once they have been initialized. + -Like all other attributes in this section, the ``@fixed`` attribute must -specify in which version of the library clients may rely on the property being -stored. The attribute may not be applied to non-final properties in classes. +New Conformances +---------------- + +If a conformance is added to a type in version 1.1 of a library, it's important +that it isn't accessed in version 1.0. This is obvious if the protocol itself +was introduced in version 1.1, but needs special handling if both the protocol +and the type were available earlier. In this case, the conformance *itself* +needs to be labeled as being introduced in version 1.1, so that the compiler +can enforce its safe use. .. note:: - It would be possible to allow ``@fixed`` on non-final properties, and have - it only apply when the client code is definitively working with an instance - of the base class, not any of its subclasses. But this is probably too - subtle, and makes it look like the attribute is doing something useful when - it actually isn't. + This may feel like a regression from Objective-C, where `duck typing` would + allow a ``Wand`` to be passed as an ``id `` without ill effects. + However, ``Wand`` would still fail a ``-conformsToProtocol:`` check in + version 1.0 of the library, and so whether or not the client code will work + is dependent on what should be implementation details of the library. +We've considered two possible syntaxes for this:: + @available(1.1) + extension MyStruct : SomeProto {…} -Other Promises About Types -~~~~~~~~~~~~~~~~~~~~~~~~~~ +and -Advanced users may want to promise more specific things about various types. -These are similar to the internal ``effects`` attribute we have for functions, -except that they can be enforced by the compiler. +:: -- ``trivial``: Promises that the type is `trivial`. Note that this is not a - recursive property; a trivial type may still require indirection due to - having an unknown size, and so a type containing that type is not considered - trivial. + extension MyStruct : @available(1.1) SomeProto {…} + +The former requires fewer changes to the language grammar, but the latter could +also be used on the declaration of the type itself (i.e. the ``struct`` +declaration). + +If we went with the former syntax, applying ``@available`` to an extension +would override the default availability of entities declared within the +extension; unlike access control, entities within the extension may freely +declare themselves to be either more or less available than what the extension +provides. + + +Fixed-Contents Structs +---------------------- + +To opt out of this flexibility, a struct may be marked ``@fixed_contents``. +This promises that no stored properties will be added to or removed from the +struct, even ``private`` or ``internal`` ones. Additionally, all versioned +stored properties in a ``@fixed_contents`` struct are implicitly declared +``@inlineable`` (as described above for top-level variables). In effect: + +- Reordering stored instance properties relative to one another is not + permitted. Reordering all other members is still permitted. +- Adding new stored instance properties (public or non-public) is not permitted. + Adding any other new members is still permitted. +- Existing instance properties may not be changed from stored to computed or + vice versa. +- Changing the body of any *existing* methods, initializers, computed property + accessors, or non-instance stored property accessors is permitted. Changing + the body of a stored instance property observing accessor is only permitted + if the property is not `versioned `. +- Adding or removing observing accessors from any + `versioned ` stored instance properties (public or + non-public) is not permitted. +- Removing stored instance properties is not permitted. Removing any other + non-public, non-versioned members is still permitted. +- Adding a new protocol conformance is still permitted. +- Removing conformances to non-public protocols is still permitted. + +Additionally, if the type of any stored instance property includes a struct or +enum, that struct or enum must be `versioned `. This includes +generic parameters and members of tuples. -- ``size_in_bits(N)``: Promises that the type is not larger than a certain - size. (It may be smaller.) +.. note:: -- ``no_payload``: Promises that an enum does not have payloads on any of its - cases (even the non-public ones). + This name is intentionally awful to encourage us to come up with a better + one. -Collectively these features are known as "performance assertions", to -underscore the fact that they do not affect how a type is used at the source -level, but do allow for additional optimizations. We may also expose some of -these qualities to static or dynamic queries for performance-sensitive code. +A ``@fixed_contents`` struct is *not* guaranteed to use the same layout as a C +struct with a similar "shape". If such a struct is necessary, it should be +defined in a C header and imported into Swift. + +.. note:: + + We can add a *different* feature to control layout some day, or something + equivalent, but this feature should not restrict Swift from doing useful + things like minimizing member padding. + +.. note:: + + It would be possible to say that a ``@fixed_contents`` struct only + guarantees the "shape" of the struct, so to speak, while + leaving all property accesses to go through function calls. This would + allow stored properties to change their accessors, or (with the Behaviors + proposal) to change a behavior's implementation, or change from one + behavior to another. However, the *most common case* here is probably just + a simple C-like struct that groups together simple values, with only public + stored properties and no observing accessors, and having to opt into direct + access to those properties seems unnecessarily burdensome. The struct is + being declared ``@fixed_contents`` for a reason, after all: it's been + discovered that its use is causing performance issues. + + Consequently, as a first pass we may just require all stored properties in + a ``@fixed_contents`` struct, public or non-public, to have trivial + accessors, i.e. no observing accessors and no behaviors. + +The ``@fixed_contents`` attribute takes a version number, just like +``@available``. This is so that clients can deploy against older versions of +the library, which may have a different layout for the struct. (In this case +the client must manipulate the struct as if the ``@fixed_contents`` attribute +were absent.) + +.. admonition:: TODO + + We really shouldn't care about the *order* of the stored properties. + + +Enums +~~~~~ + +By default, a library owner may add new cases to a public enum between releases +without breaking binary compatibility. As with structs, this results in a fair +amount of indirection when dealing with enum values, in order to potentially +accommodate new values. More specifically, the following changes are permitted: + +- Adding a new case. +- Reordering existing cases, although this is discouraged. In particular, if + an enum is RawRepresentable, changing the raw representations of cases may + break existing clients who use them for serialization. +- Adding a raw type to an enum that does not have one. +- Removing a non-public, non-versioned case. +- Adding any other members. +- Removing any non-public, non-versioned members. +- Adding a new protocol conformance (with proper availability annotations). +- Removing conformances to non-public protocols. + +.. note:: + + If an enum value has a known case, or can be proven to belong to a set of + known cases, the compiler is of course free to use a more efficient + representation for the value, just as it may discard fields of structs that + are provably never accessed. + +.. note:: + + Non-public cases in public enums don't exist at the moment, but they *can* + be useful, and they require essentially the same implementation work as + cases added in future versions of a library. + +.. admonition:: TODO + + This states that adding/removing ``indirect`` (on either a case or the + entire enum) is considered a breaking change. Is that what we want? + + +Closed Enums +------------ + +A library owner may opt out of this flexibility by marking a versioned enum as +``@closed``. A "closed" enum may not have any cases with less access than the +enum itself, and may not add new cases in the future. This guarantees to +clients that the enum cases are exhaustive. In particular: + +- Adding new cases is not permitted +- Reordering existing cases is not permitted. +- Adding a raw type to an enum that does not have one is still permitted. +- Removing a non-public case is not applicable. +- Adding any other members is still permitted. +- Removing any non-public, non-versioned members is still permitted. +- Adding a new protocol conformance is still permitted. +- Removing conformances to non-public protocols is still permitted. + +.. note:: + + Were a public "closed" enum allowed to have non-public cases, clients of + the library would still have to treat the enum as opaque and would still + have to be able to handle unknown cases in their ``switch`` statements. + +The ``@closed`` attribute takes a version number, just like ``@available``. +This is so that clients can deploy against older versions of the library, which +may have non-public cases in the enum. (In this case the client must manipulate +the enum as if the ``@closed`` attribute were absent.) All cases that are not +versioned become implicitly versioned with this number. + +Even for default "open" enums, adding new cases should not be done lightly. Any +clients attempting to do an exhaustive switch over all enum cases will likely +not handle new cases well. + +.. note:: + + One possibility would be a way to map new cases to older ones on older + clients. This would only be useful for certain kinds of enums, though, and + adds a lot of additional complexity, all of which would be tied up in + versions. Our generalized switch patterns probably make it hard to nail + down the behavior here. + + +Protocols +~~~~~~~~~ + +There are very few safe changes to make to protocols: + +- A new non-type requirement may be added to a protocol, as long as it has an + unconstrained default implementation. +- A new optional requirement may be added to an ``@objc`` protocol. +- All members may be reordered, including associated types. + +However, any members may be added to protocol extensions, and non-public, +non-versioned members may always be removed from protocol extensions. + +.. admonition:: TODO + + We don't have an implementation model hammered out for adding new + defaulted requirements, but it is desirable. + +.. admonition:: TODO + + It would also be nice to be able to add new associated types with default + values, but that seems trickier to implement. + + +Classes +~~~~~~~ + +Because class instances are always accessed through references, they are very +flexible and can change in many ways between releases. Like structs, classes +support all of the following changes: + +- Reordering any existing members, including stored properties. +- Changing existing properties from stored to computed or vice versa. +- Changing the body of any methods, initializers, or accessors. +- Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from + an existing property. This is effectively the same as modifying the body of a + setter. +- Removing any non-public, non-versioned members, including stored properties. +- Adding a new protocol conformance (with proper availability annotations). +- Removing conformances to non-public protocols. + +Omitted from this list is the free addition of new members. Here classes are a +little more restrictive than structs; they only allow the following changes: + +- Adding a new convenience initializer. +- Adding a new designated initializer, if the class is not publicly + subclassable. +- Adding a deinitializer. +- Adding new, non-overriding method, subscript, or property. +- Adding a new overriding member, as long as its type does not change. + Changing the type could be incompatible with existing overrides in subclasses. + +Finally, classes allow the following changes that do not apply to structs: + +- "Moving" a method, subscript, or property up to its superclass. The + declaration of the original member must remain along with its original + availability, but its body may consist of simply calling the new superclass + implementation. +- Changing a class's superclass ``A`` to another class ``B``, *if* class ``B`` + is a subclass of ``A`` *and* class ``B``, along with any superclasses between + it and class ``A``, were introduced in the latest version of the library. +- A non-final override of a method, subscript, property, or initializer may be + removed as long as the generic parameters, formal parameters, and return type + *exactly* match the overridden declaration. Any existing callers should + automatically use the superclass implementation. + +.. admonition:: TODO + + The latter is very tricky to get right. We've seen it happen a few times in + Apple's SDKs, but at least one of them, `NSCollectionViewItem`_ becoming a + subclass of NSViewController instead of the root class NSObject, doesn't + strictly follow the rules. While NSViewController was introduced in the + same version of the OS, its superclass, NSResponder, was already present. + If a client app was deploying to an earlier version of the OS, would + NSCollectionViewItem be a subclass of NSResponder or not? How would the + compiler be able to enforce this? + +.. _NSCollectionViewItem: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSCollectionViewItem_Class/index.html + +Other than those detailed above, no other changes to a class or its members +are permitted. In particular: + +- New designated initializers may not be added to a publicly-subclassable + class. This would change the inheritance of convenience initializers, which + existing subclasses may depend on. +- New ``required`` initializers may not be added to a publicly-subclassable + class. There is no way to guarantee their presence on existing subclasses. +- ``final`` may not be added to *or* removed from a class or any of its members. + The presence of ``final`` enables optimization; its absence means there may + be subclasses/overrides that would be broken by the change. +- ``dynamic`` may not be added to *or* removed from any members. Existing + clients would not know to invoke the member dynamically. +- A ``final`` override of a member may *not* be removed, even if the type + matches exactly; existing clients may be performing a direct call to the + implementation instead of using dynamic dispatch. + +.. note:: These restrictions tie in with the ongoing discussions about + "``final``-by-default" and "non-publicly-subclassable-by-default". + + +Possible Restrictions on Classes +-------------------------------- + +In addition to ``final``, it may be useful to restrict the size of a class +instance (like a struct's ``@fixed_contents``) or the number of overridable +members in its virtual dispatch table. These annotations have not been designed. + + +Extensions +~~~~~~~~~~ + +Non-protocol extensions largely follow the same rules as the types they extend. +The following changes are permitted: + +- Adding new extensions and removing empty extensions. +- Moving a member from one extension to another within the same module, as long + as both extensions have the exact same constraints. +- Moving a member from an extension to the declaration of the base type, + provided that the declaration is in the same module. The reverse is permitted + for all members except stored properties, although note that moving all + initializers out of a type declaration may cause a new one to be implicitly + synthesized. + +Adding, removing, reordering, and modifying members follow the same rules as +the base type; see the sections on structs, enums, and classes above. + + +Protocol Extensions +------------------- + +Protocol extensions follow slightly different rules; the following changes +are permitted: + +- Adding new extensions and removing empty extensions. +- Moving a member from one extension to another within the same module, as long + as both extensions have the exact same constraints. +- Adding any new member. +- Reordering members. +- Removing any non-public, non-versioned member. +- Changing the body of any methods, initializers, or accessors. + + +Operators +~~~~~~~~~ + +Operator declarations are entirely compile-time constructs, so changing them +does not have any affect on binary compatibility. However, they do affect +*source* compatibility, so it is recommended that existing operators are not +changed at all except for the following: + +- Making a non-associative operator left- or right-associative. -All of these features take a version number, just like the more semantic -fragility attributes above. The exact spelling is not proposed by this document. + +A Unifying Theme +~~~~~~~~~~~~~~~~ + +So far this proposal has talked about ways to give up flexibility for several +different kinds of declarations: ``@inlineable`` for functions, +``@fixed_contents`` for structs, etc. Each of these has a different set of +constraints it enforces on the library author and promises it makes to clients. +However, they all follow a common theme of giving up the flexibility of future +changes in exchange for improved performance and perhaps some semantic +guarantees. Therefore, all of these attributes are informally referred to as +"fragility attributes". + +Given that these attributes share several characteristics, we could consider +converging on a single common attribute, say ``@fixed``, ``@inline``, or +``@fragile``. However, this may be problematic if the same declaration has +multiple kinds of flexibility, as in the description of classes above. + + +Versioning Internal Declarations +================================ + +The initial discussion on versioning focused on ``public`` APIs, making sure +that a client knows what features they can use when a specific version of a +library is present. Inlineable functions have much the same constraints, except +the inlineable function is the client and the entities being used may not be +``public``. + +Adding a versioning annotation to an ``internal`` entity promises that the +entity will be available at link time in the containing module's binary. This +makes it safe to refer to such an entity from an inlineable function. If the +entity is ever made ``public``, its availability should not be changed; not +only is it safe for new clients to rely on it, but *existing* clients require +its presence as well. + +.. note:: + + Why isn't this a special form of ``public``? Because we don't want it to + imply everything that ``public`` does, such as requiring overrides to be + ``public``. + +Because a versioned class member may eventually be made ``public``, it must be +assumed that new overrides may eventually appear from outside the module unless +the member is marked ``final`` or the class is not publicly subclassable. + +Non-public conformances are never considered versioned, even if both the +conforming type and the protocol are versioned. + +Entities declared ``private`` may not be versioned; the mangled name of such an +entity includes an identifier based on the containing file, which means moving +the declaration to another file changes the entity's mangled name. This implies +that a client would not be able to find the entity at run time if the source +code is reorganized, which is unacceptable. + +.. note:: + + There are ways around this limitation, the most simple being that versioned + ``private`` entities are subject to the same cross-file redeclaration rules + as ``internal`` entities. However, this is a purely additive feature, so to + keep things simple we'll stick with the basics. + +We could do away with the entire feature if we restricted inlineable functions +and fixed-contents structs to only refer to public entities. However, this +removes one of the primary reasons to make something inlineable: to allow +efficient access to a type while still protecting its invariants. Optimization @@ -532,11 +953,11 @@ containing library is the version attached to the ``@inlineable`` attribute. Code within this context must be treated as if the containing library were just a normal dependency. -A publicly inlineable function still has a public symbol, which may be used -when the function is referenced from a client rather than called. This version -of the function is not subject to the same restrictions as the version that -may be inlined, and so it may be desirable to compile a function twice: once -for inlining, once for maximum performance. +A versioned inlineable function still has an exported symbol in the library +binary, which may be used when the function is referenced from a client rather +than called. This version of the function is not subject to the same +restrictions as the version that may be inlined, and so it may be desirable to +compile a function twice: once for inlining, once for maximum performance. Local Availability Contexts @@ -554,6 +975,37 @@ optimization that may be complicated to implement (and even to represent properly in SIL), and so it is not a first priority. +Other Promises About Types +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Advanced users may want to promise more specific things about various types. +These are similar to the internal ``effects`` attribute we have for functions, +except that they can be enforced by the compiler. + +- ``trivial``: Promises that the type is `trivial`. + +- ``size_in_bits(N)``: Promises that the type is not larger than a certain + size. (It may be smaller.) + +- ``fixed_size``: Promises that the type has *some* size known at compile-time, + allowing optimizations like promoting allocations to the stack. Only applies + to fixed-contents structs and closed enums, which can already infer this + information; the explicit annotation allows it to be enforced. + +Collectively these features are known as "performance assertions", to +underscore the fact that they do not affect how a type is used at the source +level, but do allow for additional optimizations. We may also expose some of +these qualities to static or dynamic queries for performance-sensitive code. + +.. note:: Previous revisions of this document contained a ``no_payload`` + assertion for enums. However, this doesn't actually offer any additional + optimization opportunities over combining ``trivial`` with ``size_in_bits``, + and the latter is more flexible. + +All of these features need to be versioned, just like the more semantic +fragility attributes above. The exact spelling is not proposed by this document. + + Resilience Domains ================== @@ -581,56 +1033,6 @@ a client has the same resilience domain name as a library it is using, it may assume that version of the library will be present at runtime. -Protocol Conformances -===================== - -Consider this scenario: a library is released containing both a ``MagicType`` -protocol and a ``Wand`` struct. ``Wand`` satisfies all the requirements of the -``MagicType`` protocol, but the conformance was never actually declared in the -library. Someone files a bug, and it gets fixed in version 1.1. - -Now, what happens when this client code is deployed against version 1.0 of the -library? - -:: - - // Library - @available(1.0) - public func classifyMagicItem(item: Item) -> MagicKind - - // Client - let kind = classifyMagicItem(elderWand) - log("\(elderWand): \(kind)") - -In order to call ``classifyMagicItem``, the client code needs access to the -conformance of ``Wand`` to the ``MagicType`` protocol. But that conformance -*didn't exist* in version 1.0, so the client program will fail on older systems. - -Therefore, a library author needs a way to declare that a type *now* conforms -to a protocol when it previously didn't. The way to do this is by placing -availability information on an extension:: - - @available(1.1) - extension Wand : MagicType {} - -Note that this is unnecessary if either ``Wand`` or ``MagicType`` were itself -introduced in version 1.1; in that case, it would not be possible to access -the conformance from a context that only required 1.0. - -As with access control, applying ``@available`` to an extension overrides the -default availability of entities declared within the extension; unlike access -control, entities within the extension may freely declare themselves to be -either more or less available than what the extension provides. - -.. note:: - - This may feel like a regression from Objective-C, where `duck typing` would - allow a ``Wand`` to be passed as an ``id `` without ill effects. - However, ``Wand`` would still fail a ``-conformsToProtocol:`` check in - version 1.0 of the library, and so whether or not the client code will work - is dependent on what should be implementation details of the library. - - Checking Binary Compatibility ============================= @@ -639,16 +1041,16 @@ check their work. Therefore, we intend to ship a tool that can compare two versions of a library's public interface, and present any suspect differences for verification. Important cases include but are not limited to: -- Removal of public entities. +- Removal of versioned entities. -- Incompatible modifications to public entities, such as added protocol +- Incompatible modifications to versioned entities, such as added protocol conformances lacking versioning information. - + - Unsafely-backdated "fragile" attributes as discussed in the `Giving Up Flexibility`_ section. - -- Unsafe modifications to entities marked with the "fragile" attributes, such as - adding a stored property to a ``@fixed_layout`` struct. + +- Unsafe modifications to entities marked with the "fragile" attributes, such as + adding a stored property to a ``@fixed_contents`` struct. Automatic Versioning @@ -709,7 +1111,7 @@ Glossary API An `entity` in a library that a `client` may use, or the collection of all such entities in a library. (If contrasting with `SPI`, only those entities - that are available to arbitrary clients.) Marked ``public`` in + that are available to arbitrary clients.) Marked ``public`` in Swift. Stands for "Application Programming Interface". availability context @@ -718,15 +1120,12 @@ Glossary are always properly nested, and the global availability context includes the module's minimum deployment target and minimum dependency versions. - availability-pinned - See `Pinning`_. - backwards-compatible A modification to an API that does not break existing clients. May also describe the API in question. binary compatibility - A general term encompassing both backwards- and forwards-compatibility + A general term encompassing both backwards- and forwards-compatibility concerns. Also known as "ABI compatibility". client @@ -741,7 +1140,9 @@ Glossary (Note that this is a dynamic constraint.) entity - A type, function, member, or global in a Swift program. + A type, function, member, or global in a Swift program. Occasionally the + term "entities" also includes conformances, since these have a runtime + presence and are depended on by clients. forwards-compatible An API that is designed to handle future clients, perhaps allowing certain @@ -753,7 +1154,7 @@ Glossary module The primary unit of code sharing in Swift. Code in a module is always built together, though it may be spread across several source files. - + performance assertion See `Other Promises About Types`_. @@ -768,9 +1169,12 @@ Glossary target In this document, a collection of code in a single Swift module that is - built together; a "compilation unit". Roughly equivalent to a target in + built together; a "compilation unit". Roughly equivalent to a target in Xcode. trivial A value whose assignment just requires a fixed-size bit-for-bit copy without any indirection or reference-counting operations. + + versioned entity + See `Publishing Versioned API`_. diff --git a/docs/MutationModel.rst b/docs/MutationModel.rst index dae65de7431d2..d75b4d8ea1c32 100644 --- a/docs/MutationModel.rst +++ b/docs/MutationModel.rst @@ -37,10 +37,10 @@ Consider:: } var w = Window() - w.title += " (parenthesized remark)” + w.title += " (parenthesized remark)" What do we do with this? Since ``+=`` has an ``inout`` first -argument, we detect this situation statically (hopefully one day we’ll +argument, we detect this situation statically (hopefully one day we'll have a better error message): :: @@ -53,7 +53,7 @@ Great. Now what about this? [#append]_ :: w.title.append(" (fool the compiler)") -Today, we allow it, but since there’s no way to implement the +Today, we allow it, but since there's no way to implement the write-back onto ``w.title``, the changes are silently dropped. Unsatisfying Approaches @@ -101,14 +101,14 @@ Otherwise, it is considered **read-only**. The implicit ``self`` parameter of a struct or enum method is semantically an ``inout`` parameter if and only if the method is attributed with -``mutating``. Read-only methods do not “write back” onto their target +``mutating``. Read-only methods do not "write back" onto their target objects. A program that applies the ``mutating`` to a method of a class—or of a protocol attributed with ``@class_protocol``—is ill-formed. [Note: it is logically consistent to think of all methods of classes as read-only, even though they may in fact modify instance -variables, because they never “write back” onto the source reference.] +variables, because they never "write back" onto the source reference.] Mutating Operations ------------------- diff --git a/docs/OptimizationTips.rst b/docs/OptimizationTips.rst index a8c66e01eb8fc..8f2280bdced4f 100644 --- a/docs/OptimizationTips.rst +++ b/docs/OptimizationTips.rst @@ -157,7 +157,7 @@ do not have any overriding declarations in the same file: func usingE(e: E) { e.doSomething() // There is no sub class in the file that declares this class. // The compiler can remove virtual calls to doSomething() - // and directly call A’s doSomething method. + // and directly call A's doSomething method. } func usingF(f: F) -> Int { @@ -176,7 +176,7 @@ Advice: Use value types in Array In Swift, types can be divided into two different categories: value types (structs, enums, tuples) and reference types (classes). A key distinction is -that value types can not be included inside an NSArray. Thus when using value +that value types cannot be included inside an NSArray. Thus when using value types, the optimizer can remove most of the overhead in Array that is necessary to handle the possibility of the array being backed an NSArray. @@ -265,7 +265,7 @@ Swift eliminates integer overflow bugs by checking for overflow when performing normal arithmetic. These checks are not appropriate in high performance code where one knows that no memory safety issues can result. -Advice: Use unchecked integer arithmetic when you can prove that overflow can not occur +Advice: Use unchecked integer arithmetic when you can prove that overflow cannot occur --------------------------------------------------------------------------------------- In performance-critical code you can elide overflow checks if you know it is @@ -446,7 +446,7 @@ argument drops from being O(n), depending on the size of the tree to O(1). :: - struct tree : P { + struct Tree : P { var node : [P?] init() { node = [ thing ] diff --git a/docs/OptimizerDesign.md b/docs/OptimizerDesign.md index dd653dad74912..e6e767ad0bf7b 100644 --- a/docs/OptimizerDesign.md +++ b/docs/OptimizerDesign.md @@ -25,7 +25,7 @@ phase (stands for intermediate representation generation phase) that lowers SIL into LLVM IR. The LLVM backend optimizes and emits binary code for the compiled program. -Please refer to the document “Swift Intermediate Language (SIL)” for more +Please refer to the document "Swift Intermediate Language (SIL)" for more details about the SIL IR. The compiler optimizer is responsible for optimizing the program using the @@ -125,8 +125,8 @@ The mechanism that swift uses to invalidate analysis is broadcast-invalidation. Passes ask the pass manager to invalidate specific traits. For example, a pass like simplify-cfg will ask the pass manager to announce that it modified some branches in the code. The pass manager will send a message to all of the -available analysis that says “please invalidate yourself if you care about -branches for function F“. The dominator tree would then invalidate the dominator +available analysis that says "please invalidate yourself if you care about +branches for function F". The dominator tree would then invalidate the dominator tree for function F because it knows that changes to branches can mean that the dominator tree was modified. @@ -180,7 +180,7 @@ This is an example of the *@_semantics* attribute as used by Swift Array: Notice that as soon as we inline functions that have the @_semantics attribute the attribute is lost and the optimizer can't analyze the content of the -function. For example, the optimizer can identify the array ‘count' method (that +function. For example, the optimizer can identify the array 'count' method (that returns the size of the array) and can hoist this method out of loops. However, as soon as this method is inlined, the code looks to the optimizer like a memory read from an undetermined memory location, and the optimizer can't optimize the @@ -189,7 +189,7 @@ functions with the @_semantics attribute until after all of the data-structure specific optimizations are done. Unfortunately, this lengthens our optimization pipeline. -Please refer to the document “High-Level SIL Optimizations” for more details. +Please refer to the document "High-Level SIL Optimizations" for more details. ### Instruction Invalidation in SIL @@ -241,4 +241,4 @@ TODO. ### List of passes -The updated list of passes is available in the file “Passes.def”. +The updated list of passes is available in the file "Passes.def". diff --git a/docs/Pattern Matching.rst b/docs/Pattern Matching.rst index d0bfedd6c2dfd..08dc743faa3bc 100644 --- a/docs/Pattern Matching.rst +++ b/docs/Pattern Matching.rst @@ -141,7 +141,7 @@ provide patterns for the other kinds of types as well. Selection statement ------------------- -This is the main way we expect users to employ non-obvious pattern- matching. We +This is the main way we expect users to employ non-obvious pattern-matching. We obviously need something with statement children, so this has to be a statement. That's also fine because this kind of full pattern match is very syntactically heavyweight, and nobody would want to embed it in the middle of an @@ -354,7 +354,7 @@ imperative language — in contrast to, say, a functional language where you're in an expression and you need to produce a value — there's a colorable argument that non-exhaustive matches should be okay. I dislike this, however, and propose that it should be an error to -make an non-exhaustive switch; people who want non-exhaustive matches +make a non-exhaustive switch; people who want non-exhaustive matches can explicitly put in default cases. Exhaustiveness actually isn't that difficult to check, at least over ADTs. It's also really the behavior that I would expect from the @@ -689,13 +689,13 @@ interpreted according to what is found: value must match the named type (according to the rules below for 'is' patterns). It is okay for this to be trivially true. - In addition, there must be an non-empty arguments clause, and each + In addition, there must be a non-empty arguments clause, and each element in the clause must have an identifier. For each element, the identifier must correspond to a known property of the named type, and the value of that property must satisfy the element pattern. -- If the name resolves to a enum element, then the dynamic type +- If the name resolves to an enum element, then the dynamic type of the matched value must match the enum type as discussed above, and the value must be of the specified element. There must be an arguments clause if and only if the element has a value type. diff --git a/docs/Runtime.md b/docs/Runtime.md new file mode 100644 index 0000000000000..198b49ed60c14 --- /dev/null +++ b/docs/Runtime.md @@ -0,0 +1,404 @@ +# The Swift Runtime + +This document describes the ABI interface to the Swift runtime, which provides +the following core functionality for Swift programs: + +- memory management, including allocation and reference counting; +- the runtime type system, including dynamic casting, generic instantiation, + and protocol conformance registration; + +It is intended to describe only the runtime interface that compiler-generated +code should conform to, not details of how things are implemented. + +The final runtime interface is currently a work-in-progress; it is a goal of +Swift 3 to stabilize it. This document attempts to describe both the current +state of the runtime and the intended endpoint of the stable interface. +Changes that are intended to be made before stabilization are marked with +**ABI TODO**. Entry points that only exist on Darwin platforms with +ObjC interop, and +information that only pertains to ObjC interop, are marked **ObjC-only**. + +## Deprecated entry points + +Entry points in this section are intended to be removed or internalized before +ABI stabilization. + +### Exported C++ symbols + +**ABI TODO**: Any exported C++ symbols are implementation details that are not +intended to be part of the stable runtime interface. + +### swift\_ClassMirror\_count +### swift\_ClassMirror\_quickLookObject +### swift\_ClassMirror\_subscript +### swift\_EnumMirror\_caseName +### swift\_EnumMirror\_count +### swift\_EnumMirror\_subscript +### swift\_MagicMirrorData\_objcValue +### swift\_MagicMirrorData\_objcValueType +### swift\_MagicMirrorData\_summary +### swift\_MagicMirrorData\_value +### swift\_MagicMirrorData\_valueType +### swift\_ObjCMirror\_count +### swift\_ObjCMirror\_subscript +### swift\_StructMirror\_count +### swift\_StructMirror\_subscript +### swift\_TupleMirror\_count +### swift\_TupleMirror\_subscript +### swift\_reflectAny + +**ABI TODO**: These functions are implementation details of the standard +library `reflect` interface. They will be superseded by a low-level +runtime reflection API. + +### swift\_stdlib\_demangleName + +``` +@convention(thin) (string: UnsafePointer, + length: UInt, + @out String) -> () +``` + +Given a pointer to a Swift mangled symbol name as a byte string of `length` +characters, returns the demangled name as a `Swift.String`. + +**ABI TODO**: Decouple from the standard library `Swift.String` implementation. +Rename with a non-`stdlib` naming scheme. + +## Memory allocation + +### TODO + +``` +000000000001cb30 T _swift_allocBox +000000000001c990 T _swift_allocObject +000000000001ca60 T _swift_bufferAllocate +000000000001ca70 T _swift_bufferAllocateOnStack +000000000001ca80 T _swift_bufferDeallocateFromStack +000000000001ca90 T _swift_bufferHeaderSize +000000000001cd30 T _swift_deallocBox +000000000001d490 T _swift_deallocClassInstance +000000000001cd60 T _swift_deallocObject +000000000001d4c0 T _swift_deallocPartialClassInstance +000000000001d400 T _swift_rootObjCDealloc +000000000001c960 T _swift_slowAlloc +000000000001c980 T _swift_slowDealloc +000000000001ce10 T _swift_projectBox +000000000001ca00 T _swift_initStackObject +``` + +## Reference counting + +### TODO + +``` +0000000000027ba0 T _swift_bridgeObjectRelease +0000000000027c50 T _swift_bridgeObjectRelease_n +0000000000027b50 T _swift_bridgeObjectRetain +0000000000027be0 T _swift_bridgeObjectRetain_n +000000000001ce70 T _swift_release +000000000001cee0 T _swift_release_n +000000000001ce30 T _swift_retain +000000000001ce50 T _swift_retain_n +000000000001d140 T _swift_tryPin +000000000001d240 T _swift_tryRetain +0000000000027b10 T _swift_unknownRelease +0000000000027a70 T _swift_unknownRelease_n +0000000000027ad0 T _swift_unknownRetain +0000000000027a10 T _swift_unknownRetain_n +0000000000027d50 T _swift_unknownUnownedAssign +00000000000280a0 T _swift_unknownUnownedCopyAssign +0000000000027fd0 T _swift_unknownUnownedCopyInit +0000000000027ed0 T _swift_unknownUnownedDestroy +0000000000027cb0 T _swift_unknownUnownedInit +0000000000027f20 T _swift_unknownUnownedLoadStrong +00000000000281f0 T _swift_unknownUnownedTakeAssign +0000000000028070 T _swift_unknownUnownedTakeInit +0000000000027f70 T _swift_unknownUnownedTakeStrong +00000000000282b0 T _swift_unknownWeakAssign +0000000000028560 T _swift_unknownWeakCopyAssign +00000000000284e0 T _swift_unknownWeakCopyInit +00000000000283e0 T _swift_unknownWeakDestroy +0000000000028270 T _swift_unknownWeakInit +0000000000028420 T _swift_unknownWeakLoadStrong +0000000000028610 T _swift_unknownWeakTakeAssign +0000000000028520 T _swift_unknownWeakTakeInit +0000000000028470 T _swift_unknownWeakTakeStrong +000000000001d3c0 T _swift_unownedCheck +000000000001cfb0 T _swift_unownedRelease +000000000001d0a0 T _swift_unownedRelease_n +000000000001cf70 T _swift_unownedRetain +000000000001cf60 T _swift_unownedRetainCount +000000000001d2b0 T _swift_unownedRetainStrong +000000000001d310 T _swift_unownedRetainStrongAndRelease +000000000001d060 T _swift_unownedRetain_n +000000000001d1b0 T _swift_unpin +000000000001ca20 T _swift_verifyEndOfLifetime +000000000001d680 T _swift_weakAssign +000000000001d830 T _swift_weakCopyAssign +000000000001d790 T _swift_weakCopyInit +000000000001d770 T _swift_weakDestroy +000000000001d640 T _swift_weakInit +000000000001d6d0 T _swift_weakLoadStrong +000000000001d8b0 T _swift_weakTakeAssign +000000000001d800 T _swift_weakTakeInit +000000000001d710 T _swift_weakTakeStrong +000000000002afe0 T _swift_isUniquelyReferencedNonObjC +000000000002af50 T _swift_isUniquelyReferencedNonObjC_nonNull +000000000002b060 T _swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject +000000000002b200 T _swift_isUniquelyReferencedOrPinnedNonObjC_nonNull +000000000002b130 T _swift_isUniquelyReferencedOrPinnedNonObjC_nonNull_bridgeObject +000000000002b2f0 T _swift_isUniquelyReferencedOrPinned_native +000000000002b290 T _swift_isUniquelyReferencedOrPinned_nonNull_native +000000000002af00 T _swift_isUniquelyReferenced_native +000000000002aea0 T _swift_isUniquelyReferenced_nonNull_native +000000000001d280 T _swift_isDeallocating +``` + +**ABI TODO**: `_unsynchronized` r/r entry points + +## Error objects + +The `ErrorType` existential type uses a special single-word, reference- +counted representation. + +**ObjC-only**: The representation is internal to the runtime in order +to provide efficient bridging with the platform `NSError` and `CFError` +implementations. On non-ObjC platforms this bridging is unnecessary, and +the error object interface could be made more fragile. + +To preserve the encapsulation of the ErrorType representation, and +allow for future representation optimizations, the runtime provides +special entry points for allocating, projecting, and reference +counting error values. + + +``` +00000000000268e0 T _swift_allocError +0000000000026d50 T _swift_bridgeErrorTypeToNSError +0000000000026900 T _swift_deallocError +0000000000027120 T _swift_errorRelease +0000000000027100 T _swift_errorRetain +0000000000026b80 T _swift_getErrorValue +``` + +**ABI TODO**: `_unsynchronized` r/r entry points + +**ABI TODO**: `_n` r/r entry points + +## Initialization + +### swift_once + +``` +@convention(thin) (Builtin.RawPointer, @convention(thin) () -> ()) -> () +``` + +Used to lazily initialize global variables. The first parameter must +point to a word-sized memory location that was initialized to zero at +process start. It is undefined behavior to reference memory that has +been initialized to something other than zero or written to by anything other +than `swift_once` in the current process's lifetime. The function referenced by +the second parameter will have been run exactly once in the time between +process start and the function returns. + +## Dynamic casting + +``` +0000000000001470 T _swift_dynamicCast +0000000000000a60 T _swift_dynamicCastClass +0000000000000ae0 T _swift_dynamicCastClassUnconditional +0000000000028750 T _swift_dynamicCastForeignClass +000000000002ae20 T _swift_dynamicCastForeignClassMetatype +000000000002ae30 T _swift_dynamicCastForeignClassMetatypeUnconditional +0000000000028760 T _swift_dynamicCastForeignClassUnconditional +00000000000011c0 T _swift_dynamicCastMetatype +0000000000000cf0 T _swift_dynamicCastMetatypeToObjectConditional +0000000000000d20 T _swift_dynamicCastMetatypeToObjectUnconditional +00000000000012e0 T _swift_dynamicCastMetatypeUnconditional +00000000000286c0 T _swift_dynamicCastObjCClass +0000000000028bd0 T _swift_dynamicCastObjCClassMetatype +0000000000028c00 T _swift_dynamicCastObjCClassMetatypeUnconditional +0000000000028700 T _swift_dynamicCastObjCClassUnconditional +0000000000028af0 T _swift_dynamicCastObjCProtocolConditional +0000000000028a50 T _swift_dynamicCastObjCProtocolUnconditional +0000000000028960 T _swift_dynamicCastTypeToObjCProtocolConditional +00000000000287d0 T _swift_dynamicCastTypeToObjCProtocolUnconditional +0000000000000de0 T _swift_dynamicCastUnknownClass +0000000000000fd0 T _swift_dynamicCastUnknownClassUnconditional +``` + +## Debugging + +``` +0000000000027140 T _swift_willThrow +``` + +## Objective-C Bridging + +**ObjC-only**. + +**ABI TODO**: Decouple from the runtime as much as possible. Much of this +should be implementable in the standard library now. + +``` +0000000000003b60 T _swift_bridgeNonVerbatimFromObjectiveC +0000000000003c80 T _swift_bridgeNonVerbatimFromObjectiveCConditional +00000000000037e0 T _swift_bridgeNonVerbatimToObjectiveC +00000000000039c0 T _swift_getBridgedNonVerbatimObjectiveCType +0000000000003d90 T _swift_isBridgedNonVerbatimToObjectiveC +``` + +## Code generation + +Certain common code paths are implemented in the runtime as a code size +optimization. + +``` +0000000000023a40 T _swift_assignExistentialWithCopy +000000000001dbf0 T _swift_copyPOD +000000000001c560 T _swift_getEnumCaseMultiPayload +000000000001be60 T _swift_getEnumCaseSinglePayload +000000000001c400 T _swift_storeEnumTagMultiPayload +000000000001bf90 T _swift_storeEnumTagSinglePayload +``` + +## Type metadata lookup + +These functions look up metadata for types that potentially require runtime +instantiation or initialization, including structural types, generics, classes, +and metadata for imported C and Objective-C types. + +**ABI TODO**: Instantiation APIs under flux as part of resilience work. For +nominal types, `getGenericMetadata` is likely to become an implementation +detail used to implement resilient per-type metadata accessor functions. + +``` +0000000000023230 T _swift_getExistentialMetatypeMetadata +0000000000023630 T _swift_getExistentialTypeMetadata +0000000000023b90 T _swift_getForeignTypeMetadata +000000000001ef30 T _swift_getFunctionTypeMetadata +000000000001eed0 T _swift_getFunctionTypeMetadata1 +000000000001f1f0 T _swift_getFunctionTypeMetadata2 +000000000001f250 T _swift_getFunctionTypeMetadata3 +000000000001e940 T _swift_getGenericMetadata +0000000000022fd0 T _swift_getMetatypeMetadata +000000000001ec50 T _swift_getObjCClassMetadata +000000000001e6b0 T _swift_getResilientMetadata +0000000000022260 T _swift_getTupleTypeMetadata +00000000000225a0 T _swift_getTupleTypeMetadata2 +00000000000225d0 T _swift_getTupleTypeMetadata3 +0000000000028bc0 T _swift_getInitializedObjCClass +``` + +**ABI TODO**: Fast entry points for `getExistential*TypeMetadata1-3`. Static +metadata for `Any` and `AnyObject` is probably worth considering too. + +## Type metadata initialization + +Calls to these entry points are emitted when instantiating type metadata at +runtime. + +**ABI TODO**: Initialization APIs under flux as part of resilience work. + +``` +000000000001e3e0 T _swift_allocateGenericClassMetadata +000000000001e620 T _swift_allocateGenericValueMetadata +0000000000022be0 T _swift_initClassMetadata_UniversalStrategy +000000000001c100 T _swift_initEnumMetadataMultiPayload +000000000001bd60 T _swift_initEnumValueWitnessTableSinglePayload +0000000000022a20 T _swift_initStructMetadata_UniversalStrategy +0000000000024230 T _swift_initializeSuperclass +0000000000028b60 T _swift_instantiateObjCClass +``` + +## Metatypes + +``` +0000000000000b60 T _swift_getDynamicType +0000000000022fb0 T _swift_getObjectType +00000000000006f0 T _swift_getTypeName +00000000000040c0 T _swift_isClassType +0000000000003f50 T _swift_isClassOrObjCExistentialType +0000000000004130 T _swift_isOptionalType +00000000000279f0 T _swift_objc_class_usesNativeSwiftReferenceCounting +000000000002b340 T _swift_objc_class_unknownGetInstanceExtents +000000000002b350 T _swift_class_getInstanceExtents +0000000000004080 T _swift_class_getSuperclass +``` + +**ABI TODO**: getTypeByName entry point. + +**ABI TODO**: Should have a `getTypeKind` entry point with well-defined enum +constants to supersede `swift_is*Type`. + +**ABI TODO**: Rename class metadata queries with a consistent naming scheme. + +## Protocol conformance lookup + +``` +0000000000002ef0 T _swift_registerProtocolConformances +0000000000003060 T _swift_conformsToProtocol +``` + +## Error reporting + +``` +000000000001c7d0 T _swift_reportError +000000000001c940 T _swift_deletedMethodError +``` + +## Standard metadata + +The Swift runtime exports standard metadata objects for `Builtin` types +as well as standard value witness tables that can be freely adopted by +types with common layout attributes. Note that, unlike public-facing types, +the runtime does not guarantee a 1:1 mapping of Builtin types to metadata +objects, and will reuse metadata objects to represent builtins with the same +layout characteristics. + +``` +000000000004faa8 S __TMBB +000000000004fab8 S __TMBO +000000000004f9f8 S __TMBb +000000000004f9c8 S __TMBi128_ +000000000004f998 S __TMBi16_ +000000000004f9d8 S __TMBi256_ +000000000004f9a8 S __TMBi32_ +000000000004f9b8 S __TMBi64_ +000000000004f988 S __TMBi8_ +000000000004f9e8 S __TMBo +000000000004fac8 S __TMT_ +000000000004f568 S __TWVBO +000000000004f4b0 S __TWVBb +000000000004f0a8 S __TWVBi128_ +000000000004eec8 S __TWVBi16_ +000000000004f148 S __TWVBi256_ +000000000004ef68 S __TWVBi32_ +000000000004f008 S __TWVBi64_ +000000000004ee28 S __TWVBi8_ +000000000004f1e8 S __TWVBo +000000000004f778 S __TWVFT_T_ +000000000004f3f8 S __TWVMBo +000000000004f8e8 S __TWVT_ +000000000004f830 S __TWVXfT_T_ +000000000004f620 S __TWVXoBO +000000000004f2a0 S __TWVXoBo +000000000004f6d8 S __TWVXwGSqBO_ +000000000004f358 S __TWVXwGSqBo_ +``` + +## Tasks + +- Moving to per-type instantiation functions instead of using + `getGenericMetadata` directly + +- `swift_objc_` naming convention for ObjC + +- Alternative ABIs for retain/release + +- Unsynchronized retain/release + +- Nonnull retain/release + +- Decouple dynamic casting, bridging, and reflection from the standard library diff --git a/docs/SIL.rst b/docs/SIL.rst index fd17000af32fb..2d41071bb3288 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -341,8 +341,6 @@ The type of a value in SIL shall be: - the address of a legal SIL type, ``$*T``, or -- the address of local storage of a legal SIL type, ``$*@local_storage T``. - A type ``T`` is a *legal SIL type* if: - it is a function type which satisfies the constraints (below) on @@ -386,22 +384,6 @@ type. Values of address type thus cannot be allocated, loaded, or stored Addresses can be passed as arguments to functions if the corresponding parameter is indirect. They cannot be returned. -Local Storage Types -``````````````````` - -The *address of local storage for T* ``$*@local_storage T`` is a -handle to a stack allocation of a variable of type ``$T``. - -For many types, the handle for a stack allocation is simply the -allocated address itself. However, if a type is runtime-sized, the -compiler must emit code to potentially dynamically allocate memory. -SIL abstracts over such differences by using values of local-storage -type as the first result of ``alloc_stack`` and the operand of -``dealloc_stack``. - -Local-storage address types are not *first-class* in the same sense -that address types are not first-class. - Box Types ````````` @@ -424,7 +406,7 @@ number of ways: - A SIL function type declares its conventional treatment of its context value: - - If it is ``@thin``, the function requires no context value. + - If it is ``@convention(thin)``, the function requires no context value. - If it is ``@callee_owned``, the context value is treated as an owned direct parameter. @@ -594,7 +576,7 @@ generic constraints: * Non-class protocol types * @weak types - Values of address-only type (“address-only values”) must reside in + Values of address-only type ("address-only values") must reside in memory and can only be referenced in SIL by address. Addresses of address-only values cannot be loaded from or stored to. SIL provides special instructions for indirectly manipulating address-only @@ -604,7 +586,7 @@ Some additional meaningful categories of type: - A *heap object reference* type is a type whose representation consists of a single strong-reference-counted pointer. This includes all class types, - the ``Builtin.ObjectPointer`` and ``Builtin.ObjCPointer`` types, and + the ``Builtin.NativeObject`` and ``Builtin.UnknownObject`` types, and archetypes that conform to one or more class protocols. - A *reference type* is more general in that its low-level representation may include additional global pointers alongside a strong-reference-counted @@ -721,7 +703,7 @@ Values and Operands sil-identifier ::= [A-Za-z_0-9]+ sil-value-name ::= '%' sil-identifier - sil-value ::= sil-value-name ('#' [0-9]+)? + sil-value ::= sil-value-name sil-value ::= 'undef' sil-operand ::= sil-value ':' sil-type @@ -729,17 +711,6 @@ SIL values are introduced with the ``%`` sigil and named by an alphanumeric identifier, which references the instruction or basic block argument that produces the value. SIL values may also refer to the keyword 'undef', which is a value of undefined contents. -In SIL, a single instruction may produce multiple values. Operands that refer -to multiple-value instructions choose the value by following the ``%name`` with -``#`` and the index of the value. For example:: - - // alloc_box produces two values--the refcounted pointer %box#0, and the - // value address %box#1 - %box = alloc_box $Int64 - // Refer to the refcounted pointer - strong_retain %box#0 : $@box Int64 - // Refer to the address - store %value to %box#1 : $*Int64 Unlike LLVM IR, SIL instructions that take value operands *only* accept value operands. References to literal constants, functions, global variables, or @@ -864,16 +835,17 @@ partial application level. For a curried function declaration:: The declaration references and types for the different uncurry levels are as follows:: - #example.foo!0 : $@thin (x:A) -> (y:B) -> (z:C) -> D - #example.foo!1 : $@thin ((y:B), (x:A)) -> (z:C) -> D - #example.foo!2 : $@thin ((z:C), (y:B), (x:A)) -> D + #example.foo!0 : $@convention(thin) (x:A) -> (y:B) -> (z:C) -> D + #example.foo!1 : $@convention(thin) ((y:B), (x:A)) -> (z:C) -> D + #example.foo!2 : $@convention(thin) ((z:C), (y:B), (x:A)) -> D The deepest uncurry level is referred to as the **natural uncurry level**. In this specific example, the reference at the natural uncurry level is ``#example.foo!2``. Note that the uncurried argument clauses are composed right-to-left, as specified in the `calling convention`_. For uncurry levels -less than the uncurry level, the entry point itself is ``@thin`` but returns a -thick function value carrying the partially applied arguments for its context. +less than the uncurry level, the entry point itself is ``@convention(thin)`` but +returns a thick function value carrying the partially applied arguments for its +context. `Dynamic dispatch`_ instructions such as ``class method`` require their method declaration reference to be uncurried to at least uncurry level 1 (which applies @@ -1007,9 +979,9 @@ implements the method for that class:: func bas() } - sil @A_foo : $@thin (@owned A) -> () - sil @A_bar : $@thin (@owned A) -> () - sil @A_bas : $@thin (@owned A) -> () + sil @A_foo : $@convention(thin) (@owned A) -> () + sil @A_bar : $@convention(thin) (@owned A) -> () + sil @A_bas : $@convention(thin) (@owned A) -> () sil_vtable A { #A.foo!1: @A_foo @@ -1021,7 +993,7 @@ implements the method for that class:: func bar() } - sil @B_bar : $@thin (@owned B) -> () + sil @B_bar : $@convention(thin) (@owned B) -> () sil_vtable B { #A.foo!1: @A_foo @@ -1033,7 +1005,7 @@ implements the method for that class:: func bas() } - sil @C_bas : $@thin (@owned C) -> () + sil @C_bas : $@convention(thin) (@owned C) -> () sil_vtable C { #A.foo!1: @A_foo @@ -1124,7 +1096,12 @@ Global Variables SIL representation of a global variable. -FIXME: to be written. +Global variable access is performed by the ``alloc_global`` and ``global_addr`` +SIL instructions. Prior to performing any access on the global, the +``alloc_global`` instruction must be performed to initialize the storage. + +Once a global's storage has been initialized, ``global_addr`` is used to +project the value. Dataflow Errors --------------- @@ -1192,8 +1169,8 @@ Calling Convention This section describes how Swift functions are emitted in SIL. -Swift Calling Convention @cc(swift) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Swift Calling Convention @convention(swift) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Swift calling convention is the one used by default for native Swift functions. @@ -1388,13 +1365,13 @@ gets lowered to SIL as:: sil @inout : $(@inout Int) -> () { entry(%x : $*Int): - %1 = integer_literal 1 : $Int + %1 = integer_literal $Int, 1 store %1 to %x return } -Swift Method Calling Convention @cc(method) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Swift Method Calling Convention @convention(method) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The method calling convention is currently identical to the freestanding function convention. Methods are considered to be curried functions, taking @@ -1408,8 +1385,8 @@ passed last:: sil @Foo_method_1 : $((x : Int), @inout Foo) -> Int { ... } -Witness Method Calling Convention @cc(witness_method) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Witness Method Calling Convention @convention(witness_method) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The witness method calling convention is used by protocol witness methods in `witness tables`_. It is identical to the ``method`` calling convention @@ -1420,8 +1397,8 @@ witnesses must be polymorphically dispatchable on their ``Self`` type, the ``Self``-related metadata for a witness must be passed in a maximally abstracted manner. -C Calling Convention @cc(cdecl) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +C Calling Convention @convention(c) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In Swift's C module importer, C types are always mapped to Swift types considered trivial by SIL. SIL does not concern itself with platform @@ -1431,8 +1408,8 @@ platform calling convention. SIL (and therefore Swift) cannot currently invoke variadic C functions. -Objective-C Calling Convention @cc(objc_method) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Objective-C Calling Convention @convention(objc_method) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Reference Counts ```````````````` @@ -1523,7 +1500,7 @@ return a class reference:: bb0(%0 : $MyClass): %1 = class_method %0 : $MyClass, #MyClass.foo!1 - %2 = apply %1(%0) : $@cc(method) @thin (@guaranteed MyClass) -> @owned MyOtherClass + %2 = apply %1(%0) : $@convention(method) (@guaranteed MyClass) -> @owned MyOtherClass // use of %2 goes here; no use of %1 strong_release %2 : $MyOtherClass strong_release %1 : $MyClass @@ -1558,8 +1535,8 @@ A value ``%1`` is said to be *value-dependent* on a value ``%0`` if: - ``%1`` is the result of ``mark_dependence`` and ``%0`` is either of the operands. -- ``%1`` is the value address of an allocation instruction of which - ``%0`` is the local storage token or box reference. +- ``%1`` is the value address of a box allocation instruction of which + ``%0`` is the box reference. - ``%1`` is the result of a ``struct``, ``tuple``, or ``enum`` instruction and ``%0`` is an operand. @@ -1633,13 +1610,15 @@ alloc_stack sil-instruction ::= 'alloc_stack' sil-type (',' debug-var-attr)* %1 = alloc_stack $T - // %1#0 has type $*@local_storage T - // %1#1 has type $*T + // %1 has type $*T Allocates uninitialized memory that is sufficiently aligned on the stack -to contain a value of type ``T``. The first result of the instruction -is a local-storage handle suitable for passing to ``dealloc_stack``. -The second result of the instruction is the address of the allocated memory. +to contain a value of type ``T``. The result of the instruction is the address +of the allocated memory. + +If a type is runtime-sized, the compiler must emit code to potentially +dynamically allocate memory. So there is no guarantee that the allocated +memory is really located on the stack. ``alloc_stack`` marks the start of the lifetime of the value; the allocation must be balanced with a ``dealloc_stack`` instruction to @@ -1700,15 +1679,13 @@ alloc_box sil-instruction ::= 'alloc_box' sil-type (',' debug-var-attr)* %1 = alloc_box $T - // %1 has two values: - // %1#0 has type $@box T - // %1#1 has type $*T + // %1 has type $@box T Allocates a reference-counted ``@box`` on the heap large enough to hold a value of type ``T``, along with a retain count and any other metadata required by the -runtime. The result of the instruction is a two-value operand; the first value -is the reference-counted ``@box`` reference that owns the box, and the second -value is the address of the value inside the box. +runtime. The result of the instruction is the reference-counted ``@box`` +reference that owns the box. The ``project_box`` instruction is used to retrieve +the address of the value inside the box. The box will be initialized with a retain count of 1; the storage will be uninitialized. The box owns the contained value, and releasing it to a retain @@ -1734,22 +1711,36 @@ behavior if the value buffer is currently allocated. The type operand must be a lowered object type. +alloc_global +```````````` + +:: + + sil-instruction ::= 'alloc_global' sil-global-name + + alloc_global @foo + +Initialize the storage for a global variable. This instruction has +undefined behavior if the global variable has already been initialized. + +The type operand must be a lowered object type. + dealloc_stack ````````````` :: sil-instruction ::= 'dealloc_stack' sil-operand - dealloc_stack %0 : $*@local_storage T - // %0 must be of a local-storage $*@local_storage T type + dealloc_stack %0 : $*T + // %0 must be of $*T type Deallocates memory previously allocated by ``alloc_stack``. The allocated value in memory must be uninitialized or destroyed prior to being deallocated. This instruction marks the end of the lifetime for the value created by the corresponding ``alloc_stack`` instruction. The operand -must be the ``@local_storage`` of the shallowest live ``alloc_stack`` -allocation preceding the deallocation. In other words, deallocations must be -in last-in, first-out stack order. +must be the shallowest live ``alloc_stack`` allocation preceding the +deallocation. In other words, deallocations must be in last-in, first-out +stack order. dealloc_box ``````````` @@ -2392,14 +2383,14 @@ function_ref sil-instruction ::= 'function_ref' sil-function-name ':' sil-type - %1 = function_ref @function : $@thin T -> U - // $@thin T -> U must be a thin function type + %1 = function_ref @function : $@convention(thin) T -> U + // $@convention(thin) T -> U must be a thin function type // %1 has type $T -> U Creates a reference to a SIL function. global_addr -``````````````` +``````````` :: @@ -2407,7 +2398,10 @@ global_addr %1 = global_addr @foo : $*Builtin.Word -Creates a reference to the address of a global variable. +Creates a reference to the address of a global variable which has been +previously initialized by ``alloc_global``. It is undefined behavior to +perform this operation on a global variable which has not been +initialized. integer_literal ``````````````` @@ -2445,6 +2439,7 @@ string_literal sil-instruction ::= 'string_literal' encoding string-literal encoding ::= 'utf8' encoding ::= 'utf16' + encoding ::= 'objc_selector' %1 = string_literal "asdf" // %1 has type $Builtin.RawPointer @@ -2452,7 +2447,10 @@ string_literal Creates a reference to a string in the global string table. The result is a pointer to the data. The referenced string is always null-terminated. The string literal value is specified using Swift's string -literal syntax (though ``\()`` interpolations are not allowed). +literal syntax (though ``\()`` interpolations are not allowed). When +the encoding is ``objc_selector``, the string literal produces a +reference to a UTF-8-encoded Objective-C selector in the Objective-C +method name segment. Dynamic Dispatch ~~~~~~~~~~~~~~~~ @@ -2483,7 +2481,7 @@ class_method sil-instruction ::= 'class_method' sil-method-attributes? sil-operand ',' sil-decl-ref ':' sil-type - %1 = class_method %0 : $T, #T.method!1 : $@thin U -> V + %1 = class_method %0 : $T, #T.method!1 : $@convention(thin) U -> V // %0 must be of a class type or class metatype $T // #T.method!1 must be a reference to a dynamically-dispatched method of T or // of one of its superclasses, at uncurry level >= 1 @@ -2512,11 +2510,11 @@ super_method sil-instruction ::= 'super_method' sil-method-attributes? sil-operand ',' sil-decl-ref ':' sil-type - %1 = super_method %0 : $T, #Super.method!1.foreign : $@thin U -> V + %1 = super_method %0 : $T, #Super.method!1.foreign : $@convention(thin) U -> V // %0 must be of a non-root class type or class metatype $T // #Super.method!1.foreign must be a reference to an ObjC method of T's // superclass or of one of its ancestor classes, at uncurry level >= 1 - // %1 will be of type $@thin U -> V + // %1 will be of type $@convention(thin) U -> V Looks up a method in the superclass of a class or class metatype instance. Note that for native Swift methods, ``super.method`` calls are statically @@ -2532,13 +2530,13 @@ witness_method sil-type ',' sil-decl-ref ':' sil-type %1 = witness_method $T, #Proto.method!1 \ - : $@thin @cc(witness_method) U -> V + : $@convention(witness_method) U -> V // $T must be an archetype // #Proto.method!1 must be a reference to a method of one of the protocol // constraints on T // U -> V must be the type of the referenced method, // generic on Self - // %1 will be of type $@thin U -> V + // %1 will be of type $@convention(thin) U -> V Looks up the implementation of a protocol method for a generic type variable constrained by that protocol. The result will be generic on the ``Self`` @@ -2553,20 +2551,20 @@ dynamic_method sil-instruction ::= 'dynamic_method' sil-method-attributes? sil-operand ',' sil-decl-ref ':' sil-type - %1 = dynamic_method %0 : $P, #X.method!1 : $@thin U -> V + %1 = dynamic_method %0 : $P, #X.method!1 : $@convention(thin) U -> V // %0 must be of a protocol or protocol composition type $P, // where $P contains the Swift.DynamicLookup protocol // #X.method!1 must be a reference to an @objc method of any class // or protocol type // - // The "self" argument of the method type $@thin U -> V must be - // Builtin.ObjCPointer + // The "self" argument of the method type $@convention(thin) U -> V must be + // Builtin.UnknownObject Looks up the implementation of an Objective-C method with the same selector as the named method for the dynamic type of the value inside an existential container. The "self" operand of the result function value is represented using an opaque type, the value for which must -be projected out as a value of type ``Builtin.ObjCPointer``. +be projected out as a value of type ``Builtin.UnknownObject``. It is undefined behavior if the dynamic type of the operand does not have an implementation for the Objective-C method with the selector to @@ -2605,7 +2603,7 @@ apply // %1, %2, etc. must be of the argument types $A, $B, etc. // %r will be of the return type $R - %r = apply %0(%1, %2, ...) : $(T, U, ...) -> R + %r = apply %0(%1, %2, ...) : $(T, U, ...) -> R // %0 must be of a polymorphic function type $(T, U, ...) -> R // %1, %2, etc. must be of the argument types after substitution $A, $B, etc. // %r will be of the substituted return type $R' @@ -2649,7 +2647,7 @@ partial_apply // of the tail part of the argument tuple of %0 // %c will be of the partially-applied thick function type (Z...) -> R - %c = partial_apply %0(%1, %2, ...) : $(Z..., T, U, ...) -> R + %c = partial_apply %0(%1, %2, ...) : $(Z..., T, U, ...) -> R // %0 must be of a polymorphic function type $(T, U, ...) -> R // %1, %2, etc. must be of the argument types after substitution $A, $B, etc. // of the tail part of the argument tuple of %0 @@ -2685,28 +2683,30 @@ curried function in Swift:: emits curry thunks in SIL as follows (retains and releases omitted for clarity):: - func @foo : $@thin A -> B -> C -> D -> E { + func @foo : $@convention(thin) A -> B -> C -> D -> E { entry(%a : $A): - %foo_1 = function_ref @foo_1 : $@thin (B, A) -> C -> D -> E - %thunk = partial_apply %foo_1(%a) : $@thin (B, A) -> C -> D -> E + %foo_1 = function_ref @foo_1 : $@convention(thin) (B, A) -> C -> D -> E + %thunk = partial_apply %foo_1(%a) : $@convention(thin) (B, A) -> C -> D -> E return %thunk : $B -> C -> D -> E } - func @foo_1 : $@thin (B, A) -> C -> D -> E { + func @foo_1 : $@convention(thin) (B, A) -> C -> D -> E { entry(%b : $B, %a : $A): - %foo_2 = function_ref @foo_2 : $@thin (C, B, A) -> D -> E - %thunk = partial_apply %foo_2(%b, %a) : $@thin (C, B, A) -> D -> E + %foo_2 = function_ref @foo_2 : $@convention(thin) (C, B, A) -> D -> E + %thunk = partial_apply %foo_2(%b, %a) \ + : $@convention(thin) (C, B, A) -> D -> E return %thunk : $(B, A) -> C -> D -> E } - func @foo_2 : $@thin (C, B, A) -> D -> E { + func @foo_2 : $@convention(thin) (C, B, A) -> D -> E { entry(%c : $C, %b : $B, %a : $A): - %foo_3 = function_ref @foo_3 : $@thin (D, C, B, A) -> E - %thunk = partial_apply %foo_3(%c, %b, %a) : $@thin (D, C, B, A) -> E + %foo_3 = function_ref @foo_3 : $@convention(thin) (D, C, B, A) -> E + %thunk = partial_apply %foo_3(%c, %b, %a) \ + : $@convention(thin) (D, C, B, A) -> E return %thunk : $(C, B, A) -> D -> E } - func @foo_3 : $@thin (D, C, B, A) -> E { + func @foo_3 : $@convention(thin) (D, C, B, A) -> E { entry(%d : $D, %c : $C, %b : $B, %a : $A): // ... body of foo ... } @@ -2723,21 +2723,22 @@ following example:: lowers to an uncurried entry point and is curried in the enclosing function:: - func @bar : $@thin (Int, @box Int, *Int) -> Int { + func @bar : $@convention(thin) (Int, @box Int, *Int) -> Int { entry(%y : $Int, %x_box : $@box Int, %x_address : $*Int): // ... body of bar ... } - func @foo : $@thin Int -> Int { + func @foo : $@convention(thin) Int -> Int { entry(%x : $Int): // Create a box for the 'x' variable %x_box = alloc_box $Int - store %x to %x_box#1 : $*Int + %x_addr = project_box %x_box : $@box Int + store %x to %x_addr : $*Int // Create the bar closure %bar_uncurried = function_ref @bar : $(Int, Int) -> Int - %bar = partial_apply %bar_uncurried(%x_box#0, %x_box#1) \ - : $(Int, Builtin.ObjectPointer, *Int) -> Int + %bar = partial_apply %bar_uncurried(%x_box, %x_addr) \ + : $(Int, Builtin.NativeObject, *Int) -> Int // Apply it %1 = integer_literal $Int, 1 @@ -2775,8 +2776,8 @@ metatype sil-instruction ::= 'metatype' sil-type - %1 = metatype $T.metatype - // %1 has type $T.metatype + %1 = metatype $T.Type + // %1 has type $T.Type Creates a reference to the metatype object for type ``T``. @@ -2786,9 +2787,9 @@ value_metatype sil-instruction ::= 'value_metatype' sil-type ',' sil-operand - %1 = value_metatype $T.metatype, %0 : $T + %1 = value_metatype $T.Type, %0 : $T // %0 must be a value or address of type $T - // %1 will be of type $T.metatype + // %1 will be of type $T.Type Obtains a reference to the dynamic metatype of the value ``%0``. @@ -2798,10 +2799,10 @@ existential_metatype sil-instruction ::= 'existential_metatype' sil-type ',' sil-operand - %1 = existential_metatype $P.metatype, %0 : $P + %1 = existential_metatype $P.Type, %0 : $P // %0 must be a value of class protocol or protocol composition // type $P, or an address of address-only protocol type $*P - // %1 will be a $P.metatype value referencing the metatype of the + // %1 will be a $P.Type value referencing the metatype of the // concrete value inside %0 Obtains the metatype of the concrete value @@ -3001,16 +3002,16 @@ the enum is injected with an `inject_enum_addr`_ instruction:: sil @init_with_data : $(AddressOnlyType) -> AddressOnlyEnum { entry(%0 : $*AddressOnlyEnum, %1 : $*AddressOnlyType): // Store the data argument for the case. - %2 = init_enum_data_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.HasData + %2 = init_enum_data_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.HasData!enumelt.1 copy_addr [take] %2 to [initialization] %1 : $*AddressOnlyType // Inject the tag. - inject_enum_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.HasData + inject_enum_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.HasData!enumelt.1 return } sil @init_without_data : $() -> AddressOnlyEnum { // No data. We only need to inject the tag. - inject_enum_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.NoData + inject_enum_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.NoData!enumelt return } @@ -3021,7 +3022,7 @@ discriminator and is done with the `switch_enum`_ terminator:: sil @switch_foo : $(Foo) -> () { entry(%foo : $Foo): - switch_enum %foo : $Foo, case #Foo.A: a_dest, case #Foo.B: b_dest + switch_enum %foo : $Foo, case #Foo.A!enumelt.1: a_dest, case #Foo.B!enumelt.1: b_dest a_dest(%a : $Int): /* use %a */ @@ -3038,14 +3039,15 @@ projecting the enum value with `unchecked_take_enum_data_addr`_:: sil @switch_foo : $ (Foo) -> () { entry(%foo : $*Foo): - switch_enum_addr %foo : $*Foo, case #Foo.A: a_dest, case #Foo.B: b_dest + switch_enum_addr %foo : $*Foo, case #Foo.A!enumelt.1: a_dest, \ + case #Foo.B!enumelt.1: b_dest a_dest: - %a = unchecked_take_enum_data_addr %foo : $*Foo, #Foo.A + %a = unchecked_take_enum_data_addr %foo : $*Foo, #Foo.A!enumelt.1 /* use %a */ b_dest: - %b = unchecked_take_enum_data_addr %foo : $*Foo, #Foo.B + %b = unchecked_take_enum_data_addr %foo : $*Foo, #Foo.B!enumelt.1 /* use %b */ } @@ -3055,8 +3057,8 @@ enum sil-instruction ::= 'enum' sil-type ',' sil-decl-ref (',' sil-operand)? - %1 = enum $U, #U.EmptyCase - %1 = enum $U, #U.DataCase, %0 : $T + %1 = enum $U, #U.EmptyCase!enumelt + %1 = enum $U, #U.DataCase!enumelt.1, %0 : $T // $U must be an enum type // #U.DataCase or #U.EmptyCase must be a case of enum $U // If #U.Case has a data type $T, %0 must be a value of type $T @@ -3072,7 +3074,7 @@ unchecked_enum_data sil-instruction ::= 'unchecked_enum_data' sil-operand ',' sil-decl-ref - %1 = unchecked_enum_data %0 : $U, #U.DataCase + %1 = unchecked_enum_data %0 : $U, #U.DataCase!enumelt.1 // $U must be an enum type // #U.DataCase must be a case of enum $U with data // %1 will be of object type $T for the data type of case U.DataCase @@ -3087,7 +3089,7 @@ init_enum_data_addr sil-instruction ::= 'init_enum_data_addr' sil-operand ',' sil-decl-ref - %1 = init_enum_data_addr %0 : $*U, #U.DataCase + %1 = init_enum_data_addr %0 : $*U, #U.DataCase!enumelt.1 // $U must be an enum type // #U.DataCase must be a case of enum $U with data // %1 will be of address type $*T for the data type of case U.DataCase @@ -3109,7 +3111,7 @@ inject_enum_addr sil-instruction ::= 'inject_enum_addr' sil-operand ',' sil-decl-ref - inject_enum_addr %0 : $*U, #U.Case + inject_enum_addr %0 : $*U, #U.Case!enumelt // $U must be an enum type // #U.Case must be a case of enum $U // %0 will be overlaid with the tag for #U.Case @@ -3129,7 +3131,7 @@ unchecked_take_enum_data_addr sil-instruction ::= 'unchecked_take_enum_data_addr' sil-operand ',' sil-decl-ref - %1 = unchecked_take_enum_data_addr %0 : $*U, #U.DataCase + %1 = unchecked_take_enum_data_addr %0 : $*U, #U.DataCase!enumelt.1 // $U must be an enum type // #U.DataCase must be a case of enum $U with data // %1 will be of address type $*T for the data type of case U.DataCase @@ -3156,8 +3158,8 @@ select_enum ':' sil-type %n = select_enum %0 : $U, \ - case #U.Case1: %1, \ - case #U.Case2: %2, /* ... */ \ + case #U.Case1!enumelt: %1, \ + case #U.Case2!enumelt: %2, /* ... */ \ default %3 : $T // $U must be an enum type @@ -3170,8 +3172,8 @@ enum value. This is equivalent to a trivial `switch_enum`_ branch sequence:: entry: switch_enum %0 : $U, \ - case #U.Case1: bb1, \ - case #U.Case2: bb2, /* ... */ \ + case #U.Case1!enumelt: bb1, \ + case #U.Case2!enumelt: bb2, /* ... */ \ default bb_default bb1: br cont(%1 : $T) // value for #U.Case1 @@ -3195,8 +3197,8 @@ select_enum_addr ':' sil-type %n = select_enum_addr %0 : $*U, \ - case #U.Case1: %1, \ - case #U.Case2: %2, /* ... */ \ + case #U.Case1!enumelt: %1, \ + case #U.Case2!enumelt: %2, /* ... */ \ default %3 : $T // %0 must be the address of an enum type $*U @@ -3265,6 +3267,7 @@ container may use one of several representations: containers: * `alloc_existential_box`_ + * `project_existential_box`_ * `open_existential_box`_ * `dealloc_existential_box`_ @@ -3279,8 +3282,9 @@ more expensive ``alloc_existential_box``:: // The slow general way to form an ErrorType, allocating a box and // storing to its value buffer: %error1 = alloc_existential_box $ErrorType, $NSError + %addr = project_existential_box $NSError in %error1 : $ErrorType strong_retain %nserror: $NSError - store %nserror to %error1#1 : $NSError + store %nserror to %addr : $NSError // The fast path supported for NSError: strong_retain %nserror: $NSError @@ -3422,7 +3426,7 @@ alloc_existential_box // $P must be a protocol or protocol composition type with boxed // representation // $T must be an AST type that conforms to P - // %1#0 will be of type $P + // %1 will be of type $P // %1#1 will be of type $*T', where T' is the most abstracted lowering of T Allocates a boxed existential container of type ``$P`` with space to hold a @@ -3430,8 +3434,25 @@ value of type ``$T'``. The box is not fully initialized until a valid value has been stored into the box. If the box must be deallocated before it is fully initialized, ``dealloc_existential_box`` must be used. A fully initialized box can be ``retain``-ed and ``release``-d like any -reference-counted type. The address ``%0#1`` is dependent on the lifetime of -the owner reference ``%0#0``. +reference-counted type. The ``project_existential_box`` instruction is used +to retrieve the address of the value inside the container. + +project_existential_box +``````````````````````` +:: + + sil-instruction ::= 'project_existential_box' sil-type 'in' sil-operand + + %1 = project_existential_box $T in %0 : $P + // %0 must be a value of boxed protocol or protocol composition type $P + // $T must be the most abstracted lowering of the AST type for which the box + // was allocated + // %1 will be of type $*T + +Projects the address of the value inside a boxed existential container. +The address is dependent on the lifetime of the owner reference ``%0``. +It is undefined behavior if the concrete type ``$T`` is not the same type for +which the box was allocated with ``alloc_existential_box``. open_existential_box ```````````````````` @@ -3626,7 +3647,7 @@ ref_to_raw_pointer sil-instruction ::= 'ref_to_raw_pointer' sil-operand 'to' sil-type %1 = ref_to_raw_pointer %0 : $C to $Builtin.RawPointer - // $C must be a class type, or Builtin.ObjectPointer, or Builtin.ObjCPointer + // $C must be a class type, or Builtin.NativeObject, or Builtin.UnknownObject // %1 will be of type $Builtin.RawPointer Converts a heap object reference to a ``Builtin.RawPointer``. The ``RawPointer`` @@ -3641,7 +3662,7 @@ raw_pointer_to_ref sil-instruction ::= 'raw_pointer_to_ref' sil-operand 'to' sil-type %1 = raw_pointer_to_ref %0 : $Builtin.RawPointer to $C - // $C must be a class type, or Builtin.ObjectPointer, or Builtin.ObjCPointer + // $C must be a class type, or Builtin.NativeObject, or Builtin.UnknownObject // %1 will be of type $C Converts a ``Builtin.RawPointer`` back to a heap object reference. Casting @@ -3808,10 +3829,10 @@ thick_to_objc_metatype sil-instruction ::= 'thick_to_objc_metatype' sil-operand 'to' sil-type - %1 = thick_to_objc_metatype %0 : $@thick T.metatype to $@objc_metatype T.metatype - // %0 must be of a thick metatype type $@thick T.metatype + %1 = thick_to_objc_metatype %0 : $@thick T.Type to $@objc_metatype T.Type + // %0 must be of a thick metatype type $@thick T.Type // The destination type must be the corresponding Objective-C metatype type - // %1 will be of type $@objc_metatype T.metatype + // %1 will be of type $@objc_metatype T.Type Converts a thick metatype to an Objective-C class metatype. ``T`` must be of class, class protocol, or class protocol composition type. @@ -3822,10 +3843,10 @@ objc_to_thick_metatype sil-instruction ::= 'objc_to_thick_metatype' sil-operand 'to' sil-type - %1 = objc_to_thick_metatype %0 : $@objc_metatype T.metatype to $@thick T.metatype - // %0 must be of an Objective-C metatype type $@objc_metatype T.metatype + %1 = objc_to_thick_metatype %0 : $@objc_metatype T.Type to $@thick T.Type + // %0 must be of an Objective-C metatype type $@objc_metatype T.Type // The destination type must be the corresponding thick metatype type - // %1 will be of type $@thick T.metatype + // %1 will be of type $@thick T.Type Converts an Objective-C class metatype to a thick metatype. ``T`` must be of class, class protocol, or class protocol composition type. @@ -4045,7 +4066,7 @@ select_value sil-instruction ::= 'select_value' sil-operand sil-select-value-case* (',' 'default' sil-value)? ':' sil-type - sil-selct-value-case ::= 'case' sil-value ':' sil-value + sil-select-value-case ::= 'case' sil-value ':' sil-value %n = select_value %0 : $U, \ @@ -4058,7 +4079,7 @@ select_value // %r1, %r2, %r3, etc. must have type $T // %n has type $T -Selects one of the "case" or "default" operands based on the case of an +Selects one of the "case" or "default" operands based on the case of a value. This is equivalent to a trivial `switch_value`_ branch sequence:: entry: @@ -4086,8 +4107,8 @@ switch_enum (',' sil-switch-default)? sil-switch-enum-case ::= 'case' sil-decl-ref ':' sil-identifier - switch_enum %0 : $U, case #U.Foo: label1, \ - case #U.Bar: label2, \ + switch_enum %0 : $U, case #U.Foo!enumelt: label1, \ + case #U.Bar!enumelt: label2, \ ..., \ default labelN @@ -4121,12 +4142,12 @@ original enum value. For example:: sil @sum_of_foo : $Foo -> Int { entry(%x : $Foo): switch_enum %x : $Foo, \ - case #Foo.Nothing: nothing, \ - case #Foo.OneInt: one_int, \ - case #Foo.TwoInts: two_ints + case #Foo.Nothing!enumelt: nothing, \ + case #Foo.OneInt!enumelt.1: one_int, \ + case #Foo.TwoInts!enumelt.1: two_ints nothing: - %zero = integer_literal 0 : $Int + %zero = integer_literal $Int, 0 return %zero : $Int one_int(%y : $Int): @@ -4162,8 +4183,8 @@ switch_enum_addr (',' sil-switch-enum-case)* (',' sil-switch-default)? - switch_enum_addr %0 : $*U, case #U.Foo: label1, \ - case #U.Bar: label2, \ + switch_enum_addr %0 : $*U, case #U.Foo!enumelt: label1, \ + case #U.Bar!enumelt: label2, \ ..., \ default labelN diff --git a/docs/SequencesAndCollections.rst b/docs/SequencesAndCollections.rst index f6272314b22e1..3478e89d62dee 100644 --- a/docs/SequencesAndCollections.rst +++ b/docs/SequencesAndCollections.rst @@ -60,8 +60,8 @@ As you can see, sequence does nothing more than deliver a generator. To understand the need for generators, it's important to distinguish the two kinds of sequences. -* **Volatile** sequences like “stream of network packets,” carry - their own traversal state, and are expected to be “consumed” as they +* **Volatile** sequences like "stream of network packets," carry + their own traversal state, and are expected to be "consumed" as they are traversed. * **Stable** sequences, like arrays, should *not* be mutated by `for`\ @@ -215,7 +215,7 @@ that stability in generic code, we'll need another protocol. Collections =========== -A **collection** is a stable sequence with addressable “positions,” +A **collection** is a stable sequence with addressable "positions," represented by an associated `Index` type:: protocol CollectionType : SequenceType { diff --git a/docs/StdlibAPIGuidelines.rst b/docs/StdlibAPIGuidelines.rst index 26004130fac61..230bac5ae3967 100644 --- a/docs/StdlibAPIGuidelines.rst +++ b/docs/StdlibAPIGuidelines.rst @@ -102,7 +102,7 @@ Subsequent Parameters Other Differences ----------------- -* We don't use namespace prefixes such as “`NS`”, relying instead on +* We don't use namespace prefixes such as "`NS`", relying instead on the language's own facilities. * Names of types, protocols and enum cases are `UpperCamelCase`. @@ -156,7 +156,7 @@ library, but are compatible with the Cocoa guidelines. } * Even unlabelled parameter names should be meaningful as they'll be - referred to in comments and visible in “generated headers” + referred to in comments and visible in "generated headers" (cmd-click in Xcode): .. parsed-literal:: @@ -200,12 +200,12 @@ Acceptable Short or Non-Descriptive Names func map(transformation: T->U) -> [U] // not this one - func forEach(body: (S.Generator.Element)->()) + func forEach(body: (S.Generator.Element) -> ()) Prefixes and Suffixes --------------------- -* `Any` is used as a prefix to denote “type erasure,” +* `Any` is used as a prefix to denote "type erasure," e.g. `AnySequence` wraps any sequence with element type `T`, conforms to `SequenceType` itself, and forwards all operations to the wrapped sequence. When handling the wrapper, the specific type of diff --git a/docs/StdlibRationales.rst b/docs/StdlibRationales.rst index 02d423d4b0a6d..6b90b80d14935 100644 --- a/docs/StdlibRationales.rst +++ b/docs/StdlibRationales.rst @@ -64,7 +64,7 @@ generally *should* use a keyword. For example, ``String(33, radix: they're converting. Secondly, avoiding method or property syntax provides a distinct context for code completion. Rather than appearing in completions offered after ``.``, for example, the - available conversions could show up whenever the user hit the “tab” + available conversions could show up whenever the user hit the "tab" key after an expression. Protocols with restricted conformance rules diff --git a/docs/StringDesign.rst b/docs/StringDesign.rst index 52fcfca9d8b6b..9480eb4f98c28 100644 --- a/docs/StringDesign.rst +++ b/docs/StringDesign.rst @@ -116,9 +116,9 @@ Goals ``String`` should: * honor industry standards such as Unicode -* when handling non-ASCII text, deliver “reasonably correct” +* when handling non-ASCII text, deliver "reasonably correct" results to users thinking only in terms of ASCII -* when handling ASCII text, provide “expected behavior” to users +* when handling ASCII text, provide "expected behavior" to users thinking only in terms of ASCII * be hard to use incorrectly * be easy to use correctly @@ -165,7 +165,7 @@ optimizations, including: - In-place modification of uniquely-owned buffers As a result, copying_ and slicing__ strings, in particular, can be -viewed by most programmers as being “almost free.” +viewed by most programmers as being "almost free." __ sliceable_ @@ -197,7 +197,7 @@ Strings are **Value Types** Distinct string variables have independent values: when you pass someone a string they get a copy of the value, and when someone passes you a string *you own it*. Nobody can change a string value -“behind your back.” +"behind your back." .. parsed-literal:: |swift| class Cave { @@ -219,7 +219,7 @@ passes you a string *you own it*. Nobody can change a string value `// s: String =` :look:`"Hey"`\ :aside:`…and it doesn't.` |swift| :look1:`t.addEcho()`\ :aside:`this call can't change c.lastSound…` |swift| [s, c.lastSound, t] - `// r0: String[] = ["Hey",` :look:`"HeyHey"`\ :aside:`…and it doesn't.`\ `, "HeyHeyHeyHey"]` + `// r0: [String] = ["Hey",` :look:`"HeyHey"`\ :aside:`…and it doesn't.`\ `, "HeyHeyHeyHey"]` Strings are **Unicode-Aware** ----------------------------- @@ -231,18 +231,18 @@ Strings are **Unicode-Aware** specifies requires careful justification. So far, we have found two possible points of deviation for Swift ``String``: - 1. The `Unicode Text Segmentation Specification`_ says, “`do not - break between CR and LF`__.” However, breaking extended + 1. The `Unicode Text Segmentation Specification`_ says, "`do not + break between CR and LF`__." However, breaking extended grapheme clusters between CR and LF may necessary if we wish - ``String`` to “behave normally” for users of pure ASCII. This + ``String`` to "behave normally" for users of pure ASCII. This point is still open for discussion. __ http://www.unicode.org/reports/tr29/#GB2 2. The `Unicode Text Segmentation Specification`_ says, - “`do not break between regional indicator symbols`__.” However, it also - says “(Sequences of more than two RI characters should be separated - by other characters, such as U+200B ZWSP).” Although the + "`do not break between regional indicator symbols`__." However, it also + says "(Sequences of more than two RI characters should be separated + by other characters, such as U+200B ZWSP)." Although the parenthesized note probably has less official weight than the other admonition, breaking pairs of RI characters seems like the right thing for us to do given that Cocoa already forms strings with @@ -278,7 +278,7 @@ Strings are **Locale-Agnostic** Strings neither carry their own locale information, nor provide behaviors that depend on a global locale setting. Thus, for any pair -of strings ``s1`` and ``s2``, “``s1 == s2``” yields the same result +of strings ``s1`` and ``s2``, "``s1 == s2``" yields the same result regardless of system state. Strings *do* provide a suitable foundation on which to build locale-aware interfaces.\ [#locales]_ @@ -316,8 +316,8 @@ Strings are Composed of ``Character``\ s cluster**, as specified by a default or tailored Unicode segmentation algorithm. This term is `precisely defined`__ by the Unicode specification, but it roughly means `what the user thinks of when she -hears “character”`__. For example, the pair of code points “LATIN -SMALL LETTER N, COMBINING TILDE” forms a single grapheme cluster, “ñ”. +hears "character"`__. For example, the pair of code points "LATIN +SMALL LETTER N, COMBINING TILDE" forms a single grapheme cluster, "ñ". __ http://www.unicode.org/glossary/#grapheme_cluster __ http://useless-factor.blogspot.com/2007/08/unicode-implementers-guide-part-4.html @@ -342,8 +342,8 @@ __ http://www.unicode.org/glossary/#extended_grapheme_cluster __ http://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table This segmentation offers naïve users of English, Chinese, French, and -probably a few other languages what we think of as the “expected -results.” However, not every script_ can be segmented uniformly for +probably a few other languages what we think of as the "expected +results." However, not every script_ can be segmented uniformly for all purposes. For example, searching and collation require different segmentations in order to handle Indic scripts correctly. To that end, strings support properties for more-specific segmentations: @@ -386,9 +386,9 @@ Strings are **Sliceable** .. parsed-literal:: |swift| s[r.start...r.end] `// r2 : String = "awe"` - |swift| s[\ :look1:`r.start...`\ ]\ :aside:`postfix slice operator means “through the end”` + |swift| s[\ :look1:`r.start...`\ ]\ :aside:`postfix slice operator means "through the end"` `// r3 : String = "awesome"` - |swift| s[\ :look1:`...r.start`\ ]\ :aside:`prefix slice operator means “from the beginning”` + |swift| s[\ :look1:`...r.start`\ ]\ :aside:`prefix slice operator means "from the beginning"` `// r4 : String = "Strings are "` |swift| :look1:`s[r]`\ :aside:`indexing with a range is the same as slicing` `// r5 : String = "awe"` @@ -579,7 +579,7 @@ How Would You Design It? 5. CodePoint substring search is just byte string search 6. Most programs that handle 8-bit files safely can handle UTF-8 safely 7. UTF-8 sequences sort in code point order. - 8. UTF-8 has no “byte order.” + 8. UTF-8 has no "byte order." __ http://research.swtch.com/2010/03/utf-8-bits-bytes-and-benefits.html @@ -682,7 +682,7 @@ withRange:subrange]`` becomes ``str[subrange].doFoo(arg)``. * Deprecated Cocoa APIs are not considered - * A status of “*Remove*” below indicates a feature whose removal is + * A status of "*Remove*" below indicates a feature whose removal is anticipated. Rationale is provided for these cases. Indexing @@ -806,18 +806,18 @@ Comparison func **<=** (lhs: String, rhs: String) -> Bool func **>=** (lhs: String, rhs: String) -> Bool -``NSString`` comparison is “literal” by default. As the documentation +``NSString`` comparison is "literal" by default. As the documentation says of ``isEqualToString``, - “Ö” represented as the composed character sequence “O” and umlaut - would not compare equal to “Ö” represented as one Unicode character. + "Ö" represented as the composed character sequence "O" and umlaut + would not compare equal to "Ö" represented as one Unicode character. By contrast, Swift string's primary comparison interface uses Unicode's default collation_ algorithm, and is thus always -“Unicode-correct.” Unlike comparisons that depend on locale, it is +"Unicode-correct." Unlike comparisons that depend on locale, it is also stable across changes in system state. However, *just like* ``NSString``\ 's ``isEqualToString`` and ``compare`` methods, it -should not be expected to yield ideal (or even “proper”) results in +should not be expected to yield ideal (or even "proper") results in all contexts. --------- @@ -940,7 +940,7 @@ Searching :Swift: .. parsed-literal:: - func **find**\ (match: (Character)->Bool) -> Range + func **find**\ (match: (Character) -> Bool) -> Range .. Admonition:: Usage Example @@ -1021,8 +1021,8 @@ Splitting :Swift: .. parsed-literal:: - func split(maxSplit: Int = Int.max()) -> String[] - func split(separator: Character, maxSplit: Int = Int.max()) -> String[] + func split(maxSplit: Int = Int.max()) -> [String] + func split(separator: Character, maxSplit: Int = Int.max()) -> [String] The semantics of these functions were taken from Python, which seems to be a fairly good representative of what modern languages are @@ -1038,7 +1038,7 @@ Splitting func **split**\ (seq: Seq, isSeparator: IsSeparator, maxSplit: Int = Int.max(), - allowEmptySlices: Bool = false ) -> Seq[] + allowEmptySlices: Bool = false ) -> [Seq] Splitting ~~~~~~~~~ @@ -1084,10 +1084,10 @@ Capitalization .. Note:: ``NSString`` capitalizes the first letter of each substring separated by spaces, tabs, or line terminators, which is in - no sense “Unicode-correct.” In most other languages that + no sense "Unicode-correct." In most other languages that support a ``capitalize`` method, it operates only on the first character of the string, and capitalization-by-word is - named something like “``title``.” If Swift ``String`` + named something like "``title``." If Swift ``String`` supports capitalization by word, it should be Unicode-correct, but how we sort this particular area out is still **TBD**. @@ -1100,7 +1100,7 @@ Capitalization :Swift: .. parsed-literal:: - trim **trim**\ (match: (Character)->Bool) -> String + trim **trim**\ (match: (Character) -> Bool) -> String .. Admonition:: Usage Example @@ -1712,7 +1712,7 @@ Why YAGNI * Derivation * ... -.. [#agnostic] Unicode specifies default (“un-tailored”) +.. [#agnostic] Unicode specifies default ("un-tailored") locale-independent collation_ and segmentation_ algorithms that make reasonable sense in most contexts. Using these algorithms allows strings to be naturally compared and combined, generating @@ -1748,6 +1748,6 @@ Why YAGNI been normalized, thus speeding up comparison operations. .. [#elements] Since ``String`` is locale-agnostic_, its elements are - determined using Unicode's default, “un-tailored” segmentation_ + determined using Unicode's default, "un-tailored" segmentation_ algorithm. diff --git a/docs/Testing.rst b/docs/Testing.rst index 49d9805073742..8e5c39f8de1ed 100644 --- a/docs/Testing.rst +++ b/docs/Testing.rst @@ -313,6 +313,8 @@ Other substitutions: * ``%platform-sdk-overlay-dir``: absolute path of the directory where the SDK overlay module files for the target platform are stored. +* ``%{python}``: run the same Python interpreter that's being used to run the + current ``lit`` test. When writing a test where output (or IR, SIL) depends on the bitness of the target CPU, use this pattern:: @@ -355,7 +357,7 @@ CPU=i386_or_x86_64`` to ``REQUIRES: CPU=x86_64``. ``swift_test_mode_optimize[_unchecked|none]_`` to specify a test mode plus cpu configuration. -``optimized_stdlib_``` to specify a optimized stdlib plus cpu +``optimized_stdlib_``` to specify an optimized stdlib plus cpu configuration. Feature ``REQUIRES: executable_test`` diff --git a/docs/TextFormatting.rst b/docs/TextFormatting.rst index 6c9bedfdc8ce7..30e47ef83eb5a 100644 --- a/docs/TextFormatting.rst +++ b/docs/TextFormatting.rst @@ -21,9 +21,9 @@ Scope Goals ..... -* The REPL and LLDB (“debuggers”) share formatting logic -* All types are “debug-printable” automatically -* Making a type “printable for humans” is super-easy +* The REPL and LLDB ("debuggers") share formatting logic +* All types are "debug-printable" automatically +* Making a type "printable for humans" is super-easy * ``toString()``-ability is a consequence of printability. * Customizing a type's printed representations is super-easy * Format variations such as numeric radix are explicit and readable @@ -43,11 +43,11 @@ Non-Goals that feature. Therefore, localization and dynamic format strings should be designed together, and *under this proposal* the only format strings are string literals containing interpolations - (“``\(...)``”). Cocoa programmers can still use Cocoa localization + ("``\(...)``"). Cocoa programmers can still use Cocoa localization APIs for localization jobs. In Swift, only the most common cases need to be very terse. - Anything “fancy” can afford to be a bit more verbose. If and when + Anything "fancy" can afford to be a bit more verbose. If and when we address localization and design a full-featured dynamic string formatter, it may make sense to incorporate features of ``printf`` into the design. @@ -68,7 +68,7 @@ printed with ``print(x)``, and can be converted to ``String`` with The simple extension story for beginners is as follows: - “To make your type ``CustomStringConvertible``, simply declare conformance to + "To make your type ``CustomStringConvertible``, simply declare conformance to ``CustomStringConvertible``:: extension Person : CustomStringConvertible {} @@ -152,9 +152,9 @@ directly to the ``OutputStream`` for efficiency reasons, Producing a representation that can be consumed by the REPL and LLDB to produce an equivalent object is strongly encouraged where possible! For example, ``String.debugFormat()`` produces - a representation starting and ending with “``"``”, where special + a representation starting and ending with "``"``", where special characters are escaped, etc. A ``struct Point { var x, y: Int }`` - might be represented as “``Point(x: 3, y: 5)``”. + might be represented as "``Point(x: 3, y: 5)``". (Non-Debug) Printing .................... @@ -348,7 +348,7 @@ an underlying stream:: However, upcasing is a trivial example: many such transformations—such as ``trim()`` or regex replacement—are stateful, which implies some -way of indicating “end of input” so that buffered state can be +way of indicating "end of input" so that buffered state can be processed and written to the underlying stream: .. parsed-literal:: @@ -422,10 +422,10 @@ If we were willing to say that only ``class``\ es can conform to ``OutputStream``\ s are passed around. Then, we'd simply need a ``class StringStream`` for creating ``String`` representations. It would also make ``OutputStream`` adapters a *bit* simpler to use -because you'd never need to “write back” explicitly onto the target +because you'd never need to "write back" explicitly onto the target stream. However, stateful ``OutputStream`` adapters would still need a ``close()`` method, which makes a perfect place to return a copy of -the underlying stream, which can then be “written back”: +the underlying stream, which can then be "written back": .. parsed-literal:: diff --git a/docs/TypeChecker.rst b/docs/TypeChecker.rst index fb1856eb30645..21fd3b77a1319 100644 --- a/docs/TypeChecker.rst +++ b/docs/TypeChecker.rst @@ -106,7 +106,7 @@ the Swift type system: flavors of equality constraints: - Exact equality constraints, or "binding", written ``T0 := X`` - for some type variable ``T0`` and type ``X``, which requires + for some type variable ``T0`` and type ``X``, which requires that ``T0`` be exactly identical to ``X``; - Equality constraints, written ``X == Y`` for types ``X`` and ``Y``, which require ``X`` and ``Y`` to have the same type, diff --git a/docs/TypeReference.md b/docs/TypeReference.md new file mode 100644 index 0000000000000..4b7b44d6ecddb --- /dev/null +++ b/docs/TypeReference.md @@ -0,0 +1,66 @@ +# Symbolic Type References + +*Symbolic type references* are compact representations containing the +minimum amount of information about type relationships primarily for the +purposes of reflection. + +## Encoding + +These are encoded with a mostly textual mangling. Single characters +denote the start of a mangling node but 32-bit integers can also be +directly embedded. + +``` +typeref-symbol ::= prefix typeref + +typeref ::= 'b' relative-offset-to-name // Builtin type +typeref ::= 'n' relative-offset-to-metadata // Internal nominal type +typeref ::= 'N' relative-offset-to-name // External nominal type +typeref ::= 'g' relative-offset-to-metadata count typeref-list // Internal bound generic type +typeref ::= 'G' relative-offset-to-name count typeref-list // External bound generic type +typeref ::= '?' index depth // Generic parameter +typeref ::= 't' num-elements typeref-list // Tuple type +typeref ::= 'f' func-representation count typeref typeref // Function type +typeref ::= 'p' has-class-constrained-flag? count protocol-list // Protocol composition +typeref ::= 'm' typeref // Metatype +typeref ::= 'e' count protocol-list // Existential metatype + +has-class-constrained-flag ::= 'c' + +func-representation ::= 't' // Thin +func-representation ::= 'T' // Thick +func-representation ::= 'b' // Block + +base-255-i32 ::= <32-bit integer, variable length base-255 encoded> + +count ::= base-255-i32 +index ::= base-255-i32 +depth ::= base-255-i32 +relative-offset ::= base-255-i32 +``` + +### Relative Offset, Index, and Depth tokens + +`Relative offset` tokens are the 32-bit integers packed into the type +reference -- not a string of digits. These are used to efficiently +reference other types internally in the current binary image, avoiding +unnecessarily embedding redundant copies of type manglings, and +"pointing" to a mangled string for external type references. This uses a +base-255 encoding to avoid nulls in the sequence of bytes. + +The offset value is relative to the address of the offset itself so that +a base address doesn't need to be threaded when parsing bytes. + +For external references to types defined in other images, the relative +offset takes you to the mangled name string for symbol lookup. + +`Count`, `Index`, and `Depth` tokens are encoded this way as well. + +### Flags + +The flags of the field record is a 32-bit unsigned integer marking some +statically known facts about the field's type, such as reference ownership. + +#### Flag bits + +TODO diff --git a/docs/archive/LangRef.html b/docs/archive/LangRef.html index 2ec564d90c9dd..5ee53490e7106 100644 --- a/docs/archive/LangRef.html +++ b/docs/archive/LangRef.html @@ -762,7 +762,7 @@

Infix Attributes

FIXME: Implement these restrictions.

-

Resilience Attribute

+

Resilience Attribute

     attribute-resilience ::= 'resilient'
@@ -1093,7 +1093,7 @@ 

Function Types

The result type of a function type must be materializable. The argument type of a - function is always required to be parenthesized (a tuple). The behavior + function is always required to be parenthesized (a tuple). The behavior of function types may be modified with the autoclosure attribute.

@@ -1901,7 +1901,7 @@

Closure Expression

// both have type 'Int'. magic(42, { $0 < $1 }) - // Compare the other way way. + // Compare the other way. magic(42, { $1 < $0 }) // Provide parameter names, but infer the types. diff --git a/docs/archive/LangRefNew.rst b/docs/archive/LangRefNew.rst index 3355e66d19c23..a22b50e2d6075 100644 --- a/docs/archive/LangRefNew.rst +++ b/docs/archive/LangRefNew.rst @@ -1123,7 +1123,7 @@ label if it is a named pattern or a type annotation of a named pattern. A tuple pattern whose body ends in ``'...'`` is a varargs tuple. The last element of such a tuple must be a typed pattern, and the type of that pattern -is changed from ``T`` to ``T[]``. The corresponding tuple type for a varargs +is changed from ``T`` to ``[T]``. The corresponding tuple type for a varargs tuple is a varargs tuple type. As a special case, a tuple pattern with one element that has no label, has no @@ -1150,7 +1150,7 @@ appear in declarations. class D1 : B {} class D2 : B {} - var bs : B[] = [B(), D1(), D2()] + var bs : [B] = [B(), D1(), D2()] for b in bs { switch b { @@ -1537,8 +1537,8 @@ Short Circuiting Logical Operators :: - func && (lhs: Bool, rhs: ()->Bool) -> Bool - func || (lhs: Bool, rhs: ()->Bool) -> Bool + func && (lhs: Bool, rhs: () -> Bool) -> Bool + func || (lhs: Bool, rhs: () -> Bool) -> Bool Swift has a simplified precedence levels when compared with C. From highest to lowest: diff --git a/docs/archive/Resilience.rst b/docs/archive/Resilience.rst index 84ec5f6d8ec19..e6112d0f6f9b1 100644 --- a/docs/archive/Resilience.rst +++ b/docs/archive/Resilience.rst @@ -42,7 +42,7 @@ program may depend on some number of other components; this graph of dependencies can be assumed to be acyclic. Because a component is distributed as a unit, ABI resilience within the -component is not required. It may still help to serve as a build- time +component is not required. It may still help to serve as a build-time optimization, but Swift aims to offer substantially better build times than C/C++ programs due to other properties of the language (the module system, the lack of a preprocessor, the instantiation model, etc.). @@ -254,7 +254,7 @@ versioned [fragile] attribute. There is also a [resilient] attribute, exclusive to any form of [fragile], to explicitly describe a declaration as resilient. Resilience is lexically inherited. It is not lexically constrained; a resilient -language structure may have fragile sub-structures and vice- versa. The global +language structure may have fragile sub-structures and vice-versa. The global context is resilient, although since it is also [public] (and not [api]), objects are not in practice constrained by resilience. @@ -351,7 +351,7 @@ change a Resilience affects pretty much every language feature. Execution-time abstraction does not come without cost, and we do not wish to -incur those costs where unnecessary. Many forms of execution- time abstraction +incur those costs where unnecessary. Many forms of execution-time abstraction are unnecessary except as a build-time optimization, because in practice the software is deployed in large chunks that can be compiled at the same time. Within such a resilience unit , many execution-time abstractions can be @@ -364,7 +364,7 @@ outside its resilience unit. A structure is said to be resilient if accesses to it rely only on its -A structure is said to be universally non-resilient if it is non- resilient in +A structure is said to be universally non-resilient if it is non-resilient in all contexts in which it is accessible. Many APIs are willing to selectively "lock down" some of their component @@ -405,8 +405,8 @@ non-resilient. Named types declared within a function are universally non-resilient. -Named types with the [unchanging] annotation are universally non- -resilient. Problem, because of the need/desire to make things depend on whether +Named types with the [unchanging] annotation are universally non-resilient. +Problem, because of the need/desire to make things depend on whether a type is universally non-resilient. Makes it impossible to add [unchanging] without breaking ABI. See the call section. @@ -433,9 +433,9 @@ Named types It is an error to place the [unchanging] annotation on any of these types: -* a struct type with member types that are not universally non- resilient +* a struct type with member types that are not universally non-resilient -* an enum type with an enumerator whose type is not universally non- resilient +* an enum type with an enumerator whose type is not universally non-resilient * a class extension @@ -450,8 +450,8 @@ It is an error to place the [unchanging] annotation on a class extension. It is an error to place the [unchanging] annotation on a class whose primary definition contains a field whose type is potentially resilient in a context where the class is accessible. That is, if the class is exported, all of its -fields must be universally non- resilient. If it is not exported, all of its -fields must be non- resilient within its resilience unit. +fields must be universally non-resilient. If it is not exported, all of its +fields must be non-resilient within its resilience unit. It is allowed to add fields to an [unchanging] class in a class extension. Such fields are always side-stored, even if they are declared within the same diff --git a/docs/conf.py b/docs/conf.py index 0af7b9a7c9384..58da546ef97d5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,7 +10,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -47,9 +47,9 @@ # built documents. # # The short X.Y version. -version = '2.2' +version = '3.0' # The full version, including alpha/beta/rc tags. -release = '2.2' +release = '3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -100,10 +100,10 @@ # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - # Red links are a bit too garish - "linkcolor" : "#577492", - "visitedlinkcolor" : "#577492", - "hoverlinkcolor" : "#551A8B" + # Red links are a bit too garish + "linkcolor": "#577492", + "visitedlinkcolor": "#577492", + "hoverlinkcolor": "#551A8B" } # Add any paths that contain custom themes here, relative to this directory. @@ -178,21 +178,21 @@ # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('contents', 'Swift.tex', u'Swift Documentation', - u'LLVM project', 'manual'), + ('contents', 'Swift.tex', u'Swift Documentation', + u'LLVM project', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -235,9 +235,9 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('contents', 'Swift', u'Swift Documentation', - u'LLVM project', 'Swift', 'One line description of project.', - 'Miscellaneous'), + ('contents', 'Swift', u'Swift Documentation', + u'LLVM project', 'Swift', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in index e9c3a6415fa23..6b56723b5d5f1 100644 --- a/docs/doxygen.cfg.in +++ b/docs/doxygen.cfg.in @@ -1063,7 +1063,7 @@ PERL_PATH = #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# generate an inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more @@ -1239,7 +1239,7 @@ SEARCHENGINE = @enable_searchengine@ # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows -# full text search. The disadvances is that it is more difficult to setup +# full text search. The disadvantage is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = @enable_server_based_search@ diff --git a/docs/doxygen.intro b/docs/doxygen.intro index 8d953655bc6ab..f1ff0682a5829 100644 --- a/docs/doxygen.intro +++ b/docs/doxygen.intro @@ -4,7 +4,7 @@ /// Welcome to Swift. /// /// This documentation describes the @b internal software that makes -/// up Swift, not the @b external use of Swift. There are no instructions +/// up Swift, not the @b external use of Swift. There are no instructions /// here on how to use Swift, only the APIs that make up the software. For usage /// instructions, please see the programmer's guide or reference manual. /// diff --git a/docs/proposals/Accessors.rst b/docs/proposals/Accessors.rst index f22b8c7c1f8d1..da5da10f0426b 100644 --- a/docs/proposals/Accessors.rst +++ b/docs/proposals/Accessors.rst @@ -704,7 +704,7 @@ that was technically copied beforehand. For example:: var oldArray : [Int] = [] // This function copies array before modifying it, but because that - // copy is of an value undergoing modification, the copy will use + // copy is of a value undergoing modification, the copy will use // the same buffer and therefore observe updates to the element. func foo(inout element: Int) { oldArray = array diff --git a/docs/proposals/ArrayBridge.rst b/docs/proposals/ArrayBridge.rst index a3bc33009952c..8f1c56f9c8c06 100644 --- a/docs/proposals/ArrayBridge.rst +++ b/docs/proposals/ArrayBridge.rst @@ -4,7 +4,7 @@ .. .. This source file is part of the Swift.org open source project .. -.. Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +.. Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors .. Licensed under Apache License v2.0 with Runtime Library Exception .. .. See http://swift.org/LICENSE.txt for license information @@ -34,11 +34,11 @@ Being "great for Cocoa" means this must work and be efficient:: var a = [cocoaObject1, cocoaObject2] someCocoaObject.takesAnNSArray(a) - func processViews(views: AnyObject[]) { ... } + func processViews(views: [AnyObject]) { ... } var b = someNSWindow.views // views is an NSArray processViews(b) - var c: AnyObject[] = someNSWindow.views + var c: [AnyObject] = someNSWindow.views Being "great For C" means that an array created in Swift must have C-like performance and be representable as a base pointer and @@ -47,18 +47,18 @@ length, for interaction with C APIs, at zero cost. Proposed Solution ================= -``Array``, a.k.a. ``T[]``, is notionally an ``enum`` with two +``Array``, a.k.a. ``[T]``, is notionally an ``enum`` with two cases; call them ``Native`` and ``Cocoa``. The ``Native`` case stores a ``ContiguousArray``, which has a known, contiguous buffer representation and O(1) access to the address of any element. The ``Cocoa`` case stores an ``NSArray``. ``NSArray`` bridges bidirectionally in O(1) [#copy]_ to -``AnyObject[]``. It also implicitly converts in to ``T[]``, where T +``[AnyObject]``. It also implicitly converts in to ``[T]``, where T is any class declared to be ``@objc``. No dynamic check of element types is ever performed for arrays of ``@objc`` elements; instead we simply let ``objc_msgSend`` fail when ``T``\ 's API turns out to be -unsupported by the object. Any ``T[]``, where T is an ``@objc`` +unsupported by the object. Any ``[T]``, where T is an ``@objc`` class, converts implicitly to NSArray. Optimization @@ -92,7 +92,7 @@ fold this to "0" iff ``T`` is known to be a protocol other than AnyObject, if it is known to be a non-\ ``@objc`` class, or if it is known to be any struct, enum or tuple. Otherwise, the builtin is left alone, and if it reaches IRGen, IRGen should conservatively fold it to -"1". In the common case where ``Array`` is inlined and +"1". In the common case where ``Array`` is inlined and specialized, this will allow us to eliminate all of the overhead in the important C cases. @@ -114,7 +114,7 @@ We considered an approach where conversions between ``NSArray`` and native Swift ``Array`` were entirely manual and quickly ruled it out as failing to satisfy the requirements. -We considered another promising proposal that would make ``T[]`` a +We considered another promising proposal that would make ``[T]`` a (hand-rolled) existential wrapper type. Among other things, we felt this approach would expose multiple array types too prominently and would tend to "bless" an inappropriately-specific protocol as the diff --git a/docs/proposals/C Pointer Argument Interop.rst b/docs/proposals/C Pointer Argument Interop.rst index 0be9dd9f19cbf..1d5823690272d 100644 --- a/docs/proposals/C Pointer Argument Interop.rst +++ b/docs/proposals/C Pointer Argument Interop.rst @@ -141,7 +141,7 @@ known, so a copy-on-write array buffer must be eagerly uniqued prior to the address of the array being taken:: func loadFloatsFromData(data: NSData) { - var a: Float[] = [0.0, 0.0, 0.0, 0.0] + var a: [Float] = [0.0, 0.0, 0.0, 0.0] var b = a // Should only mutate 'b' without affecting 'a', so its backing store diff --git a/docs/proposals/C Pointer Interop Language Model.rst b/docs/proposals/C Pointer Interop Language Model.rst index aa51aef2b0d89..2620a36247788 100644 --- a/docs/proposals/C Pointer Interop Language Model.rst +++ b/docs/proposals/C Pointer Interop Language Model.rst @@ -72,7 +72,7 @@ You can call it as any of:: var x: Float = 0.0 var p: UnsafeMutablePointer = nil - var a: Float[] = [1.0, 2.0, 3.0] + var a: [Float] = [1.0, 2.0, 3.0] foo(nil) foo(p) foo(&x) @@ -86,7 +86,7 @@ You can call it as any of:: var x: Float = 0.0, y: Int = 0 var p: UnsafeMutablePointer = nil, q: UnsafeMutablePointer = nil - var a: Float[] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3] + var a: [Float] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3] bar(nil) bar(p) bar(q) diff --git a/docs/proposals/DeclarationTypeChecker.rst b/docs/proposals/DeclarationTypeChecker.rst index 6195f87e438c4..1872da6f5fd25 100644 --- a/docs/proposals/DeclarationTypeChecker.rst +++ b/docs/proposals/DeclarationTypeChecker.rst @@ -68,7 +68,7 @@ There are a few aspects of the language that make it challenging to implement th extension C { } extension B { struct Inner { } } -Here, the name lookup used for the first extension needs to resolve the typealias, which depends on the second extension having already been bound. There is a similar dependency on resolving superclasses beforing binding extensions:: +Here, the name lookup used for the first extension needs to resolve the typealias, which depends on the second extension having already been bound. There is a similar dependency on resolving superclasses before binding extensions:: class X { struct Inner { } } class Y : X { } @@ -154,7 +154,7 @@ The proposed architecture is significantly different from the current type check **Make name lookup phase-aware**: Name lookup is currently one of the worst offenders when violating phase ordering. Parameterize name lookup based on the phase at which it's operating. For example, asking for name lookup at the "extension binding" phase might not resolve type aliases, look into superclasses, or look into protocols. -**Make type resolution phase-aware**: Type resolution effectively brings a given ``TypeRepr`` up to the "declaration type validation`` phase in one shot. Parameterize type resolution based on the target phase, and start minimizing the among of work that the type checking does. Use extension binding as a testbed for these more-minimal dependencies. +**Make type resolution phase-aware**: Type resolution effectively brings a given ``TypeRepr`` up to the "declaration type validation`` phase in one shot. Parameterize type resolution based on the target phase, and start minimizing the amount of work that the type checking does. Use extension binding as a testbed for these more-minimal dependencies. **Dependency graph and priority queue**: Extend the current-phase trait with an operation that enumerates the dependencies that need to be satisfied to bring a given AST node up to a particular phase. Start with ``TypeRepr`` nodes, and use the dependency graph and priority queue to satisfy all dependencies ahead of time, eliminating direct recursion from the type-resolution code path. Build circular-dependency detection within this test-bed. @@ -165,7 +165,7 @@ The proposed architecture is significantly different from the current type check How do we test it? ~~~~~~~~~~~~~~~~~~ -**Existing code continues to work**: As we move various parts of the type checker over to the dependency graph, existing Swift code should continue to work, since we'll have fallbacks to the existing logic and the new type checker should be strictly more lazy than the existing type checker. +**Existing code continues to work**: As we move various parts of the type checker over to the dependency graph, existing Swift code should continue to work, since we'll have fallbacks to the existing logic and the new type checker should be strictly lazier than the existing type checker. **Order-independence testing**: One of the intended improvements from this type checker architecture is that we should get more predictable order-independent behavior. To check this, we can randomly scramble the order in which we type-check declarations in the primary source file of a well-formed module and verify that we get the same results. @@ -180,4 +180,4 @@ The proposed change is a major architectural shift, and it's only complete when **Accessors that check the current phase**: When we're finished, each of the AST's accessors should assert that the AST node is in the appropriate phase. The number of such assertions that have been enabled is an indication of how well the type checker is respecting the dependencies. -**Phases of AST nodes in non-primary files**: With the current type checker, every AST node in a non-primary file that gets touched when type-checking the primary file will end up being fully validated (currently, the "attribute checking" phase). As the type checker gets more lazy, the AST nodes in non-primary files will trend toward earlier phases. Tracking the number of nodes in non-primary files at each phase over time will help us establish how lazy the type checker is becoming. +**Phases of AST nodes in non-primary files**: With the current type checker, every AST node in a non-primary file that gets touched when type-checking the primary file will end up being fully validated (currently, the "attribute checking" phase). As the type checker gets lazier, the AST nodes in non-primary files will trend toward earlier phases. Tracking the number of nodes in non-primary files at each phase over time will help us establish how lazy the type checker is becoming. diff --git a/docs/proposals/Enums.rst b/docs/proposals/Enums.rst index 46402160b1a1f..607596bd4d9b6 100644 --- a/docs/proposals/Enums.rst +++ b/docs/proposals/Enums.rst @@ -281,7 +281,7 @@ circumstances: StringLiteralConvertible. - None of the cases of the enum may have non-void payloads. -If an enum declares an raw type, then its cases may declare raw +If an enum declares a raw type, then its cases may declare raw values. raw values must be integer, float, character, or string literals, and must be unique within the enum. If the raw type is IntegerLiteralConvertible, then the raw values default to diff --git a/docs/proposals/InitializerInheritance.rst b/docs/proposals/InitializerInheritance.rst index 688c0f36b34b6..8e833d72c85e6 100644 --- a/docs/proposals/InitializerInheritance.rst +++ b/docs/proposals/InitializerInheritance.rst @@ -50,16 +50,16 @@ We can also distinguish two ways to originally invoke an initializer: Either kind of dispatched initialization poses a soundness problem because there may not be a sound initializer with any given signature in the most-derived class. In ObjC, initializers are normal instance -methods and are therefore inherited like normal, but this isn’t really +methods and are therefore inherited like normal, but this isn't really quite right; initialization is different from a normal method in that -it’s not inherently sensible to require subclasses to provide +it's not inherently sensible to require subclasses to provide initializers at all the signatures that their superclasses provide. Subobject initializers ~~~~~~~~~~~~~~~~~~~~~~ The defining class of a subobject initializer is central to its behavior. It can be soundly inherited by a class C only if is trivial -to initialize the ivars of C, but it’s convenient to ignore that and +to initialize the ivars of C, but it's convenient to ignore that and assume that subobjects will always trivially wrap and delegate to superclass subobject initializers. @@ -75,7 +75,7 @@ initializer of a class C if and only if it is defined by C. Complete object initializers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The defining class of a complete object initializer doesn’t really +The defining class of a complete object initializer doesn't really matter. In principle, complete object initializers could just as well be freestanding functions to which a metatype is passed. It can make sense to inherit a complete object initializer. @@ -90,11 +90,11 @@ A complete object initializer soundly acts like a complete object initializer of a class C if and only if it delegates to an initializer which soundly acts like a complete object initializer of C. -These rules are not obvious to check statically because they’re +These rules are not obvious to check statically because they're dependent on the dynamic value of the most-derived class C. Therefore any ability to check them depends on restricting C somehow relative to the defining class of the initializer. Since, statically, we only -know the defining class of the initializer, we can’t establish +know the defining class of the initializer, we can't establish soundness solely at the definition site; instead we have to prevent unsound initializers from being called. @@ -116,7 +116,7 @@ Virtual initializers The above condition is not sufficient to make indirect initialization sound, because it relies on the ability to simply not use an initializer in cases where its delegation behavior isn't known to be -sound, and we can’t do that to arbitrary code. For that, we would +sound, and we can't do that to arbitrary code. For that, we would need true virtual initializers. A virtual initializer is a contract much more like that of a standard @@ -378,7 +378,7 @@ a trivial ``NSDocument``:: In Swift, there would be no way to create an object of type ``MyDocument``. However, the frameworks will allocate an instance of -``MyDocument`` and then send an message such as +``MyDocument`` and then send a message such as ``initWithContentsOfURL:ofType:error:`` to the object. This will find ``-[NSDocument initWithContentsOfURL:ofType:error:]``, which delegates to ``-[NSDocument init]``, leaving ``MyDocument``'s stored properties diff --git a/docs/proposals/InoutCOWOptimization.rst b/docs/proposals/InoutCOWOptimization.rst index cc88b59e77ffc..c784fda253786 100644 --- a/docs/proposals/InoutCOWOptimization.rst +++ b/docs/proposals/InoutCOWOptimization.rst @@ -25,8 +25,8 @@ The problem is caused as follows: x[0].mutate() - we “``subscript get``” ``x[0]`` into a temporary, mutate the - temporary, and “``subscript set``” it back into ``x[0]``. + we "``subscript get``" ``x[0]`` into a temporary, mutate the + temporary, and "``subscript set``" it back into ``x[0]``. * When the element itself is a COW type, that temporary implies a retain count of at least 2 on the element's buffer. @@ -51,7 +51,7 @@ could be written as follows: protocol Sliceable { ... @mutating - func quickSort(compare: (StreamType.Element, StreamType.Element)->Bool) { + func quickSort(compare: (StreamType.Element, StreamType.Element) -> Bool) { let (start,end) = (startIndex, endIndex) if start != end && start.succ() != end { let pivot = self[start] diff --git a/docs/proposals/Inplace.rst b/docs/proposals/Inplace.rst index 95d31e1623fc4..d2225fad20bf5 100644 --- a/docs/proposals/Inplace.rst +++ b/docs/proposals/Inplace.rst @@ -23,12 +23,12 @@ In recent standard library design meetings about the proper API for sets, it was decided that the canonical ``Set`` interface should be written in terms of methods: [#operators]_ :: - struct Set { - public func contains(x: T) -> Bool // x ∈ A, A ∋ x - public func isSubsetOf(b: Set) -> Bool // A ⊆ B - public func isStrictSubsetOf(b: Set) -> Bool // A ⊂ B - public func isSupersetOf(b: Set) -> Bool // A ⊇ B - public func isStrictSupersetOf(b: Set) -> Bool // A ⊃ B + struct Set { + public func contains(x: Element) -> Bool // x ∈ A, A ∋ x + public func isSubsetOf(b: Set) -> Bool // A ⊆ B + public func isStrictSubsetOf(b: Set) -> Bool // A ⊂ B + public func isSupersetOf(b: Set) -> Bool // A ⊇ B + public func isStrictSupersetOf(b: Set) -> Bool // A ⊃ B ... } @@ -36,17 +36,17 @@ When we started to look at the specifics, however, we ran into a familiar pattern:: ... - public func union(b: Set) -> Set // A ∪ B - public mutating func unionInPlace(b: Set) // A ∪= B + public func union(b: Set) -> Set // A ∪ B + public mutating func unionInPlace(b: Set) // A ∪= B - public func intersect(b: Set) -> Set // A ∩ B - public mutating func intersectInPlace(b: Set) // A ∩= B + public func intersect(b: Set) -> Set // A ∩ B + public mutating func intersectInPlace(b: Set) // A ∩= B - public func subtract(b: Set) -> Set // A - B - public mutating func subtractInPlace(b: Set) // A -= B + public func subtract(b: Set) -> Set // A - B + public mutating func subtractInPlace(b: Set) // A -= B - public func exclusiveOr(b: Set) -> Set // A ⊕ B - public mutating func exclusiveOrInPlace(b: Set) // A ⊕= B + public func exclusiveOr(b: Set) -> Set // A ⊕ B + public mutating func exclusiveOrInPlace(b: Set) // A ⊕= B We had seen the same pattern when considering the API for ``String``, but in that case, there are no obvious operator @@ -310,7 +310,7 @@ as though it were written: .. parsed-literal:: { - (var y: X)->X in + (var y: X) -> X in y\ **.=**\ *f*\ (a₀, p₁: a₁, p₂: a₂, …p\ *n*: a\ *n*) return y }(x) @@ -344,7 +344,7 @@ as though it were written: .. parsed-literal:: { - (var y: X)->X in + (var y: X) -> X in y *op*\ **=**\ *expression* return y }(x) @@ -424,7 +424,7 @@ fine:: foo.=advanced(10) The alternative would be to say that explicitly-written assignment methods -cannot work properly for immutable classes and “work” with reference +cannot work properly for immutable classes and "work" with reference semantics on other classes. We consider this approach indefensible, especially when one considers that operators encourage writing algorithms that can only work properly with value semantics and will diff --git a/docs/proposals/OptimizerEffects.rst b/docs/proposals/OptimizerEffects.rst index 1dafd11e9ca4a..c22b626cf8b18 100644 --- a/docs/proposals/OptimizerEffects.rst +++ b/docs/proposals/OptimizerEffects.rst @@ -482,7 +482,7 @@ destructor can have arbitrary side-effects. Therefore, it is not valid to hoist the makeUnique in the code without proving that 'T's destructor cannot change the uniqueness state. This is trivial for trivial types but requires a more sophisticated analysis for class types (and in general cannot be disproved). In -following example we can only hoist makeUnique if we can prove that elt's, and +following example we can only hoist makeUnique if we can prove that elt's, and elt2's destructor can't change the uniqueness state of the arrays.:: for i in 0 ..< min(a.size, b.size) { @@ -795,7 +795,7 @@ Store (1) and load (2) do not alias and (3) is defined as ``readnone``. So (1) could be moved over (3). Currently inlining is prevented in high-level SIL for all functions which -have an semantics or effect attribute. Therefore we could say that the +have a semantics or effect attribute. Therefore we could say that the implementor of a pure value type has to define effects on all member functions which eventually can access or modify the storage. diff --git a/docs/proposals/ValueSemantics.rst b/docs/proposals/ValueSemantics.rst index 3541d407e0a09..c48dd11fb50bc 100644 --- a/docs/proposals/ValueSemantics.rst +++ b/docs/proposals/ValueSemantics.rst @@ -25,7 +25,7 @@ Value Semantics --------------- For a type with value semantics, variable initialization, assignment, -and argument-passing (hereafter, “the big three operations”) each +and argument-passing (hereafter, "the big three operations") each create an *independently modifiable copy* of the source value that is *interchangeable with the source*. [#interchange]_ @@ -151,13 +151,13 @@ The Problem With Generics The classic Liskov principle says the semantics of operations on ``Duck``\ 's subtypes need to be consistent with those on ``Duck`` itself, -so that functions operating on ``Duck``\ s still “work” when passed a +so that functions operating on ``Duck``\ s still "work" when passed a ``Mallard``. More generally, for a function to make meaningful guarantees, the semantics of its sub-operations need to be consistent regardless of the actual argument types passed. The type of an argument passed by-value to an ordinary function is -fully constrained, so the “big three” have knowable semantics. The +fully constrained, so the "big three" have knowable semantics. The type of an ordinary argument passed by-reference is constrained by subtype polymorphism, where a (usually implicit) contract between base- and sub-types can dictate consistency. @@ -175,11 +175,11 @@ pseudo-random number generator). It needs to make one copy and do in-place mutation of the state, rather than wholesale value replacement via assignment, which might be expensive. -Here’s a version of cycle_length that works when state is a mutable +Here's a version of cycle_length that works when state is a mutable value type:: func cycle_length( - s : State, mutate : ( [inout] State )->() + s : State, mutate : ( [inout] State ) -> () ) -> Int requires State : EqualityComparable { @@ -196,7 +196,7 @@ value type:: The reason the above breaks when the state is in a class instance is that the intended copy in line 1 instead creates a new reference to the same state, and the comparison in line 2 (regardless of whether we -decide ``!=`` does “identity” or “value” comparison) always succeeds. +decide ``!=`` does "identity" or "value" comparison) always succeeds. You can write a different implementation that only works on clonable classes: @@ -211,7 +211,7 @@ classes: } func cycle_length( - s : State, mutate : ( [inout] State )->() + s : State, mutate : ( [inout] State ) -> () ) -> Int requires State : EqualityComparable, **Clonable** { @@ -233,8 +233,8 @@ clonable classes: func cycle_length( s : State, - **next : (x : State)->State,** - **equal : ([inout] x : State, [inout] y : State)->Bool** + **next : (x : State) -> State,** + **equal : ([inout] x : State, [inout] y : State) -> Bool** ) -> Int requires State : EqualityComparable { diff --git a/docs/proposals/archive/Memory and Concurrency Model.rst b/docs/proposals/archive/Memory and Concurrency Model.rst index 82dc4bd50d986..5a5fa6f95c58f 100644 --- a/docs/proposals/archive/Memory and Concurrency Model.rst +++ b/docs/proposals/archive/Memory and Concurrency Model.rst @@ -48,7 +48,7 @@ Swift. Given a static type, it is obvious what kind it is from its definition. These kinds are: 1. **Immutable Data** - Immutable data (which can have a constructor, but whose - value cannot be changed after it completes) is sharable across actors, and it + value cannot be changed after it completes) is shareable across actors, and it would make sense to unique them where possible. Immutable data can (transitively) point to other immutable data, but it isn't valid (and the compiler rejects) immutable data that is pointing to mutable data. For @@ -322,7 +322,7 @@ covered by this model at all. For example, having multiple threads execute on different slices of the same array would require copying the array to temporary disjoint memory spaces to do operations, then recopy it back into place. This data copying can be awkward and reduce the benefits of parallelism to make it -non- profitable. +non-profitable. There are multiple different ways to tackle this. We can just throw it back into the programmer's lap and tell them that the behavior is undefined if they get a diff --git a/docs/proposals/archive/ProgramStructureAndCompilationModel.rst b/docs/proposals/archive/ProgramStructureAndCompilationModel.rst index dd21306bbfd99..c659f44ea875d 100644 --- a/docs/proposals/archive/ProgramStructureAndCompilationModel.rst +++ b/docs/proposals/archive/ProgramStructureAndCompilationModel.rst @@ -57,7 +57,7 @@ world. In the trivial hello world example, the source file gets implicitly dropped into a default component (since it doesn't have a component declaration). The default component has settings that corresponds to an executable. As the app grows and -wants to start using sub- libraries, the author would have to know about +wants to start using sub-libraries, the author would have to know about components. This ensures a simple model for new people, because they don't need to know anything about components until they want to define a library and stable APIs. @@ -132,7 +132,7 @@ Components can optionally be broken into a set of "**Subcomponents**", which are organizational units within a top-level component. Subcomponents exist to support extremely large components that have multiple different teams contributing to a single large product. Subcomponents are purely an -implementation detail of top- level components and have no runtime, +implementation detail of top-level components and have no runtime, naming/namespace, or other externally visible artifacts that persist once the entire domain is built. If version 1.0 of a domain is shipped, version 1.1 can completely reshuffle the internal subcomponent organization without affecting @@ -275,7 +275,7 @@ diagnosed here. If this directory is a subcomponent (as opposed to a top-level component), the subcomponent declaration has already been read. If this subcomponent depends on -any other components that are not up-to- date, those are recursively +any other components that are not up-to-date, those are recursively rebuilt. Explicit subcomponent dependencies are acyclic and cycles are diagnosed here. Now all depended-on top-level components and subcomponents are built. @@ -306,7 +306,7 @@ declared cyclic dependencies match the given and actual prototype. 2) resources are copied or processed into the product directory. 3) the explicit dependence graph is verified, extraneous edges are warned about, missing edges are errors. -In terms of implementation, this should be relatively straight- forward, and is +In terms of implementation, this should be relatively straight-forward, and is carefully layered to be memory efficient (e.g. only processing an SCC at a time instead of an entire component) as well as highly parallel for multicore machines. For incremental builds, we will have a huge win because the @@ -330,7 +330,7 @@ client builds against the component to type check the client and ensure that its references are resolved. Because we have the version number as well as the full interface to the -component available in a consumable format is that we can build a SDK generation +component available in a consumable format is that we can build an SDK generation tool. This tool would take manifest files for a set of releases (e.g. iOS 4.0, 4.0.1, 4.0.2, 4.1, 4.1.1, 4.2) and build a single SDK manifest which would have a mapping from symbol+type -> version list that indicates what the versions a diff --git a/docs/proposals/containers_value_type.html b/docs/proposals/containers_value_type.html index ff7855e29e464..c64d60c53cf5f 100644 --- a/docs/proposals/containers_value_type.html +++ b/docs/proposals/containers_value_type.html @@ -231,7 +231,7 @@

those used in Cocoa. Now there is absolutely nothing wrong with high quality, strictly followed naming conventions. But they aren't checked by the compiler. Having the compiler be able to confirm: yes, this -argument can be modified / no, that argument can not be modified; is a +argument can be modified / no, that argument cannot be modified; is a tremendous productivity booster.

@@ -482,7 +482,7 @@

Summary

more easily spot the few cases where this is desired.

    -
  • Swift can not provide such protection for types with reference semantics.
  • +
  • Swift cannot provide such protection for types with reference semantics.
diff --git a/docs/proposals/rejected/Bridging Container Protocols to Class Clusters.rst b/docs/proposals/rejected/Bridging Container Protocols to Class Clusters.rst index cbef36e587f2d..f80400d1b6fc4 100644 --- a/docs/proposals/rejected/Bridging Container Protocols to Class Clusters.rst +++ b/docs/proposals/rejected/Bridging Container Protocols to Class Clusters.rst @@ -24,7 +24,7 @@ Here's what I propose instead: Although I'll be talking about arrays in this proposal, I think the same approach would work for ``NSDictionary`` and ``NSSet`` as well, mapping them -to generic containers for associative map and and unordered container protocols +to generic containers for associative map and unordered container protocols respectively. NSArray vs Array diff --git a/docs/proposals/rejected/ClassConstruction.rst b/docs/proposals/rejected/ClassConstruction.rst index 74452b7a1da9f..5b1ea48747c5d 100644 --- a/docs/proposals/rejected/ClassConstruction.rst +++ b/docs/proposals/rejected/ClassConstruction.rst @@ -7,7 +7,7 @@ .. warning:: This proposal was rejected, though it helped in the design of the final Swift 1 initialization model. -Objective-C's “designated initializers pattern seems at first to +Objective-C's "designated initializers pattern seems at first to create a great deal of complication. However, designated initializers are simply the only sane response to Objective-C's initialization rules, which are the root cause of the complication. @@ -116,9 +116,9 @@ Proposal ======== I suggest we define Swift initialization to be as simple and -easily-understood as possible, and avoid “interesting” interactions +easily-understood as possible, and avoid "interesting" interactions with the more complicated Objective-C initialization process. If we -do this, we can treat Objective-C base classes as “sealed and safe” +do this, we can treat Objective-C base classes as "sealed and safe" for the purpose of initialization, and help programmers reason effectively about initialization and their class invariants. @@ -133,7 +133,7 @@ Here are the proposed rules: Objective-C. * ``self.init(…)`` calls in Swift never dispatch virtually. We have a - safe model for “virtual initialization:” ``init`` methods can call + safe model for "virtual initialization:" ``init`` methods can call overridable methods after all instance variables and superclasses are initialized. Allowing *virtual* constructor delegation would undermine that safety. diff --git a/docs/proposals/rejected/Clonable.rst b/docs/proposals/rejected/Clonable.rst index 949ecf93cb883..39bf2c5d08a41 100644 --- a/docs/proposals/rejected/Clonable.rst +++ b/docs/proposals/rejected/Clonable.rst @@ -15,7 +15,7 @@ language-level copying mechanism for classes. **Abstract:** to better support the creation of value types, we -propose a “magic” ``Clonable`` protocol and an annotation for describing +propose a "magic" ``Clonable`` protocol and an annotation for describing which instance variables should be cloned when a type is copied. This proposal **augments revision 1** of the Clonable proposal with our rationale for dropping our support for ``val`` and ``ref``, a @@ -65,7 +65,7 @@ automatic, if we add that feature) forwarding. By dropping ``val`` we also lose some terseness aggregating ``class`` contents into ``struct``\ s. However, since ``ref`` is being dropped -there's less call for a symmetric ``val``. The extra “cruft” that +there's less call for a symmetric ``val``. The extra "cruft" that ``[clone]`` adds actually seems appropriate when viewed as a special bridge for ``class`` types, and less like a penalty against value types. @@ -125,7 +125,7 @@ variables marked ``[clone]``:: var somethingIJustReferTo : Bar } -When a ``Baz`` is copied by any of the “big three” operations (variable +When a ``Baz`` is copied by any of the "big three" operations (variable initialization, assignment, or function argument passing), even as part of a larger ``struct``, its ``[clone]`` member is ``clone()``\ d. Because ``Foo`` itself has a ``[clone]`` member, that is ``clone()``\ d diff --git a/docs/proposals/rejected/Constructors.rst b/docs/proposals/rejected/Constructors.rst index fc69a38f4b6ab..c88b9b7802571 100644 --- a/docs/proposals/rejected/Constructors.rst +++ b/docs/proposals/rejected/Constructors.rst @@ -461,11 +461,11 @@ zero-argument selector with no trailing colon, e.g.,:: maps to the selector ``initToMemory``. -This mapping is reversible: given a selector in the “init” family, -i.e., where the first word is “init”, we split the selector into its +This mapping is reversible: given a selector in the "init" family, +i.e., where the first word is "init", we split the selector into its various pieces at the colons: -* For the first piece, we remove the “init” and then lowercase the +* For the first piece, we remove the "init" and then lowercase the next character *unless* the second character is also uppercase. This becomes the name of the first parameter to the constructor. If this string is non-empty and the selector is a zero-argument selector diff --git a/docs/proposals/valref.rst b/docs/proposals/valref.rst index b2c9987ec7f65..7adbd9608778a 100644 --- a/docs/proposals/valref.rst +++ b/docs/proposals/valref.rst @@ -29,15 +29,15 @@ Introduction Until recently, Swift's support for value semantics outside trivial types like scalars and immutable strings has been weak. While the -recent ``Clonable`` proposal makes new things possible in the “safe” +recent ``Clonable`` proposal makes new things possible in the "safe" zone, it leaves the language syntactically and semantically lumpy, keeping interactions between value and reference types firmly outside -the “easy” zone and failing to address the issue of generic +the "easy" zone and failing to address the issue of generic programming. This proposal builds on the ``Clonable`` proposal to create a more uniform, flexible, and interoperable type system while solving the -generic programming problem and expanding the “easy” zone. +generic programming problem and expanding the "easy" zone. General Description =================== @@ -68,8 +68,8 @@ When applied to ``class`` types, "copy" means to call the ``clone()`` method, which is generated by the compiler when the user has explicitly declared conformance to the ``Clonable`` protocol. -When we refer to variables being “declared ``val``” or “declared -``ref``”, we mean to include the case of equivalent declarations using +When we refer to variables being "declared ``val``" or "declared +``ref``", we mean to include the case of equivalent declarations using ``var`` that request the default semantics for the type. Unless otherwise specified, we discuss implementation details such as @@ -178,8 +178,8 @@ Array elements can be explicitly declared ``val`` or ``ref``:: When a reference to an array appears without a variable name, it can be written using the `usual syntax`__:: - var f : ()->ref Int[42] // a closure returning a reference to an array - var b : ref Int[42] // equivalent to to "ref b : Int[42]" + var f : () -> ref Int[42] // a closure returning a reference to an array + var b : ref Int[42] // equivalent to "ref b : Int[42]" __ `standalone types`_ @@ -191,8 +191,8 @@ brackets, that most users will never touch, e.g.:: var z : Array // an array of 42 integers-on-the-heap var z : Array, 2> // an array of 2 references to arrays ref a : Array // a reference to an array of 42 integers - var f : ()->ref Array // a closure returning a reference to an array - var b : ref Array // equivalent to to "ref b : Int[42]" + var f : () -> ref Array // a closure returning a reference to an array + var b : ref Array // equivalent to "ref b : Int[42]" Rules for copying array elements follow those of instance variables. @@ -290,7 +290,7 @@ type parameter, as follows:: parameters:: // Fill an array with independent copies of x - func fill(array:T[], x:T) { + func fill(array:[T], x:T) { for i in 0...array.length { array[i] = x } @@ -425,7 +425,7 @@ How This Design Improves Swift matters. 4. We move the cases where values and references interact much closer - to, and arguably into, the “easy” zone. + to, and arguably into, the "easy" zone. How This Design Beats Rust/C++/C#/etc. ====================================== @@ -437,7 +437,7 @@ How This Design Beats Rust/C++/C#/etc. rooting`__, etc. By contrast, there's a path to learning swift that postpones the ``val``\ /``ref`` distinction, and that's pretty much *all* one must learn to have a complete understanding of the object - model in the “easy” and “safe” zones. + model in the "easy" and "safe" zones. __ http://static.rust-lang.org/doc/tutorial.html#boxes-and-pointers __ http://static.rust-lang.org/doc/tutorial-borrowed-ptr.html#named-lifetimes @@ -560,7 +560,7 @@ example: There's always the dreaded ``auto``. * Should we drop ``let``\ /``var``\ /``auto`` for ivars, because it - “just feels wrong” there? + "just feels wrong" there? * ``ref`` is spelled like ``[inout]``, but they mean very different things @@ -569,7 +569,7 @@ example: ``[inout]``. * Should we spell ``[inout]`` differently? I think at a high level - it means something like “``[rebind]`` the name to a new value.” + it means something like "``[rebind]`` the name to a new value." * Do we want to consider replacing ``struct`` and/or ``class`` with new names such as ``valtype`` and ``reftype``? We don't love those diff --git a/docs/scripts/ns-html2rst b/docs/scripts/ns-html2rst index 004cf6f6d6a29..82d8d92d70a4d 100755 --- a/docs/scripts/ns-html2rst +++ b/docs/scripts/ns-html2rst @@ -1,49 +1,53 @@ #!/usr/bin/env python -import sys, re, subprocess +from __future__ import print_function + +import re +import subprocess +import sys def run(): if len(sys.argv) > 1: - print """ + print(""" ns-html2rst - Convert Cocoa HTML documentation into ReST usage: nshtml2rst < NSString.html > NSString.rst - """ - exit(0) + """) + sys.exit(0) html = sys.stdin.read() # Treat
(.*?)
', - r'
\1
', - html, flags=re.MULTILINE|re.DOTALL) + r'(.*?)', + r'
\1
', + html, flags=re.MULTILINE | re.DOTALL) # Strip all attributes from
...
containing class="..." # The resulting classes confound ReST html = re.sub( - r']*class=[^>]*>(.*?)
', - r'
\1
', - html, flags=re.MULTILINE|re.DOTALL) + r']*class=[^>]*>(.*?)', + r'
\1
', + html, flags=re.MULTILINE | re.DOTALL) # Remove links from ..., which doesn't have a rendering in ReST html = re.sub( - r'(.*?)]*?>(.*?)(.*?)', - r'\1\2\3', - html, flags=re.MULTILINE|re.DOTALL) + r'(.*?)]*?>(.*?)(.*?)', + r'\1\2\3', + html, flags=re.MULTILINE | re.DOTALL) # Let pandoc do most of the hard work p = subprocess.Popen( - args=['pandoc', '--reference-links', '-f', 'html', '-t', 'rst'] - , stdin=subprocess.PIPE - , stdout=subprocess.PIPE + args=['pandoc', '--reference-links', '-f', 'html', '-t', 'rst'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE ) - rst,stderr = p.communicate(html) + rst, stderr = p.communicate(html) # HACKETY HACK HACK: Our html documents apparently contain some # bogus heading level nesting. Just fix up the one we know about # so that ReST doesn't complain later. - rst = re.sub("(^|\n)('+)($|\n)", - lambda m: m.group(1) + len(m.group(2))*'^' +m.group(3), + rst = re.sub("(^|\n)('+)($|\n)", + lambda m: m.group(1) + len(m.group(2)) * '^' + m.group(3), rst, flags=re.MULTILINE) sys.stdout.write(rst) diff --git a/include/swift/ABI/Class.h b/include/swift/ABI/Class.h index 8a3807fef4e10..9b1c7ad858a56 100644 --- a/include/swift/ABI/Class.h +++ b/include/swift/ABI/Class.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/ABI/MetadataKind.def b/include/swift/ABI/MetadataKind.def index 9bef04dfd9c92..7747bd9def2e9 100644 --- a/include/swift/ABI/MetadataKind.def +++ b/include/swift/ABI/MetadataKind.def @@ -1,8 +1,8 @@ -//===--- MetadataKind.def --------------------------------------*- C++ -*--===// +//===--- MetadataKind.def ---------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 73ec6843095eb..21d833580cfe4 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,8 @@ #ifndef SWIFT_ABI_METADATAVALUES_H #define SWIFT_ABI_METADATAVALUES_H +#include "swift/AST/Ownership.h" + #include #include @@ -92,9 +94,57 @@ enum : unsigned { /// Number of words reserved in generic metadata patterns. NumGenericMetadataPrivateDataWords = 16, }; + +/// Records information about a type's fields. +struct FieldRecordFlags { +protected: + using int_type = unsigned; + int_type Data; + + enum : int_type { + InternalExternalMask = 0x00000001U, + InternalExternalShift = 0, + OwnershipMask = 0x00000006U, + OwnershipShift = 1, + }; + +public: + FieldRecordFlags() : Data(0) {} + + /// True if this field has a type defined in the same image + /// as the type that contains it. + constexpr bool isInternal() const { + return ((Data >> InternalExternalShift) & InternalExternalMask) == 0; + } + + /// True if this field has a type that is defined in another + /// image as the type that contains it. + constexpr bool isExternal() const { + return !isInternal(); + } + + /// Get the ownership semantics if the field has a reference type. + constexpr Ownership getOwnership() const { + return Ownership((Data >> OwnershipShift) & OwnershipMask); + } + + void setInternal(bool internal) { + if (internal) + Data &= ~InternalExternalMask; + else + Data |= InternalExternalMask; + } + + void setOwnership(Ownership ownership) { + Data &= ~OwnershipMask; + Data |= int_type(ownership) << OwnershipShift; + } + + int_type getValue() const { return Data; } +}; -/// Kinds of protocol conformance record. -enum class ProtocolConformanceTypeKind : unsigned { +/// Kinds of type metadata/protocol conformance records. +enum class TypeMetadataRecordKind : unsigned { /// The conformance is universal and might apply to any type. /// getDirectType() is nil. Universal, @@ -117,10 +167,10 @@ enum class ProtocolConformanceTypeKind : unsigned { /// and classes could be emitted as UniqueDirectType. UniqueIndirectClass, - /// The conformance is for a generic type. - /// getGenericPattern() points to the generic metadata pattern used to - /// form instances of the type. - UniqueGenericPattern, + /// The conformance is for a generic or resilient type. + /// getNominalTypeDescriptor() points to the nominal type descriptor shared + /// by all metadata instantiations of this type. + UniqueNominalTypeDescriptor, /// The conformance is for a nongeneric class type. /// getDirectType() points to the unique class object. @@ -130,7 +180,7 @@ enum class ProtocolConformanceTypeKind : unsigned { /// platforms, the class object always is the type metadata. UniqueDirectClass = 0xF, }; - + /// Kinds of reference to protocol conformance. enum class ProtocolConformanceReferenceKind : unsigned { /// A direct reference to a protocol witness table. @@ -139,32 +189,51 @@ enum class ProtocolConformanceReferenceKind : unsigned { /// table. WitnessTableAccessor, }; - -struct ProtocolConformanceFlags { -private: + +// Type metadata record discriminant +struct TypeMetadataRecordFlags { +protected: using int_type = unsigned; int_type Data; enum : int_type { TypeKindMask = 0x0000000FU, TypeKindShift = 0, - ConformanceKindMask = 0x00000010U, - ConformanceKindShift = 4, }; public: - constexpr ProtocolConformanceFlags() : Data(0) {} - constexpr ProtocolConformanceFlags(int_type Data) : Data(Data) {} + constexpr TypeMetadataRecordFlags() : Data(0) {} + constexpr TypeMetadataRecordFlags(int_type Data) : Data(Data) {} - constexpr ProtocolConformanceTypeKind getTypeKind() const { - return ProtocolConformanceTypeKind((Data >> TypeKindShift) & TypeKindMask); + constexpr TypeMetadataRecordKind getTypeKind() const { + return TypeMetadataRecordKind((Data >> TypeKindShift) & TypeKindMask); } + constexpr TypeMetadataRecordFlags withTypeKind( + TypeMetadataRecordKind ptk) const { + return TypeMetadataRecordFlags( + (Data & ~TypeKindMask) | (int_type(ptk) << TypeKindShift)); + } + + int_type getValue() const { return Data; } +}; + +// Protocol conformance discriminant +struct ProtocolConformanceFlags : public TypeMetadataRecordFlags { +private: + enum : int_type { + ConformanceKindMask = 0x00000010U, + ConformanceKindShift = 4, + }; + +public: + constexpr ProtocolConformanceFlags() : TypeMetadataRecordFlags(0) {} + constexpr ProtocolConformanceFlags(int_type Data) : TypeMetadataRecordFlags(Data) {} + constexpr ProtocolConformanceFlags withTypeKind( - ProtocolConformanceTypeKind ptk) const { + TypeMetadataRecordKind ptk) const { return ProtocolConformanceFlags( (Data & ~TypeKindMask) | (int_type(ptk) << TypeKindShift)); } - constexpr ProtocolConformanceReferenceKind getConformanceKind() const { return ProtocolConformanceReferenceKind((Data >> ConformanceKindShift) & ConformanceKindMask); @@ -174,8 +243,6 @@ struct ProtocolConformanceFlags { return ProtocolConformanceFlags( (Data & ~ConformanceKindMask) | (int_type(pck) << ConformanceKindShift)); } - - int_type getValue() const { return Data; } }; /// Flag that indicates whether an existential type is class-constrained or not. diff --git a/include/swift/ABI/System.h b/include/swift/ABI/System.h index f0214fd427b85..2ccb7bf149b6b 100644 --- a/include/swift/ABI/System.h +++ b/include/swift/ABI/System.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -93,4 +93,9 @@ #define SWIFT_ABI_ARM64_OBJC_RESERVED_BITS_MASK 0x8000000000000000ULL #define SWIFT_ABI_ARM64_OBJC_NUM_RESERVED_LOW_BITS 0 +/*********************************** powerpc64 ************************************/ + +// Heap objects are pointer-aligned, so the low three bits are unused. +#define SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK 0x0000000000000007ULL + #endif /* SWIFT_ABI_SYSTEM_H */ diff --git a/include/swift/AST/AST.h b/include/swift/AST/AST.h index b0b68744720da..283ceb1e7d7d4 100644 --- a/include/swift/AST/AST.h +++ b/include/swift/AST/AST.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,7 @@ #include "swift/AST/ExprHandle.h" #include "swift/AST/Initializer.h" #include "swift/AST/Module.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index d799e024e2734..b09bab0563ce7 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,6 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/Allocator.h" #include #include @@ -100,6 +99,26 @@ enum class AllocationArena { ConstraintSolver }; +/// Lists the set of "known" Foundation entities that are used in the +/// compiler. +/// +/// While the names of Foundation types aren't likely to change in +/// Objective-C, their mapping into Swift can. Therefore, when +/// referring to names of Foundation entities in Swift, use this enum +/// and \c ASTContext::getSwiftName or \c ASTContext::getSwiftId. +enum class KnownFoundationEntity { +#define FOUNDATION_ENTITY(Name) Name, +#include "swift/AST/KnownFoundationEntities.def" +}; + +/// Retrieve the Foundation entity kind for the given Objective-C +/// entity name. +Optional getKnownFoundationEntity(StringRef name); + +/// Determine with the non-prefixed name of the given known Foundation +/// entity conflicts with the Swift standard library. +bool nameConflictsWithStandardLibrary(KnownFoundationEntity entity); + /// Callback function used when referring to a type member of a given /// type variable. typedef std::function @@ -281,7 +300,7 @@ class ASTContext { template typename std::remove_reference::type *AllocateObjectCopy(T &&t, AllocationArena arena = AllocationArena::Permanent) const { - // This function can not be named AllocateCopy because it would always win + // This function cannot be named AllocateCopy because it would always win // overload resolution over the AllocateCopy(ArrayRef). using TNoRef = typename std::remove_reference::type; TNoRef *res = (TNoRef *) Allocate(sizeof(TNoRef), alignof(TNoRef), arena); @@ -487,7 +506,7 @@ class ASTContext { // Retrieve the declaration of Swift._stdlib_isOSVersionAtLeast. FuncDecl *getIsOSVersionAtLeastDecl(LazyResolver *resolver) const; - /// \brief Look for the declaration with the given name within the + /// Look for the declaration with the given name within the /// swift module. void lookupInSwiftModule(StringRef name, SmallVectorImpl &results) const; @@ -500,9 +519,10 @@ class ASTContext { Type type, LazyResolver *resolver) const; - /// \brief Notify all of the mutation listeners that the given declaration - /// was just added. - void addedExternalDecl(Decl *decl); + /// Add a declaration to a list of declarations that need to be emitted + /// as part of the current module or source file, but are otherwise not + /// nested within it. + void addExternalDecl(Decl *decl); /// Add a cleanup function to be called when the ASTContext is deallocated. void addCleanup(std::function cleanup); @@ -590,7 +610,7 @@ class ASTContext { /// one. void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration); - /// \brief Load the methods within the given class that that produce + /// \brief Load the methods within the given class that produce /// Objective-C class or instance methods with the given selector. /// /// \param classDecl The class in which we are searching for @objc methods. @@ -604,7 +624,7 @@ class ASTContext { /// /// \param previousGeneration The previous generation with which this /// callback was invoked. The list of methods will already contain all of - /// the results from generations up and and including \c previousGeneration. + /// the results from generations up and including \c previousGeneration. /// /// \param methods The list of @objc methods in this class that have this /// selector and are instance/class methods as requested. This list will be @@ -780,6 +800,16 @@ class ASTContext { /// protocols that conflict with methods. bool diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf); + /// Retrieve the Swift name for the given Foundation entity, where + /// "NS" prefix stripping will apply under omit-needless-words. + StringRef getSwiftName(KnownFoundationEntity kind); + + /// Retrieve the Swift identifier for the given Foundation entity, where + /// "NS" prefix stripping will apply under omit-needless-words. + Identifier getSwiftId(KnownFoundationEntity kind) { + return getIdentifier(getSwiftName(kind)); + } + /// Try to dump the context of the given archetype. void dumpArchetypeContext(ArchetypeType *archetype, unsigned indent = 0) const; @@ -791,7 +821,7 @@ class ASTContext { /// Collect visible clang modules from the ClangModuleLoader. These modules are /// not necessarily loaded. - void getVisibleTopLevelClangeModules(SmallVectorImpl &Modules) const; + void getVisibleTopLevelClangModules(SmallVectorImpl &Modules) const; /// Retrieve or create the stored archetype builder for the given /// canonical generic signature and module. diff --git a/include/swift/AST/ASTNode.h b/include/swift/AST/ASTNode.h index 2570d04a8a148..da20251935ddb 100644 --- a/include/swift/AST/ASTNode.h +++ b/include/swift/AST/ASTNode.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,7 +18,6 @@ #define SWIFT_AST_AST_NODE_H #include "llvm/ADT/PointerUnion.h" -#include "swift/AST/ASTWalker.h" #include "swift/AST/TypeAlignments.h" namespace swift { @@ -27,6 +26,7 @@ namespace swift { class Decl; class SourceLoc; class SourceRange; + class ASTWalker; struct ASTNode : public llvm::PointerUnion3 { // Inherit the constructors from PointerUnion. diff --git a/include/swift/AST/ASTPrinter.h b/include/swift/AST/ASTPrinter.h index e56eac35ae955..80ddd1ada7a3d 100644 --- a/include/swift/AST/ASTPrinter.h +++ b/include/swift/AST/ASTPrinter.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,10 +30,13 @@ namespace swift { /// Describes the context in which a name is being printed, which /// affects the keywords that need to be escaped. enum class PrintNameContext { - // Normal context + /// Normal context Normal, - // Generic parameter context, where 'Self' is not escaped. + /// Generic parameter context, where 'Self' is not escaped. GenericParameter, + /// Function parameter context, where keywords other than let/var/inout are + /// not escaped. + FunctionParameter, }; /// An abstract class used to print an AST. @@ -79,6 +82,8 @@ class ASTPrinter { ASTPrinter &operator<<(unsigned long long N); ASTPrinter &operator<<(UUID UU); + ASTPrinter &operator<<(DeclName name); + void printName(Identifier Name, PrintNameContext Context = PrintNameContext::Normal); @@ -102,7 +107,7 @@ class ASTPrinter { PendingDeclLocCallback = D; } - /// To sanitize a malformatted utf8 string to a well-formatted one. + /// To sanitize a malformed utf8 string to a well-formed one. static std::string sanitizeUtf8(StringRef Text); static bool printTypeInterface(Type Ty, DeclContext *DC, std::string &Result); static bool printTypeInterface(Type Ty, DeclContext *DC, llvm::raw_ostream &Out); diff --git a/include/swift/AST/ASTVisitor.h b/include/swift/AST/ASTVisitor.h index e48987a12494f..acdcae3192adc 100644 --- a/include/swift/AST/ASTVisitor.h +++ b/include/swift/AST/ASTVisitor.h @@ -1,8 +1,8 @@ -//===-- ASTVisitor.h - Decl, Expr and Stmt Visitor --------------*- C++ -*-===// +//===--- ASTVisitor.h - Decl, Expr and Stmt Visitor -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,6 +27,7 @@ #include "llvm/Support/ErrorHandling.h" namespace swift { + class ParameterList; /// ASTVisitor - This is a simple visitor class for Swift expressions. template(AA)...); \ } #include "swift/AST/Attr.def" + + bool visit(ParameterList *PL) { + return static_cast(this)->visitParameterList(PL); + } + + bool visitParameterList(ParameterList *PL) { return false; } }; diff --git a/include/swift/AST/ASTWalker.h b/include/swift/AST/ASTWalker.h index b5115f0a26b21..43fb12cb6abfe 100644 --- a/include/swift/AST/ASTWalker.h +++ b/include/swift/AST/ASTWalker.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,7 @@ class Stmt; class Pattern; class TypeRepr; struct TypeLoc; +class ParameterList; /// \brief An abstract class used to traverse an AST. class ASTWalker { @@ -182,6 +183,18 @@ class ASTWalker { /// params in an AbstractFunctionDecl. virtual bool shouldWalkIntoFunctionGenericParams() { return false; } + /// walkToParameterListPre - This method is called when first visiting a + /// ParameterList, before walking into its parameters. If it returns false, + /// the subtree is skipped. + /// + virtual bool walkToParameterListPre(ParameterList *PL) { return true; } + + /// walkToParameterListPost - This method is called after visiting the + /// children of a parameter list. If it returns false, the remaining + /// traversal is terminated and returns failure. + virtual bool walkToParameterListPost(ParameterList *PL) { return true; } + + protected: ASTWalker() = default; ASTWalker(const ASTWalker &) = default; diff --git a/include/swift/AST/AnyFunctionRef.h b/include/swift/AST/AnyFunctionRef.h index d72c8548aabc2..01455fb313272 100644 --- a/include/swift/AST/AnyFunctionRef.h +++ b/include/swift/AST/AnyFunctionRef.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -61,10 +61,10 @@ class AnyFunctionRef { getCaptureInfo().getLocalCaptures(Result); } - ArrayRef getBodyParamPatterns() const { + ArrayRef getParameterLists() const { if (auto *AFD = TheFunction.dyn_cast()) - return AFD->getBodyParamPatterns(); - return TheFunction.get()->getParamPatterns(); + return AFD->getParameterLists(); + return TheFunction.get()->getParameterLists(); } bool hasType() const { diff --git a/include/swift/AST/ArchetypeBuilder.h b/include/swift/AST/ArchetypeBuilder.h index c66cf6e72ddef..cb95ff800d0f2 100644 --- a/include/swift/AST/ArchetypeBuilder.h +++ b/include/swift/AST/ArchetypeBuilder.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -176,7 +176,7 @@ class ArchetypeBuilder { void visitPotentialArchetypes(F f); public: - /// Construct a new archtype builder. + /// Construct a new archetype builder. /// /// \param mod The module in which the builder will create archetypes. /// @@ -251,6 +251,14 @@ class ArchetypeBuilder { bool addGenericSignature(GenericSignature *sig, bool adoptArchetypes, bool treatRequirementsAsExplicit = false); + /// \brief Get a generic signature based on the provided complete list + /// of generic parameter types. + /// + /// \returns a generic signature build based on the provided list of + /// generic parameter types. + GenericSignature * + getGenericSignature(ArrayRef genericParamsTypes); + /// Infer requirements from the given type, recursively. /// /// This routine infers requirements from a type that occurs within the @@ -281,12 +289,12 @@ class ArchetypeBuilder { /// because the type \c Dictionary cannot be formed without it. /// /// \returns true if an error occurred, false otherwise. - bool inferRequirements(Pattern *pattern, GenericParamList *genericParams); + bool inferRequirements(ParameterList *params,GenericParamList *genericParams); /// Finalize the set of requirements, performing any remaining checking /// required before generating archetypes. /// - /// \returns true if an error occurs, false otherwse. + /// \returns true if an error occurs, false otherwise. bool finalize(SourceLoc loc); /// \brief Resolve the given type to the potential archetype it names. diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 3cf4e8803722a..e87775cafa3ee 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,7 +37,6 @@ TYPE_ATTR(noreturn) // SIL-specific attributes TYPE_ATTR(block_storage) TYPE_ATTR(box) -TYPE_ATTR(local_storage) TYPE_ATTR(sil_unowned) TYPE_ATTR(sil_unmanaged) TYPE_ATTR(sil_weak) @@ -92,7 +91,7 @@ SIMPLE_DECL_ATTR(final, Final, DECL_ATTR(objc, ObjC, OnFunc | OnClass | OnProtocol | OnVar | OnSubscript | - OnConstructor | OnDestructor | OnEnum, 3) + OnConstructor | OnDestructor | OnEnum | OnEnumElement, 3) SIMPLE_DECL_ATTR(required, Required, OnConstructor|DeclModifier, 4) @@ -100,7 +99,10 @@ SIMPLE_DECL_ATTR(required, Required, SIMPLE_DECL_ATTR(optional, Optional, OnConstructor|OnFunc|OnVar|OnSubscript|DeclModifier, 5) -/// NOTE: 6 is unused. +DECL_ATTR(swift3_migration, Swift3Migration, + OnEnum | OnStruct | OnClass | OnProtocol | OnTypeAlias | + OnVar | OnSubscript | OnConstructor | OnFunc | OnEnumElement | + OnGenericTypeParam | OnAssociatedType | LongAttribute, 6) SIMPLE_DECL_ATTR(noreturn, NoReturn, OnFunc, 7) @@ -140,7 +142,7 @@ DECL_ATTR(inline, Inline, OnFunc | OnConstructor, 20) DECL_ATTR(_semantics, Semantics, OnFunc | OnConstructor | OnDestructor | OnSubscript | - UserInaccessible, 21) + AllowMultipleAttributes | UserInaccessible, 21) SIMPLE_DECL_ATTR(dynamic, Dynamic, OnFunc | OnVar | OnSubscript | OnConstructor | DeclModifier, 22) @@ -160,7 +162,7 @@ SIMPLE_DECL_ATTR(nonobjc, NonObjC, OnFunc | OnVar | OnSubscript | OnConstructor, 30) SIMPLE_DECL_ATTR(_fixed_layout, FixedLayout, - OnClass | OnStruct | OnEnum | UserInaccessible, 31) + OnVar | OnClass | OnStruct | OnEnum | UserInaccessible, 31) // Non-serialized attributes. diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 37b60898d28e3..87c22839e7d69 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,8 @@ #include "swift/Basic/SourceLoc.h" #include "swift/Basic/UUID.h" +#include "swift/Basic/STLExtras.h" +#include "swift/Basic/Range.h" #include "swift/AST/Identifier.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/Ownership.h" @@ -642,7 +644,7 @@ enum class MinVersionComparison { Unavailable, /// The entity might be unavailable, because it was introduced after - /// the minimimum version. + /// the minimum version. PotentiallyUnavailable, /// The entity has been obsoleted. @@ -1148,6 +1150,28 @@ class WarnUnusedResultAttr : public DeclAttribute { } }; +/// The @swift3_migration attribute which describes the transformations +/// required to migrate the given Swift 2.x API to Swift 3. +class Swift3MigrationAttr : public DeclAttribute { + DeclName Renamed; + StringRef Message; + +public: + Swift3MigrationAttr(SourceLoc atLoc, SourceLoc attrLoc, SourceLoc lParenLoc, + DeclName renamed, StringRef message, SourceLoc rParenLoc, + bool implicit) + : DeclAttribute(DAK_Swift3Migration, atLoc, SourceRange(attrLoc, rParenLoc), + implicit), + Renamed(renamed), Message(message) { } + + DeclName getRenamed() const { return Renamed; } + StringRef getMessage() const { return Message; } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_Swift3Migration; + } +}; + /// \brief Attributes that may be applied to declarations. class DeclAttributes { /// Linked list of declaration attributes. @@ -1258,6 +1282,34 @@ class DeclAttributes { return nullptr; } +private: + /// Predicate used to filter MatchingAttributeRange. + template struct ToAttributeKind { + ToAttributeKind() {} + + Optional + operator()(const DeclAttribute *Attr) const { + if (isa(Attr) && (Attr->isValid() || AllowInvalid)) + return Attr; + return None; + } + }; + +public: + template + using AttributeKindRange = + OptionalTransformRange, + ToAttributeKind, + const_iterator>; + + /// Return a range with all attributes in DeclAttributes with AttrKind + /// ATTR. + template + AttributeKindRange getAttributes() const { + return AttributeKindRange( + make_range(begin(), end()), ToAttributeKind()); + } + // Remove the given attribute from the list of attributes. Used when // the attribute was semantically invalid. void removeAttribute(const DeclAttribute *attr) { diff --git a/include/swift/AST/Availability.h b/include/swift/AST/Availability.h index f69d30af68e78..cd38482080e99 100644 --- a/include/swift/AST/Availability.h +++ b/include/swift/AST/Availability.h @@ -1,8 +1,8 @@ -//===--- Availability.h - Swift Availability Structures -----*- C++ -*-===// +//===--- Availability.h - Swift Availability Structures ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -35,7 +35,7 @@ class VersionRange { // The concretization of lattice elements is: // Empty: empty // All: all versions - // x.y.x: all versions greater than or equal to to x.y.z + // x.y.x: all versions greater than or equal to x.y.z enum class ExtremalRange { Empty, All }; @@ -117,7 +117,7 @@ class VersionRange { } /// Mutates this range to be the union of itself and Other. This is the - /// join operator (least upper bound) in the veresion range lattice. + /// join operator (least upper bound) in the version range lattice. void unionWith(const VersionRange &Other) { // With the existing lattice this operation is precise. If the lattice // is ever extended it is important that this operation be an diff --git a/include/swift/AST/AvailabilitySpec.h b/include/swift/AST/AvailabilitySpec.h index 12e34af9ef35a..faff239576238 100644 --- a/include/swift/AST/AvailabilitySpec.h +++ b/include/swift/AST/AvailabilitySpec.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -89,6 +89,12 @@ class VersionConstraintAvailabilitySpec : public AvailabilitySpec { static bool classof(const AvailabilitySpec *Spec) { return Spec->getKind() == AvailabilitySpecKind::VersionConstraint; } + + void * + operator new(size_t Bytes, ASTContext &C, + unsigned Alignment = alignof(VersionConstraintAvailabilitySpec)){ + return AvailabilitySpec::operator new(Bytes, C, Alignment); + } }; /// A wildcard availability specification that guards execution @@ -115,6 +121,12 @@ class OtherPlatformAvailabilitySpec : public AvailabilitySpec { static bool classof(const AvailabilitySpec *Spec) { return Spec->getKind() == AvailabilitySpecKind::OtherPlatform; } + + void * + operator new(size_t Bytes, ASTContext &C, + unsigned Alignment = alignof(OtherPlatformAvailabilitySpec)) { + return AvailabilitySpec::operator new(Bytes, C, Alignment); + } }; } // end namespace swift diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 9a01ac1f3b14c..ad64e4c4a8cbb 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -188,36 +188,6 @@ BUILTIN_SIL_OPERATION(Assign, "assign", Special) /// Init has type (T, Builtin.RawPointer) -> () BUILTIN_SIL_OPERATION(Init, "initialize", Special) -/// MarkDependence has type (T, U) -> T -BUILTIN_SIL_OPERATION(MarkDependence, "markDependence", Special) - -/// allocValueBuffer : (inout Builtin.UnsafeValueBuffer, T.Type) -/// -> Builtin.RawPointer -BUILTIN_SIL_OPERATION(AllocValueBuffer, "allocValueBuffer", Special) - -/// projectValueBuffer : (inout Builtin.UnsafeValueBuffer, T.Type) -/// -> Builtin.RawPointer -BUILTIN_SIL_OPERATION(ProjectValueBuffer, "projectValueBuffer", Special) - -/// deallocValueBuffer : (inout Builtin.UnsafeValueBuffer, T.Type) -/// -> () -BUILTIN_SIL_OPERATION(DeallocValueBuffer, "deallocValueBuffer", Special) - -/// MakeMaterializeForSetCallback has type -/// ((Builtin.RawPointer, -/// inout Builtin.UnsafeValueBuffer, -/// inout T, -/// T.Type) -> ()) -/// -> Builtin.RawPointer -/// -/// The first argument is the address returned from materializeForSet. -/// The second argument is the same Builtin.UnsafeValueBuffer -/// that was passed to materializeForSet. -/// The third argument is self. -/// The last argument is the metatype for self. -BUILTIN_SIL_OPERATION(MakeMaterializeForSetCallback, - "makeMaterializeForSetCallback", Special) - /// CastToUnknownObject has type (T) -> Builtin.UnknownObject. BUILTIN_SIL_OPERATION(CastToUnknownObject, "castToUnknownObject", Special) @@ -291,7 +261,7 @@ BUILTIN_SIL_OPERATION(FixLifetime, "fixLifetime", Special) /// /// This builtin takes an inout object reference and returns a boolean. Passing /// the reference inout forces the optimizer to preserve a retain distinct from -/// what’s required to maintain lifetime for any of the reference's source-level +/// what's required to maintain lifetime for any of the reference's source-level /// copies, because the called function is allowed to replace the reference, /// thereby releasing the referent. /// diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 66b74381686b8..07933bd22f0d9 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -91,7 +91,7 @@ getLLVMIntrinsicIDForBuiltinWithOverflow(BuiltinValueKind ID); /// Returns null if the name does not identifier a known builtin value. ValueDecl *getBuiltinValueDecl(ASTContext &Context, Identifier Name); -/// \brief Returns the name of a builtin declaration given an builtin ID. +/// \brief Returns the name of a builtin declaration given a builtin ID. StringRef getBuiltinName(BuiltinValueKind ID); /// \brief The information identifying the builtin - its kind and types. diff --git a/include/swift/AST/CanTypeVisitor.h b/include/swift/AST/CanTypeVisitor.h index 345706d33e94b..0904ee40d2232 100644 --- a/include/swift/AST/CanTypeVisitor.h +++ b/include/swift/AST/CanTypeVisitor.h @@ -1,8 +1,8 @@ -//===-- CanTypeVisitor.h - TypeVisitor specialization -----------*- C++ -*-===// +//===--- CanTypeVisitor.h - TypeVisitor specialization ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/CaptureInfo.h b/include/swift/AST/CaptureInfo.h index d60af9c679861..8ca4faab21d7f 100644 --- a/include/swift/AST/CaptureInfo.h +++ b/include/swift/AST/CaptureInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index cbc9266e2ae1e..f9062a26d0512 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -1,8 +1,8 @@ -//===--- ClangModuleLoader.h - Clang Module Loader Interface --*- C++ -*- -===// +//===--- ClangModuleLoader.h - Clang Module Loader Interface ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Comment.h b/include/swift/AST/Comment.h index 50e8793a97343..8b823fa54756b 100644 --- a/include/swift/AST/Comment.h +++ b/include/swift/AST/Comment.h @@ -1,8 +1,8 @@ -//===--- Comment.h - Swift-specific comment parsing -----------------------===// +//===--- Comment.h - Swift-specific comment parsing -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/ConcreteDeclRef.h b/include/swift/AST/ConcreteDeclRef.h index 8afa6b9670ad3..abddc14eaccce 100644 --- a/include/swift/AST/ConcreteDeclRef.h +++ b/include/swift/AST/ConcreteDeclRef.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/DebuggerClient.h b/include/swift/AST/DebuggerClient.h index 6f6d9c523220b..70dcc573736bc 100644 --- a/include/swift/AST/DebuggerClient.h +++ b/include/swift/AST/DebuggerClient.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 44687313a8cab..2bf860e8e5d08 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,29 +17,14 @@ #ifndef SWIFT_DECL_H #define SWIFT_DECL_H -#include "swift/AST/Attr.h" #include "swift/AST/CaptureInfo.h" -#include "swift/AST/DeclContext.h" #include "swift/AST/DefaultArgumentKind.h" #include "swift/AST/GenericSignature.h" -#include "swift/AST/KnownProtocols.h" -#include "swift/AST/Identifier.h" #include "swift/AST/LazyResolver.h" -#include "swift/AST/Requirement.h" -#include "swift/AST/Substitution.h" -#include "swift/AST/Type.h" -#include "swift/AST/TypeLoc.h" #include "swift/Basic/OptionalEnum.h" #include "swift/Basic/Range.h" -#include "swift/Basic/SourceLoc.h" -#include "swift/Basic/STLExtras.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" -#include namespace clang { class Decl; @@ -76,12 +61,13 @@ namespace swift { class NameAliasType; class EnumCaseDecl; class EnumElementDecl; + class ParameterList; class Pattern; struct PrintOptions; class ProtocolDecl; class ProtocolType; struct RawComment; - enum class Resilience : unsigned char; + enum class ResilienceExpansion : unsigned; class TypeAliasDecl; class Stmt; class SubscriptDecl; @@ -209,7 +195,7 @@ enum class CircularityCheck { Checked }; -/// Keeps track of whrther a given class inherits initializers from its +/// Keeps track of whether a given class inherits initializers from its /// superclass. enum class StoredInheritsSuperclassInits { /// We have not yet checked. @@ -386,8 +372,8 @@ class alignas(1 << DeclAlignInBits) Decl { /// \see AbstractFunctionDecl::BodyKind unsigned BodyKind : 3; - /// Number of curried parameter patterns (tuples). - unsigned NumParamPatterns : 6; + /// Number of curried parameter lists. + unsigned NumParameterLists : 6; /// Whether we are overridden later. unsigned Overridden : 1; @@ -871,7 +857,7 @@ class alignas(1 << DeclAlignInBits) Decl { // Only allow allocation of Decls using the allocator in ASTContext // or by doing a placement new. - void *operator new(size_t Bytes, ASTContext &C, + void *operator new(size_t Bytes, const ASTContext &C, unsigned Alignment = alignof(Decl)); void *operator new(size_t Bytes, void *Mem) { assert(Mem); @@ -899,6 +885,20 @@ void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize, return mem; } +enum class RequirementReprKind : unsigned int { + /// A type bound T : P, where T is a type that depends on a generic + /// parameter and P is some type that should bound T, either as a concrete + /// supertype or a protocol to which T must conform. + TypeConstraint, + + /// A same-type requirement T == U, where T and U are types that shall be + /// equivalent. + SameType, + + // Note: there is code that packs this enum in a 2-bit bitfield. Audit users + // when adding enumerators. +}; + /// \brief A single requirement in a 'where' clause, which places additional /// restrictions on the generic parameters or associated types of a generic /// function, type, or protocol. @@ -909,14 +909,14 @@ void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize, /// \c GenericParamList assumes these are POD-like. class RequirementRepr { SourceLoc SeparatorLoc; - RequirementKind Kind : 2; + RequirementReprKind Kind : 2; bool Invalid : 1; TypeLoc Types[2]; /// Set during deserialization; used to print out the requirements accurately /// for the generated interface. StringRef AsWrittenString; - RequirementRepr(SourceLoc SeparatorLoc, RequirementKind Kind, + RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind, TypeLoc FirstType, TypeLoc SecondType) : SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false), Types{FirstType, SecondType} { } @@ -924,7 +924,7 @@ class RequirementRepr { void printImpl(raw_ostream &OS, bool AsWritten) const; public: - /// \brief Construct a new conformance requirement. + /// \brief Construct a new type-constraint requirement. /// /// \param Subject The type that must conform to the given protocol or /// composition, or be a subclass of the given class type. @@ -932,10 +932,10 @@ class RequirementRepr { /// this requirement was implied. /// \param Constraint The protocol or protocol composition to which the /// subject must conform, or superclass from which the subject must inherit. - static RequirementRepr getConformance(TypeLoc Subject, - SourceLoc ColonLoc, - TypeLoc Constraint) { - return { ColonLoc, RequirementKind::Conformance, Subject, Constraint }; + static RequirementRepr getTypeConstraint(TypeLoc Subject, + SourceLoc ColonLoc, + TypeLoc Constraint) { + return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint }; } /// \brief Construct a new same-type requirement. @@ -945,13 +945,13 @@ class RequirementRepr { /// an invalid location if this requirement was implied. /// \param SecondType The second type. static RequirementRepr getSameType(TypeLoc FirstType, - SourceLoc EqualLoc, - TypeLoc SecondType) { - return { EqualLoc, RequirementKind::SameType, FirstType, SecondType }; + SourceLoc EqualLoc, + TypeLoc SecondType) { + return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType }; } /// \brief Determine the kind of requirement - RequirementKind getKind() const { return Kind; } + RequirementReprKind getKind() const { return Kind; } /// \brief Determine whether this requirement is invalid. bool isInvalid() const { return Invalid; } @@ -959,98 +959,98 @@ class RequirementRepr { /// \brief Mark this requirement invalid. void setInvalid() { Invalid = true; } - /// \brief For a conformance requirement, return the subject of the + /// \brief For a type-bound requirement, return the subject of the /// conformance relationship. Type getSubject() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[0].getType(); } TypeRepr *getSubjectRepr() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[0].getTypeRepr(); } TypeLoc &getSubjectLoc() { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[0]; } const TypeLoc &getSubjectLoc() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[0]; } - /// \brief For a conformance requirement, return the protocol or to which + /// \brief For a type-bound requirement, return the protocol or to which /// the subject conforms or superclass it inherits. Type getConstraint() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[1].getType(); } TypeLoc &getConstraintLoc() { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[1]; } const TypeLoc &getConstraintLoc() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return Types[1]; } /// \brief Retrieve the location of the ':' in an explicitly-written /// conformance requirement. SourceLoc getColonLoc() const { - assert(getKind() == RequirementKind::Conformance); + assert(getKind() == RequirementReprKind::TypeConstraint); return SeparatorLoc; } /// \brief Retrieve the first type of a same-type requirement. Type getFirstType() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[0].getType(); } TypeRepr *getFirstTypeRepr() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[0].getTypeRepr(); } TypeLoc &getFirstTypeLoc() { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[0]; } const TypeLoc &getFirstTypeLoc() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[0]; } /// \brief Retrieve the second type of a same-type requirement. Type getSecondType() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[1].getType(); } TypeRepr *getSecondTypeRepr() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[1].getTypeRepr(); } TypeLoc &getSecondTypeLoc() { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[1]; } const TypeLoc &getSecondTypeLoc() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return Types[1]; } /// \brief Retrieve the location of the '==' in an explicitly-written /// same-type requirement. SourceLoc getEqualLoc() const { - assert(getKind() == RequirementKind::SameType); + assert(getKind() == RequirementReprKind::SameType); return SeparatorLoc; } @@ -1063,6 +1063,11 @@ class RequirementRepr { AsWrittenString = Str; } + /// Further analyze the written string, if it's not empty, to collect the first + /// type, the second type and the requirement kind. + Optional> + getAsAnalyzedWrittenString() const; + SourceRange getSourceRange() const { return SourceRange(Types[0].getSourceRange().Start, Types[1].getSourceRange().End); @@ -1874,18 +1879,36 @@ class ExtensionRange { /// the initializer can be null if there is none. class PatternBindingEntry { Pattern *ThePattern; - llvm::PointerIntPair InitAndChecked; - + + enum class Flags { + Checked = 1 << 0, + Removed = 1 << 1 + }; + + // When the initializer is removed we don't actually clear the pointer + // because we might need to get initializer's source range. Since the + // initializer is ASTContext-allocated it is safe. + llvm::PointerIntPair> InitCheckedAndRemoved; + public: PatternBindingEntry(Pattern *P, Expr *E) - : ThePattern(P), InitAndChecked(E, false) {} + : ThePattern(P), InitCheckedAndRemoved(E, {}) {} Pattern *getPattern() const { return ThePattern; } void setPattern(Pattern *P) { ThePattern = P; } - Expr *getInit() const { return InitAndChecked.getPointer(); } - void setInit(Expr *E) { InitAndChecked.setPointer(E); } - bool isInitializerChecked() const { return InitAndChecked.getInt(); } - void setInitializerChecked() { InitAndChecked.setInt(true); } + Expr *getInit() const { + return (InitCheckedAndRemoved.getInt().contains(Flags::Removed)) + ? nullptr : InitCheckedAndRemoved.getPointer(); + } + SourceRange getOrigInitRange() const; + void setInit(Expr *E); + bool isInitializerChecked() const { + return InitCheckedAndRemoved.getInt().contains(Flags::Checked); + } + void setInitializerChecked() { + InitCheckedAndRemoved.setInt( + InitCheckedAndRemoved.getInt() | Flags::Checked); + } }; /// \brief This decl contains a pattern and optional initializer for a set @@ -1923,11 +1946,7 @@ class PatternBindingDecl : public Decl { StaticSpellingKind StaticSpelling, SourceLoc VarLoc, Pattern *Pat, Expr *E, - DeclContext *Parent) { - return create(Ctx, StaticLoc, StaticSpelling, VarLoc, - PatternBindingEntry(Pat, E), Parent); - } - + DeclContext *Parent); SourceLoc getStartLoc() const { return StaticLoc.isValid() ? StaticLoc : VarLoc; @@ -1945,6 +1964,10 @@ class PatternBindingDecl : public Decl { return getPatternList()[i].getInit(); } + SourceRange getOrigInitRange(unsigned i) const { + return getPatternList()[i].getOrigInitRange(); + } + void setInit(unsigned i, Expr *E) { getMutablePatternList()[i].setInit(E); } @@ -2177,6 +2200,7 @@ class ValueDecl : public Decl { /// Retrieve the full name of the declaration. /// TODO: Rename to getName? DeclName getFullName() const { return Name; } + void setName(DeclName name) { Name = name; } /// Retrieve the base name of the declaration, ignoring any argument /// names. @@ -2242,16 +2266,6 @@ class ValueDecl : public Decl { /// If \p DC is null, returns true only if this declaration is public. bool isAccessibleFrom(const DeclContext *DC) const; - /// Get the innermost declaration context that can provide generic - /// parameters used within this declaration. - DeclContext *getPotentialGenericDeclContext(); - - /// Get the innermost declaration context that can provide generic - /// parameters used within this declaration. - const DeclContext *getPotentialGenericDeclContext() const { - return const_cast(this)->getPotentialGenericDeclContext(); - } - /// Retrieve the "interface" type of this value, which is the type used when /// the declaration is viewed from the outside. For a generic function, /// this will have generic function type using generic parameters rather than @@ -2405,7 +2419,7 @@ class TypeAliasDecl : public TypeDecl { /// The type that represents this (sugared) name alias. mutable NameAliasType *AliasTy; - SourceLoc TypeAliasLoc; // The location of the 'typalias' keyword + SourceLoc TypeAliasLoc; // The location of the 'typealias' keyword TypeLoc UnderlyingTy; public: @@ -2745,7 +2759,7 @@ class NominalTypeDecl : public TypeDecl, public DeclContext, friend class DeclContext; friend class IterableDeclContext; friend ArrayRef - ValueDecl::getSatisfiedProtocolRequirements(bool) const; + ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const; protected: Type DeclaredTy; @@ -2787,13 +2801,17 @@ class NominalTypeDecl : public TypeDecl, public DeclContext, /// \brief Does this declaration expose a fixed layout to all resilience /// domains? + /// + /// For structs, this means clients can assume the number and order of + /// stored properties will not change. + /// + /// For enums, this means clients can assume the number and order of + /// cases will not change. bool hasFixedLayout() const; /// \brief Does this declaration expose a fixed layout to the given /// module? - bool hasFixedLayout(ModuleDecl *M) const { - return (hasFixedLayout() || M == getModuleContext()); - } + bool hasFixedLayout(ModuleDecl *M, ResilienceExpansion expansion) const; void setMemberLoader(LazyMemberLoader *resolver, uint64_t contextData); bool hasLazyMembers() const { @@ -2808,7 +2826,7 @@ class NominalTypeDecl : public TypeDecl, public DeclContext, return ValidatingGenericSignature; } - /// \brief Returns true if this this decl contains delayed value or protocol + /// \brief Returns true if this decl contains delayed value or protocol /// declarations. bool hasDelayedMembers() const { return NominalTypeDeclBits.HasDelayedMembers; @@ -2850,12 +2868,12 @@ class NominalTypeDecl : public TypeDecl, public DeclContext, /// Set the generic signature of this type. void setGenericSignature(GenericSignature *sig); - /// Retrieve the generic parameter types. - ArrayRef getGenericParamTypes() const { + /// Retrieve the innermost generic parameter types. + ArrayRef getInnermostGenericParamTypes() const { if (!GenericSig) return { }; - return GenericSig->getGenericParams(); + return GenericSig->getInnermostGenericParams(); } /// Retrieve the generic requirements. @@ -3271,7 +3289,7 @@ class ClassDecl : public NominalTypeDecl { return ClassDeclBits.Foreign; } void setForeign(bool isForeign = true) { - ClassDeclBits.Foreign = true; + ClassDeclBits.Foreign = isForeign; } /// Find a method of a class that overrides a given method. @@ -3620,9 +3638,9 @@ class AbstractStorageDecl : public ValueDecl { /// to and may be overridden. /// 2) When a stored property satisfies a protocol requirement, these /// accessors end up as entries in the witness table. - /// 3) Perhaps someday these will be used by accesses outside of this - /// resilience domain, when the owning type is resilient. - /// + /// 3) When a stored property is accessed outside of the storage + /// declaration's resilience domain, when the owning type or + /// global variable is resilient. StoredWithTrivialAccessors, /// This is a stored property with either a didSet specifier or a @@ -4022,6 +4040,18 @@ class AbstractStorageDecl : public ValueDecl { AccessStrategy getAccessStrategy(AccessSemantics semantics, AccessKind accessKind) const; + /// \brief Does this declaration expose a fixed layout to all resilience + /// domains? + /// + /// Roughly speaking, this means we can make assumptions about whether + /// the storage is stored or computed, and if stored, the precise access + /// pattern to be used. + bool hasFixedLayout() const; + + /// \brief Does this declaration expose a fixed layout to the given + /// module? + bool hasFixedLayout(ModuleDecl *M, ResilienceExpansion expansion) const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_AbstractStorageDecl && @@ -4032,7 +4062,7 @@ class AbstractStorageDecl : public ValueDecl { /// VarDecl - 'var' and 'let' declarations. class VarDecl : public AbstractStorageDecl { protected: - llvm::PointerUnion3 ParentPattern; + llvm::PointerUnion ParentPattern; VarDecl(DeclKind Kind, bool IsStatic, bool IsLet, SourceLoc NameLoc, Identifier Name, Type Ty, DeclContext *DC) @@ -4085,9 +4115,9 @@ class VarDecl : public AbstractStorageDecl { ParentPattern = PBD; } - /// Return the Pattern involved in initializing this VarDecl. However, recall that - /// the Pattern may be involved in initializing more than just this one vardecl. - /// For example, if this is a VarDecl for "x", the pattern may be + /// Return the Pattern involved in initializing this VarDecl. However, recall + /// that the Pattern may be involved in initializing more than just this one + /// vardecl. For example, if this is a VarDecl for "x", the pattern may be /// "(x, y)" and the initializer on the PatternBindingDecl may be "(1,2)" or /// "foo()". /// @@ -4173,7 +4203,7 @@ class VarDecl : public AbstractStorageDecl { void emitLetToVarNoteIfSimple(DeclContext *UseDC) const; /// Returns true if the name is the self identifier and is implicit. - bool isImplicitSelf() const; + bool isSelfParameter() const; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { @@ -4185,15 +4215,34 @@ class VarDecl : public AbstractStorageDecl { class ParamDecl : public VarDecl { Identifier ArgumentName; SourceLoc ArgumentNameLoc; + SourceLoc LetVarInOutLoc; + /// This is the type specified, including location information. + TypeLoc typeLoc; + + /// The default value, if any, along with whether this is varargs. + llvm::PointerIntPair DefaultValueAndIsVariadic; + + /// True if the type is implicitly specified in the source, but this has an + /// apparently valid typeRepr. This is used in accessors, which look like: + /// set (value) { + /// but need to get the typeRepr from the property as a whole so Sema can + /// resolve the type. + bool IsTypeLocImplicit = false; + + /// Information about a symbolic default argument, like __FILE__. + DefaultArgumentKind defaultArgumentKind = DefaultArgumentKind::None; + public: - ParamDecl(bool isLet, SourceLoc argumentNameLoc, + ParamDecl(bool isLet, SourceLoc letVarInOutLoc, SourceLoc argumentNameLoc, Identifier argumentName, SourceLoc parameterNameLoc, - Identifier parameterName, Type ty, DeclContext *dc) - : VarDecl(DeclKind::Param, /*IsStatic=*/false, isLet, parameterNameLoc, - parameterName, ty, dc), - ArgumentName(argumentName), ArgumentNameLoc(argumentNameLoc) { } + Identifier parameterName, Type ty, DeclContext *dc); + /// Clone constructor, allocates a new ParamDecl identical to the first. + /// Intentionally not defined as a typical copy constructor to avoid + /// accidental copies. + ParamDecl(ParamDecl *PD); + /// Retrieve the argument (API) name for this function parameter. Identifier getArgumentName() const { return ArgumentName; } @@ -4203,20 +4252,57 @@ class ParamDecl : public VarDecl { /// was specified separately from the parameter name. SourceLoc getArgumentNameLoc() const { return ArgumentNameLoc; } - SourceRange getSourceRange() const { - if (ArgumentNameLoc.isValid() && getNameLoc().isInvalid()) - return ArgumentNameLoc; - if (ArgumentNameLoc.isInvalid() && getNameLoc().isValid()) - return getNameLoc(); - return SourceRange(ArgumentNameLoc, getNameLoc()); - } + SourceLoc getLetVarInOutLoc() const { return LetVarInOutLoc; } + + TypeLoc &getTypeLoc() { return typeLoc; } + TypeLoc getTypeLoc() const { return typeLoc; } - Pattern *getParamParentPattern() const { - return ParentPattern.dyn_cast(); + bool isTypeLocImplicit() const { return IsTypeLocImplicit; } + void setIsTypeLocImplicit(bool val) { IsTypeLocImplicit = val; } + + bool isDefaultArgument() const { + return defaultArgumentKind != DefaultArgumentKind::None; + } + DefaultArgumentKind getDefaultArgumentKind() const { + return defaultArgumentKind; + } + void setDefaultArgumentKind(DefaultArgumentKind K) { + defaultArgumentKind = K; + } + + void setDefaultValue(ExprHandle *H) { + DefaultValueAndIsVariadic.setPointer(H); } - void setParamParentPattern(Pattern *Pat) { - ParentPattern = Pat; + ExprHandle *getDefaultValue() const { + return DefaultValueAndIsVariadic.getPointer(); } + /// Whether or not this parameter is varargs. + bool isVariadic() const { return DefaultValueAndIsVariadic.getInt(); } + void setVariadic(bool value = true) {DefaultValueAndIsVariadic.setInt(value);} + + /// Remove the type of this varargs element designator, without the array + /// type wrapping it. A parameter like "Int..." will have formal parameter + /// type of "[Int]" and this returns "Int". + static Type getVarargBaseTy(Type VarArgT); + + /// Remove the type of this varargs element designator, without the array + /// type wrapping it. + Type getVarargBaseTy() const { + assert(isVariadic()); + return getVarargBaseTy(getType()); + } + + SourceRange getSourceRange() const; + + /// Create an implicit 'self' decl for a method in the specified decl context. + /// If 'static' is true, then this is self for a static method in the type. + /// + /// Note that this decl is created, but it is returned with an incorrect + /// DeclContext that needs to be set correctly. This is automatically handled + /// when a function is created with this as part of its argument list. + /// + static ParamDecl *createSelf(SourceLoc loc, DeclContext *DC, + bool isStatic = false, bool isInOut = false); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { @@ -4264,15 +4350,16 @@ enum class ObjCSubscriptKind { /// A given type can have multiple subscript declarations, so long as the /// signatures (indices and element type) are distinct. /// -class SubscriptDecl : public AbstractStorageDecl { +class SubscriptDecl : public AbstractStorageDecl, public DeclContext { SourceLoc ArrowLoc; - Pattern *Indices; + ParameterList *Indices; TypeLoc ElementTy; public: - SubscriptDecl(DeclName Name, SourceLoc SubscriptLoc, Pattern *Indices, + SubscriptDecl(DeclName Name, SourceLoc SubscriptLoc, ParameterList *Indices, SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent) : AbstractStorageDecl(DeclKind::Subscript, Parent, Name, SubscriptLoc), + DeclContext(DeclContextKind::SubscriptDecl, Parent), ArrowLoc(ArrowLoc), Indices(nullptr), ElementTy(ElementTy) { setIndices(Indices); } @@ -4282,9 +4369,9 @@ class SubscriptDecl : public AbstractStorageDecl { SourceRange getSourceRange() const; /// \brief Retrieve the indices for this subscript operation. - Pattern *getIndices() { return Indices; } - const Pattern *getIndices() const { return Indices; } - void setIndices(Pattern *p); + ParameterList *getIndices() { return Indices; } + const ParameterList *getIndices() const { return Indices; } + void setIndices(ParameterList *p); /// Retrieve the type of the indices. Type getIndicesType() const; @@ -4313,6 +4400,13 @@ class SubscriptDecl : public AbstractStorageDecl { static bool classof(const Decl *D) { return D->getKind() == DeclKind::Subscript; } + + static bool classof(const DeclContext *DC) { + return DC->getContextKind() == DeclContextKind::SubscriptDecl; + } + + using DeclContext::operator new; + using Decl::getASTContext; }; /// \brief Base class for function-like declarations. @@ -4373,22 +4467,20 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { CaptureInfo Captures; AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name, - SourceLoc NameLoc, unsigned NumParamPatterns, + SourceLoc NameLoc, unsigned NumParameterLists, GenericParamList *GenericParams) : ValueDecl(Kind, Parent, Name, NameLoc), DeclContext(DeclContextKind::AbstractFunctionDecl, Parent), Body(nullptr), GenericParams(nullptr), GenericSig(nullptr) { setBodyKind(BodyKind::None); setGenericParams(GenericParams); - AbstractFunctionDeclBits.NumParamPatterns = NumParamPatterns; + AbstractFunctionDeclBits.NumParameterLists = NumParameterLists; AbstractFunctionDeclBits.Overridden = false; // Verify no bitfield truncation. - assert(AbstractFunctionDeclBits.NumParamPatterns == NumParamPatterns); + assert(AbstractFunctionDeclBits.NumParameterLists == NumParameterLists); } - MutableArrayRef getBodyParamBuffer(); - void setBodyKind(BodyKind K) { AbstractFunctionDeclBits.BodyKind = unsigned(K); } @@ -4440,14 +4532,14 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { } void setBody(BraceStmt *S, BodyKind NewBodyKind = BodyKind::Parsed) { assert(getBodyKind() != BodyKind::Skipped && - "can not set a body if it was skipped"); + "cannot set a body if it was skipped"); Body = S; setBodyKind(NewBodyKind); } /// \brief Note that the body was skipped for this function. Function body - /// can not be attached after this call. + /// cannot be attached after this call. void setBodySkipped(SourceRange bodyRange) { assert(getBodyKind() == BodyKind::None); BodyRange = bodyRange; @@ -4521,8 +4613,8 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { /// Determine whether the name of the ith argument is an API name by default. bool argumentNameIsAPIByDefault(unsigned i) const; - unsigned getNumParamPatterns() const { - return AbstractFunctionDeclBits.NumParamPatterns; + unsigned getNumParameterLists() const { + return AbstractFunctionDeclBits.NumParameterLists; } /// \brief Returns the "natural" number of argument clauses taken by this @@ -4547,7 +4639,7 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { /// func const(x : Int) -> () -> Int { return { x } } // NAC==1 /// \endcode unsigned getNaturalArgumentCount() const { - return getNumParamPatterns(); + return getNumParameterLists(); } /// \brief Returns the parameter pattern(s) for the function definition that @@ -4555,13 +4647,17 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { /// /// The number of "top-level" elements in this pattern will match the number /// of argument names in the compound name of the function or constructor. - MutableArrayRef getBodyParamPatterns() { - return getBodyParamBuffer(); + MutableArrayRef getParameterLists(); + ArrayRef getParameterLists() const { + auto paramLists = + const_cast(this)->getParameterLists(); + return ArrayRef(paramLists.data(),paramLists.size()); } - ArrayRef getBodyParamPatterns() const { - auto Patterns = - const_cast(this)->getBodyParamBuffer(); - return ArrayRef(Patterns.data(), Patterns.size()); + ParameterList *getParameterList(unsigned i) { + return getParameterLists()[i]; + } + const ParameterList *getParameterList(unsigned i) const { + return getParameterLists()[i]; } /// \brief If this is a method in a type or extension thereof, compute @@ -4584,7 +4680,10 @@ class AbstractFunctionDecl : public ValueDecl, public DeclContext { /// /// Note that some functions don't have an implicit 'self' decl, for example, /// free functions. In this case nullptr is returned. - VarDecl *getImplicitSelfDecl() const; + const ParamDecl *getImplicitSelfDecl() const { + return const_cast(this)->getImplicitSelfDecl(); + } + ParamDecl *getImplicitSelfDecl(); /// \brief Retrieve the set of parameters to a generic function, or null if /// this function is not generic. @@ -4649,7 +4748,7 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc StaticLoc; // Location of the 'static' token or invalid. SourceLoc FuncLoc; // Location of the 'func' token. SourceLoc ThrowsLoc; // Location of the 'throws' token. - SourceLoc AccessorKeywordLoc; // Location of the accessor keyword token, e,g. 'set'. + SourceLoc AccessorKeywordLoc; // Location of the accessor keyword, e.g. 'set'. TypeLoc FnRetType; @@ -4668,23 +4767,24 @@ class FuncDecl : public AbstractFunctionDecl { /// which property and what kind of accessor. llvm::PointerIntPair AccessorDecl; llvm::PointerUnion OverriddenOrDerivedForDecl; - llvm::PointerIntPair OperatorAndAddressorKind; + llvm::PointerIntPair OperatorAndAddressorKind; FuncDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, SourceLoc ThrowsLoc, SourceLoc AccessorKeywordLoc, - unsigned NumParamPatterns, + unsigned NumParameterLists, GenericParamList *GenericParams, Type Ty, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Func, Parent, Name, NameLoc, - NumParamPatterns, GenericParams), + NumParameterLists, GenericParams), StaticLoc(StaticLoc), FuncLoc(FuncLoc), ThrowsLoc(ThrowsLoc), AccessorKeywordLoc(AccessorKeywordLoc), OverriddenOrDerivedForDecl(), OperatorAndAddressorKind(nullptr, AddressorKind::NotAddressor) { FuncDeclBits.IsStatic = StaticLoc.isValid() || getName().isOperator(); FuncDeclBits.StaticSpelling = static_cast(StaticSpelling); - assert(NumParamPatterns > 0 && "Must have at least an empty tuple arg"); + assert(NumParameterLists > 0 && "Must have at least an empty tuple arg"); setType(Ty); FuncDeclBits.Mutating = false; FuncDeclBits.HasDynamicSelf = false; @@ -4700,7 +4800,7 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc NameLoc, SourceLoc ThrowsLoc, SourceLoc AccessorKeywordLoc, GenericParamList *GenericParams, Type Ty, - unsigned NumParamPatterns, + unsigned NumParameterLists, DeclContext *Parent, ClangNode ClangN); @@ -4712,7 +4812,7 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc NameLoc, SourceLoc ThrowsLoc, SourceLoc AccessorKeywordLoc, GenericParamList *GenericParams, Type Ty, - unsigned NumParamPatterns, + unsigned NumParameterLists, DeclContext *Parent); static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc, @@ -4720,7 +4820,7 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, SourceLoc ThrowsLoc, SourceLoc AccessorKeywordLoc, GenericParamList *GenericParams, - Type Ty, ArrayRef BodyParams, + Type Ty, ArrayRef ParameterLists, TypeLoc FnRetType, DeclContext *Parent, ClangNode ClangN = ClangNode()); @@ -4743,6 +4843,25 @@ class FuncDecl : public AbstractFunctionDecl { FuncDeclBits.Mutating = Mutating; } + /// \brief Returns the parameter lists(s) for the function definition. + /// + /// The number of "top-level" elements will match the number of argument names + /// in the compound name of the function or constructor. + MutableArrayRef getParameterLists() { + auto Ptr = reinterpret_cast(cast(this) + 1); + return { Ptr, getNumParameterLists() }; + } + ArrayRef getParameterLists() const { + return AbstractFunctionDecl::getParameterLists(); + } + ParameterList *getParameterList(unsigned i) { + return getParameterLists()[i]; + } + const ParameterList *getParameterList(unsigned i) const { + return getParameterLists()[i]; + } + + bool getHaveSearchedForCommonOverloadReturnType() { return HaveSearchedForCommonOverloadReturnType; } @@ -4760,7 +4879,7 @@ class FuncDecl : public AbstractFunctionDecl { /// attribute. For example a "mutating set" accessor. bool isExplicitNonMutating() const; - void setDeserializedSignature(ArrayRef BodyParams, + void setDeserializedSignature(ArrayRef ParameterLists, TypeLoc FnRetType); SourceLoc getStaticLoc() const { return StaticLoc; } @@ -4769,7 +4888,7 @@ class FuncDecl : public AbstractFunctionDecl { SourceLoc getAccessorKeywordLoc() const {return AccessorKeywordLoc; } SourceLoc getStartLoc() const { - return StaticLoc.isValid() ? StaticLoc : FuncLoc; + return StaticLoc.isValid() && !isAccessor() ? StaticLoc : FuncLoc; } SourceRange getSourceRange() const; @@ -4806,22 +4925,24 @@ class FuncDecl : public AbstractFunctionDecl { } /// isUnaryOperator - Determine whether this is a unary operator - /// implementation, in other words, the name of the function is an operator, - /// and the argument list consists syntactically of a single-element tuple - /// pattern. This check is syntactic rather than type-based in order to allow + /// implementation. This check is a syntactic rather than type-based check, + /// which looks at the number of parameters specified, in order to allow /// for the definition of unary operators on tuples, as in: - /// func [prefix] + (_:(a:Int, b:Int)) + /// + /// prefix func + (param : (a:Int, b:Int)) + /// /// This also allows the unary-operator-ness of a func decl to be determined /// prior to type checking. bool isUnaryOperator() const; /// isBinaryOperator - Determine whether this is a binary operator - /// implementation, in other words, the name of the function is an operator, - /// and the argument list consists syntactically of a two-element tuple - /// pattern. This check is syntactic rather than type-based in order to - /// distinguish a binary operator from a unary operator on tuples, as in: - /// func [prefix] + (_:(a:Int, b:Int)) // unary operator +(1,2) - /// func [infix] + (a:Int, b:Int) // binary operator 1 + 2 + /// implementation. This check is a syntactic rather than type-based check, + /// which looks at the number of parameters specified, in order to allow + /// distinguishing a binary operator from a unary operator on tuples, as in: + /// + /// prefix func + (_:(a:Int, b:Int)) // unary operator +(1,2) + /// infix func + (a:Int, b:Int) // binary operator 1 + 2 + /// /// This also allows the binary-operator-ness of a func decl to be determined /// prior to type checking. bool isBinaryOperator() const; @@ -5152,8 +5273,6 @@ enum class CtorInitializerKind { /// } /// \endcode class ConstructorDecl : public AbstractFunctionDecl { - friend class AbstractFunctionDecl; - /// The failability of this initializer, which is an OptionalTypeKind. unsigned Failability : 2; @@ -5163,7 +5282,7 @@ class ConstructorDecl : public AbstractFunctionDecl { // Location of the 'throws' token. SourceLoc ThrowsLoc; - Pattern *BodyParams[2]; + ParameterList *ParameterLists[2]; /// The type of the initializing constructor. Type InitializerType; @@ -5182,11 +5301,11 @@ class ConstructorDecl : public AbstractFunctionDecl { public: ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, OptionalTypeKind Failability, SourceLoc FailabilityLoc, - Pattern *SelfBodyParam, Pattern *BodyParams, + ParamDecl *selfParam, ParameterList *BodyParams, GenericParamList *GenericParams, SourceLoc throwsLoc, DeclContext *Parent); - void setBodyParams(Pattern *selfPattern, Pattern *bodyParams); + void setParameterLists(ParamDecl *selfParam, ParameterList *bodyParams); SourceLoc getConstructorLoc() const { return getNameLoc(); } SourceLoc getStartLoc() const { return getConstructorLoc(); } @@ -5211,6 +5330,26 @@ class ConstructorDecl : public AbstractFunctionDecl { Expr *getSuperInitCall() { return CallToSuperInit; } void setSuperInitCall(Expr *CallExpr) { CallToSuperInit = CallExpr; } + MutableArrayRef getParameterLists() { + return { ParameterLists, 2 }; + } + ArrayRef getParameterLists() const { + return AbstractFunctionDecl::getParameterLists(); + } + ParameterList *getParameterList(unsigned i) { + return getParameterLists()[i]; + } + const ParameterList *getParameterList(unsigned i) const { + return getParameterLists()[i]; + } + + /// Returns the normal parameters to the initializer, not including self. + ParameterList *getParameters() { return ParameterLists[1]; } + + /// Returns the normal parameters to the initializer, not including self. + const ParameterList *getParameters() const { return ParameterLists[1]; } + + /// Specifies the kind of initialization call performed within the body /// of the constructor, e.g., self.init or super.init. enum class BodyInitKind { @@ -5359,14 +5498,22 @@ class ConstructorDecl : public AbstractFunctionDecl { /// } /// \endcode class DestructorDecl : public AbstractFunctionDecl { - friend class AbstractFunctionDecl; - Pattern *SelfPattern; + ParameterList *SelfParameter; public: DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc, - Pattern *SelfPattern, DeclContext *Parent); + ParamDecl *selfDecl, DeclContext *Parent); - void setSelfPattern(Pattern *selfPattern); + void setSelfDecl(ParamDecl *selfDecl); + MutableArrayRef getParameterLists() { + return { &SelfParameter, 1 }; + } + ArrayRef getParameterLists() const { + return { &SelfParameter, 1 }; + } + + + SourceLoc getDestructorLoc() const { return getNameLoc(); } SourceLoc getStartLoc() const { return getDestructorLoc(); } SourceRange getSourceRange() const; @@ -5625,25 +5772,17 @@ inline bool AbstractStorageDecl::isStatic() const { return false; } -inline MutableArrayRef AbstractFunctionDecl::getBodyParamBuffer() { - unsigned NumPatterns = AbstractFunctionDeclBits.NumParamPatterns; - Pattern **Ptr; +inline MutableArrayRef +AbstractFunctionDecl::getParameterLists() { switch (getKind()) { default: llvm_unreachable("Unknown AbstractFunctionDecl!"); case DeclKind::Constructor: - Ptr = cast(this)->BodyParams; - break; - + return cast(this)->getParameterLists(); case DeclKind::Destructor: - Ptr = &cast(this)->SelfPattern; - break; - + return cast(this)->getParameterLists(); case DeclKind::Func: - // Body patterns are tail allocated. - Ptr = reinterpret_cast(cast(this) + 1); - break; + return cast(this)->getParameterLists(); } - return MutableArrayRef(Ptr, NumPatterns); } inline DeclIterator &DeclIterator::operator++() { diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 82324598c60c2..34dbb0aa44471 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -66,6 +66,7 @@ enum class DeclContextKind : uint8_t { AbstractClosureExpr, Initializer, TopLevelCodeDecl, + SubscriptDecl, AbstractFunctionDecl, SerializedLocal, Last_LocalDeclContextKind = SerializedLocal, @@ -245,7 +246,7 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// ClassDecl, otherwise return null. ClassDecl *isClassOrClassExtensionContext() const; - /// If this DeclContext is a enum, or an extension on a enum, return the + /// If this DeclContext is an enum, or an extension on an enum, return the /// EnumDecl, otherwise return null. EnumDecl *isEnumOrEnumExtensionContext() const; @@ -404,6 +405,12 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { LazyResolver *typeResolver, SmallVectorImpl &decls) const; + /// Look up all Objective-C methods with the given selector visible + /// in the enclosing module. + void lookupAllObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const; + /// Return the ASTContext for a specified DeclContext by /// walking up to the enclosing module and returning its ASTContext. ASTContext &getASTContext() const; diff --git a/include/swift/AST/DeclNameLoc.h b/include/swift/AST/DeclNameLoc.h new file mode 100644 index 0000000000000..2d41bf0776445 --- /dev/null +++ b/include/swift/AST/DeclNameLoc.h @@ -0,0 +1,115 @@ +//===--- DeclNameLoc.h - Declaration Name Location Info ---------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclNameLoc class. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_DECL_NAME_LOC_H +#define SWIFT_AST_DECL_NAME_LOC_H + +#include "swift/Basic/LLVM.h" +#include "swift/Basic/SourceLoc.h" + +namespace swift { + +class ASTContext; + +/// Source location information for a declaration name (\c DeclName) +/// written in the source. +class DeclNameLoc { + /// Source location information. + /// + /// If \c NumArgumentLabels == 0, this is the SourceLoc for the base name. + /// Otherwise, it points to an array of SourceLocs, which contains: + /// * The base name location + /// * The left parentheses location + /// * The right parentheses location + /// * The locations of each of the argument labels. + const void *LocationInfo; + + /// The number of argument labels stored in the name. + unsigned NumArgumentLabels; + + enum { + BaseNameIndex = 0, + LParenIndex = 1, + RParenIndex = 2, + FirstArgumentLabelIndex = 3, + }; + + /// Retrieve a pointer to either the only source location that was + /// stored or to the array of source locations that was stored. + SourceLoc const * getSourceLocs() const { + if (NumArgumentLabels == 0) + return reinterpret_cast(&LocationInfo); + + return reinterpret_cast(LocationInfo); + } + +public: + /// Create an invalid declaration name location. + DeclNameLoc() : LocationInfo(0), NumArgumentLabels(0) { } + + /// Create declaration name location information for a base name. + explicit DeclNameLoc(SourceLoc baseNameLoc) + : LocationInfo(baseNameLoc.getOpaquePointerValue()), + NumArgumentLabels(0) { } + + /// Create declaration name location information for a compound + /// name. + DeclNameLoc(ASTContext &ctx, SourceLoc baseNameLoc, + SourceLoc lParenLoc, + ArrayRef argumentLabelLocs, + SourceLoc rParenLoc); + + /// Whether the location information is valid. + bool isValid() const { return getBaseNameLoc().isValid(); } + + /// Whether the location information is invalid. + bool isInvalid() const { return getBaseNameLoc().isInvalid(); } + + /// Retrieve the location of the base name. + SourceLoc getBaseNameLoc() const { + return getSourceLocs()[BaseNameIndex]; + } + + /// Retrieve the location of the left parentheses. + SourceLoc getLParenLoc() const { + if (NumArgumentLabels == 0) return SourceLoc(); + return getSourceLocs()[LParenIndex]; + } + + /// Retrieve the location of the right parentheses. + SourceLoc getRParenLoc() const { + if (NumArgumentLabels == 0) return SourceLoc(); + return getSourceLocs()[RParenIndex]; + } + + /// Retrieve the location of an argument label. + SourceLoc getArgumentLabelLoc(unsigned index) const { + if (index >= NumArgumentLabels) + return SourceLoc(); + return getSourceLocs()[FirstArgumentLabelIndex + index]; + } + + /// Retrieve the complete source range for this declaration name. + SourceRange getSourceRange() const { + if (NumArgumentLabels == 0) return getBaseNameLoc(); + + return SourceRange(getBaseNameLoc(), getRParenLoc()); + } +}; + +} + +#endif // SWIFT_AST_DECL_NAME_LOC_H diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 9f349abd502ac..d1cbbf47ccb73 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -1,8 +1,8 @@ -//===-- DeclNodes.def - Swift Declaration AST Metaprogramming -*- C++ -*-===// +//===--- DeclNodes.def - Swift Declaration AST Metaprogramming --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/DefaultArgumentKind.h b/include/swift/AST/DefaultArgumentKind.h index a53a88d3e346f..14ef3124b60f5 100644 --- a/include/swift/AST/DefaultArgumentKind.h +++ b/include/swift/AST/DefaultArgumentKind.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,10 +17,16 @@ #ifndef SWIFT_DEFAULTARGUMENTKIND_H #define SWIFT_DEFAULTARGUMENTKIND_H +namespace llvm { +class StringRef; +} + namespace swift { +class Expr; + /// Describes the kind of default argument a tuple pattern element has. -enum class DefaultArgumentKind { +enum class DefaultArgumentKind : unsigned { /// No default argument. None, /// A normal default argument. @@ -38,8 +44,22 @@ enum class DefaultArgumentKind { Function, /// The __DSO_HANDLE__ default argument, which is expanded at the call site. DSOHandle, + /// The "nil" literal. + Nil, + /// An empty array literal. + EmptyArray, + /// An empty dictionary literal. + EmptyDictionary, }; +/// Retrieve the spelling of this default argument in source code, or +/// an empty string if it has none. +llvm::StringRef getDefaultArgumentSpelling(DefaultArgumentKind kind); + +/// Infer a default argument kind from an expression, if the +/// expression is the canonical way to spell that default argument. +DefaultArgumentKind inferDefaultArgumentKind(Expr *expr); + } // end namespace swift #endif // LLVM_SWIFT_DEFAULTARGUMENTKIND_H diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 1331f8bdb1d98..fa260b304de5e 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -1,8 +1,8 @@ -//===- DiagnosticEngine.h - Diagnostic Display Engine -----------*- C++ -*-===// +//===--- DiagnosticEngine.h - Diagnostic Display Engine ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,18 +18,9 @@ #ifndef SWIFT_BASIC_DIAGNOSTICENGINE_H #define SWIFT_BASIC_DIAGNOSTICENGINE_H -#include "swift/Basic/LLVM.h" -#include "swift/AST/Identifier.h" -#include "swift/AST/Type.h" #include "swift/AST/TypeLoc.h" +#include "swift/AST/DeclNameLoc.h" #include "swift/Basic/DiagnosticConsumer.h" -#include "swift/Basic/SourceLoc.h" -#include "clang/Basic/VersionTuple.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringRef.h" -#include -#include namespace swift { class Decl; @@ -388,6 +379,84 @@ namespace swift { return fixItReplaceChars(Start, End, {}); } }; + + /// \brief Class to track, map, and remap diagnostic severity and fatality + /// + class DiagnosticState { + public: + /// \brief Describes the current behavior to take with a diagnostic + enum class Behavior : uint8_t { + Unspecified, + Ignore, + Note, + Warning, + Error, + Fatal, + }; + + private: + /// \brief Whether we should continue to emit diagnostics, even after a + /// fatal error + bool showDiagnosticsAfterFatalError = false; + + /// \brief Don't emit any warnings + bool suppressWarnings = false; + + /// \brief Emit all warnings as errors + bool warningsAsErrors = false; + + /// \brief Whether a fatal error has occurred + bool fatalErrorOccurred = false; + + /// \brief Whether any error diagnostics have been emitted. + bool anyErrorOccurred = false; + + /// \brief Track the previous emitted Behavior, useful for notes + Behavior previousBehavior = Behavior::Unspecified; + + /// \brief Track settable, per-diagnostic state that we store + std::vector perDiagnosticBehavior; + + public: + DiagnosticState(); + + /// \brief Figure out the Behavior for the given diagnostic, taking current + /// state such as fatality into account. + Behavior determineBehavior(DiagID id); + + bool hadAnyError() const { return anyErrorOccurred; } + bool hasFatalErrorOccurred() const { return fatalErrorOccurred; } + + void setShowDiagnosticsAfterFatalError(bool val = true) { + showDiagnosticsAfterFatalError = val; + } + + /// \brief Whether to skip emitting warnings + void setSuppressWarnings(bool val) { suppressWarnings = val; } + bool getSuppressWarnings() const { return suppressWarnings; } + + /// \brief Whether to treat warnings as errors + void setWarningsAsErrors(bool val) { warningsAsErrors = val; } + bool getWarningsAsErrors() const { return warningsAsErrors; } + + void resetHadAnyError() { + anyErrorOccurred = false; + fatalErrorOccurred = false; + } + + /// Set per-diagnostic behavior + void setDiagnosticBehavior(DiagID id, Behavior behavior) { + perDiagnosticBehavior[(unsigned)id] = behavior; + } + + private: + // Make the state movable only + DiagnosticState(const DiagnosticState &) = delete; + const DiagnosticState &operator=(const DiagnosticState &) = delete; + + DiagnosticState(DiagnosticState &&) = default; + DiagnosticState &operator=(DiagnosticState &&) = default; + }; /// \brief Class responsible for formatting diagnostics and presenting them /// to the user. @@ -400,19 +469,8 @@ namespace swift { /// emitting diagnostics. SmallVector Consumers; - /// HadAnyError - True if any error diagnostics have been emitted. - bool HadAnyError; - - enum class FatalErrorState { - None, - JustEmitted, - Fatal - }; - - /// Sticky flag set to \c true when a fatal error is emitted. - FatalErrorState FatalState = FatalErrorState::None; - - bool ShowDiagnosticsAfterFatalError = false; + /// \brief Tracks diagnostic behaviors and state + DiagnosticState state; /// \brief The currently active diagnostic, if there is one. Optional ActiveDiagnostic; @@ -434,25 +492,38 @@ namespace swift { public: explicit DiagnosticEngine(SourceManager &SourceMgr) - : SourceMgr(SourceMgr), HadAnyError(false), ActiveDiagnostic() { + : SourceMgr(SourceMgr), ActiveDiagnostic() { } /// hadAnyError - return true if any *error* diagnostics have been emitted. - bool hadAnyError() const { - return HadAnyError; - } + bool hadAnyError() const { return state.hadAnyError(); } bool hasFatalErrorOccurred() const { - return FatalState != FatalErrorState::None; + return state.hasFatalErrorOccurred(); + } + + void setShowDiagnosticsAfterFatalError(bool val = true) { + state.setShowDiagnosticsAfterFatalError(val); + } + + /// \brief Whether to skip emitting warnings + void setSuppressWarnings(bool val) { state.setSuppressWarnings(val); } + bool getSuppressWarnings() const { + return state.getSuppressWarnings(); + } + + /// \brief Whether to treat warnings as errors + void setWarningsAsErrors(bool val) { state.setWarningsAsErrors(val); } + bool getWarningsAsErrors() const { + return state.getWarningsAsErrors(); } - void setShowDiagnosticsAfterFatalError(bool Val = true) { - ShowDiagnosticsAfterFatalError = Val; + void ignoreDiagnostic(DiagID id) { + state.setDiagnosticBehavior(id, DiagnosticState::Behavior::Ignore); } void resetHadAnyError() { - HadAnyError = false; - FatalState = FatalErrorState::None; + state.resetHadAnyError(); } /// \brief Add an additional DiagnosticConsumer to receive diagnostics. @@ -489,6 +560,24 @@ namespace swift { return InFlightDiagnostic(*this); } + /// \brief Emit a diagnostic using a preformatted array of diagnostic + /// arguments. + /// + /// \param Loc The declaration name location to which the + /// diagnostic refers in the source code. + /// + /// \param ID The diagnostic ID. + /// + /// \param Args The preformatted set of diagnostic arguments. The caller + /// must ensure that the diagnostic arguments have the appropriate type. + /// + /// \returns An in-flight diagnostic, to which additional information can + /// be attached. + InFlightDiagnostic diagnose(DeclNameLoc Loc, DiagID ID, + ArrayRef Args) { + return diagnose(Loc.getBaseNameLoc(), ID, Args); + } + /// \brief Emit an already-constructed diagnostic at the given location. /// /// \param Loc The location to which the diagnostic refers in the source @@ -524,6 +613,25 @@ namespace swift { return InFlightDiagnostic(*this); } + /// \brief Emit a diagnostic with the given set of diagnostic arguments. + /// + /// \param Loc The declaration name location to which the + /// diagnostic refers in the source code. + /// + /// \param ID The diagnostic to be emitted. + /// + /// \param Args The diagnostic arguments, which will be converted to + /// the types expected by the diagnostic \p ID. + template + InFlightDiagnostic + diagnose(DeclNameLoc Loc, Diag ID, + typename detail::PassArgument::type... Args) { + assert(!ActiveDiagnostic && "Already have an active diagnostic"); + ActiveDiagnostic = Diagnostic(ID, std::move(Args)...); + ActiveDiagnostic->setLoc(Loc.getBaseNameLoc()); + return InFlightDiagnostic(*this); + } + /// \brief Emit a diagnostic using a preformatted array of diagnostic /// arguments. /// @@ -582,10 +690,7 @@ namespace swift { /// \returns true if diagnostic is marked with PointsToFirstBadToken /// option. - bool isDiagnosticPointsToFirstBadToken(DiagID ID) const; - - /// \returns true if diagnostic is marked as fatal. - bool isDiagnosticFatal(DiagID ID) const; + bool isDiagnosticPointsToFirstBadToken(DiagID id) const; private: /// \brief Flush the active diagnostic. diff --git a/include/swift/AST/DiagnosticsAll.def b/include/swift/AST/DiagnosticsAll.def index d808b5ea6b84c..f8c337b278442 100644 --- a/include/swift/AST/DiagnosticsAll.def +++ b/include/swift/AST/DiagnosticsAll.def @@ -1,8 +1,8 @@ -//===- DiagnosticsAll.def - Diagnostics Text Index --------------*- C++ -*-===// +//===--- DiagnosticsAll.def - Diagnostics Text Index ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,18 +19,18 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif #define DIAG_NO_UNDEF diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 9371fc5ed01b1..4226cfa2eb376 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -1,8 +1,8 @@ -//===- DiagnosticsClangImporter.def - Diagnostics Text ----------*- C++ -*-===// +//===--- DiagnosticsClangImporter.def - Diagnostics Text --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,39 +22,39 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -WARNING(warning_from_clang,none,none, +WARNING(warning_from_clang,none, "%0", (StringRef)) -ERROR(error_from_clang,none,none, +ERROR(error_from_clang,none, "%0", (StringRef)) -NOTE(note_from_clang,none,none, +NOTE(note_from_clang,none, "%0", (StringRef)) -ERROR(clang_cannot_build_module,none,Fatal, +ERROR(clang_cannot_build_module,Fatal, "could not build Objective-C module '%0'", (StringRef)) -ERROR(bridging_header_missing,none,Fatal, +ERROR(bridging_header_missing,Fatal, "bridging header '%0' does not exist", (StringRef)) -ERROR(bridging_header_error,none,Fatal, +ERROR(bridging_header_error,Fatal, "failed to import bridging header '%0'", (StringRef)) -WARNING(could_not_rewrite_bridging_header,none,none, +WARNING(could_not_rewrite_bridging_header,none, "failed to serialize bridging header; " "target may not be debuggable outside of its original project", ()) -WARNING(invalid_swift_name_method,none,none, +WARNING(invalid_swift_name_method,none, "too %select{few|many}0 parameters in swift_name attribute (expected %1; " "got %2)", (bool, unsigned, unsigned)) diff --git a/include/swift/AST/DiagnosticsClangImporter.h b/include/swift/AST/DiagnosticsClangImporter.h index 754beefa0ba55..280c790f1a5e3 100644 --- a/include/swift/AST/DiagnosticsClangImporter.h +++ b/include/swift/AST/DiagnosticsClangImporter.h @@ -1,8 +1,8 @@ -//===- DiagnosticsClangImporter.h - Diagnostic Definitions ------*- C++ -*-===// +//===--- DiagnosticsClangImporter.h - Diagnostic Definitions ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsClangImporter.def" } diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 7004c58209a8a..841c6e3a500da 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -1,8 +1,8 @@ -//===- DiagnosticsCommon.def - Diagnostics Text -----------------*- C++ -*-===// +//===--- DiagnosticsCommon.def - Diagnostics Text ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,69 +22,63 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -ERROR(invalid_diagnostic,common,none, +ERROR(invalid_diagnostic,none, "INTERNAL ERROR: this diagnostic should not be produced", ()) -ERROR(not_implemented,TODO,none, +ERROR(not_implemented,none, "INTERNAL ERROR: feature not implemented: %0", (StringRef)) -ERROR(error_opening_output,common,none, +ERROR(error_opening_output,none, "error opening '%0' for output: %1", (StringRef, StringRef)) -NOTE(previous_decldef,common,none, +NOTE(previous_decldef,none, "previous %select{declaration|definition}0 of %1 is here", (bool, Identifier)) // Generic disambiguation -NOTE(while_parsing_as_left_angle_bracket,common,none, +NOTE(while_parsing_as_left_angle_bracket,none, "while parsing this '<' as a type parameter bracket", ()) -NOTE(while_parsing_as_less_operator,common,none, +NOTE(while_parsing_as_less_operator,none, "while parsing this '<' as an operator", ()) // FIXME: This is used both as a parse error (a literal "super" outside a // method) and a type-checker error ("super" in a method of a non-class type). -ERROR(super_not_in_class_method,common,none, +ERROR(super_not_in_class_method,none, "'super' cannot be used outside of class members", ()) -ERROR(class_func_not_in_class,common,none, +ERROR(class_func_not_in_class,none, "class methods are only allowed within classes; " "use 'static' to declare a static method", ()) -ERROR(class_var_not_in_class,common,none, +ERROR(class_var_not_in_class,none, "class properties are only allowed within classes; " "use 'static' to declare a static property", ()) // FIXME: Used by both the parser and the type-checker. -ERROR(func_decl_without_brace,decl_parsing,PointsToFirstBadToken, +ERROR(func_decl_without_brace,PointsToFirstBadToken, "expected '{' in body of function declaration", ()) -ERROR(unsupported_fixed_length_array,type_parsing,none, - "fixed-length arrays are not yet supported", ()) -ERROR(new_array_syntax,type_parsing,none, - "array types are now written with the brackets around the element type", - ()) - -NOTE(convert_let_to_var,sema,none, +NOTE(convert_let_to_var,none, "change 'let' to 'var' to make it mutable", ()) -NOTE(change_let_to_var_param,sema,none, +NOTE(change_let_to_var_param,none, "change 'let' parameter to 'var' to make it mutable", ()) -NOTE(mark_param_var,sema,none, +NOTE(mark_param_var,none, "mark parameter with 'var' to make it mutable", ()) diff --git a/include/swift/AST/DiagnosticsCommon.h b/include/swift/AST/DiagnosticsCommon.h index cec28f3c3d76b..3bce585013bbd 100644 --- a/include/swift/AST/DiagnosticsCommon.h +++ b/include/swift/AST/DiagnosticsCommon.h @@ -1,8 +1,8 @@ -//===- DiagnosticsCommon.h - Shared Diagnostic Definitions ------*- C++ -*-===// +//===--- DiagnosticsCommon.h - Shared Diagnostic Definitions ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -46,7 +46,7 @@ namespace swift { using DeclAttribute = const DeclAttribute *; // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsCommon.def" } diff --git a/include/swift/AST/DiagnosticsDriver.def b/include/swift/AST/DiagnosticsDriver.def index 15cc058c5c683..a8bd1c035332c 100644 --- a/include/swift/AST/DiagnosticsDriver.def +++ b/include/swift/AST/DiagnosticsDriver.def @@ -1,8 +1,8 @@ -//===- DiagnosticsDriver.def - Diagnostics Text -----------------*- C++ -*-===// +//===--- DiagnosticsDriver.def - Diagnostics Text ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,98 +23,102 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -WARNING(warning_parallel_execution_not_supported,driver,none, +WARNING(warning_parallel_execution_not_supported,none, "parallel execution not supported; falling back to serial execution", ()) -ERROR(error_unable_to_execute_command,driver,none, +ERROR(error_unable_to_execute_command,none, "unable to execute command: %0", (StringRef)) -ERROR(error_command_signalled,driver,none, +ERROR(error_command_signalled,none, "%0 command failed due to signal (use -v to see invocation)", (StringRef)) -ERROR(error_command_failed,driver,none, +ERROR(error_command_failed,none, "%0 command failed with exit code %1 (use -v to see invocation)", (StringRef, int)) -ERROR(error_expected_one_frontend_job,driver,none, +ERROR(error_expected_one_frontend_job,none, "unable to handle compilation, expected exactly one frontend job", ()) -ERROR(error_expected_frontend_command,driver,none, +ERROR(error_expected_frontend_command,none, "expected a swift frontend command", ()) -ERROR(error_cannot_specify__o_for_multiple_outputs,driver,none, +ERROR(error_cannot_specify__o_for_multiple_outputs,none, "cannot specify -o when generating multiple output files", ()) -ERROR(error_unable_to_load_output_file_map,driver, none, +ERROR(error_unable_to_load_output_file_map, none, "unable to load output file map", ()) -ERROR(error_no_output_file_map_specified,driver,none, +ERROR(error_no_output_file_map_specified,none, "no output file map specified", ()) -ERROR(error_unable_to_make_temporary_file,driver,none, +ERROR(error_unable_to_make_temporary_file,none, "unable to make temporary file: %0", (StringRef)) -ERROR(error_no_input_files,driver,none, +ERROR(error_no_input_files,none, "no input files", ()) -ERROR(error_unexpected_input_file,driver,none, +ERROR(error_unexpected_input_file,none, "unexpected input file: %0", (StringRef)) -ERROR(error_unknown_target,driver,none, +ERROR(error_unknown_target,none, "unknown target '%0'", (StringRef)) -ERROR(error_framework_bridging_header,driver,none, - "using bridging headers with framework targets is unsupported", ()) +ERROR(error_framework_bridging_header,none, + "using bridging headers with framework targets is unsupported", ()) -ERROR(error_i_mode,driver,none, +ERROR(error_i_mode,none, "the flag '-i' is no longer required and has been removed; " "use '%0 input-filename'", (StringRef)) -WARNING(warning_unnecessary_repl_mode,driver,none, +WARNING(warning_unnecessary_repl_mode,none, "unnecessary option '%0'; this is the default for '%1' " "with no input files", (StringRef, StringRef)) -ERROR(error_unsupported_option,driver,none, +ERROR(error_unsupported_option,none, "unsupported option '%0' for '%1'; did you mean '%2 %0'?", (StringRef, StringRef, StringRef)) -WARNING(incremental_requires_output_file_map,driver,none, +WARNING(incremental_requires_output_file_map,none, "ignoring -incremental (currently requires an output file map)", ()) -WARNING(incremental_requires_build_record_entry,driver,none, +WARNING(incremental_requires_build_record_entry,none, "ignoring -incremental; output file map has no master dependencies " "entry (\"%0\" under \"\")", (StringRef)) -ERROR(error_os_minimum_deployment,driver,none, +ERROR(error_os_minimum_deployment,none, "Swift requires a minimum deployment target of %0", (StringRef)) -ERROR(error_sdk_too_old,driver,none, +ERROR(error_sdk_too_old,none, "Swift does not support the SDK '%0'", (StringRef)) -ERROR(error_two_files_same_name,driver,none, +ERROR(error_two_files_same_name,none, "filename \"%0\" used twice: '%1' and '%2'", (StringRef, StringRef, StringRef)) -NOTE(note_explain_two_files_same_name,driver,none, +NOTE(note_explain_two_files_same_name,none, "filenames are used to distinguish private declarations with the same " "name", ()) -WARNING(warn_cannot_stat_input,driver,none, +WARNING(warn_cannot_stat_input,none, "unable to determine when '%0' was last modified: %1", (StringRef, StringRef)) -ERROR(error_input_changed_during_build,driver,none, +ERROR(error_input_changed_during_build,none, "input file '%0' was modified during the build", (StringRef)) +ERROR(error_conflicting_options, none, + "conflicting options '%0' and '%1'", + (StringRef, StringRef)) + #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/include/swift/AST/DiagnosticsDriver.h b/include/swift/AST/DiagnosticsDriver.h index 133eb7c337435..a2d1a5385fe67 100644 --- a/include/swift/AST/DiagnosticsDriver.h +++ b/include/swift/AST/DiagnosticsDriver.h @@ -1,8 +1,8 @@ -//===- DiagnosticsDriver.h - Diagnostic Definitions -------------*- C++ -*-===// +//===--- DiagnosticsDriver.h - Diagnostic Definitions -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,7 +25,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsDriver.def" } diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 683c66bdb4b60..124a3c49de582 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -1,8 +1,8 @@ -//===- DiagnosticsFrontend.def - Diagnostics Text ---------------*- C++ -*-===// +//===--- DiagnosticsFrontend.def - Diagnostics Text -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,116 +23,114 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -WARNING(warning_no_such_sdk,frontend,none, +WARNING(warning_no_such_sdk,none, "no such SDK: '%0'", (StringRef)) -ERROR(error_no_frontend_args, frontend, none, +ERROR(error_no_frontend_args, none, "no arguments provided to '-frontend'", ()) -ERROR(error_no_such_file_or_directory,frontend,none, +ERROR(error_no_such_file_or_directory,none, "no such file or directory: '%0'", (StringRef)) -ERROR(error_unsupported_target_os, frontend, none, +ERROR(error_unsupported_target_os, none, "unsupported target OS: '%0'", (StringRef)) -ERROR(error_unsupported_target_arch, frontend, none, +ERROR(error_unsupported_target_arch, none, "unsupported target architecture: '%0'", (StringRef)) -ERROR(cannot_open_file,frontend,none, +ERROR(cannot_open_file,none, "cannot open file '%0' (%1)", (StringRef, StringRef)) -ERROR(cannot_open_serialized_file,frontend,none, +ERROR(cannot_open_serialized_file,none, "cannot open file '%0' for diagnostics emission (%1)", (StringRef, StringRef)) -ERROR(error_open_input_file,frontend,none, +ERROR(error_open_input_file,none, "error opening input file '%0' (%1)", (StringRef, StringRef)) -ERROR(error_clang_importer_not_linked_in,frontend,none, - "clang importer not available", ()) -ERROR(error_clang_importer_create_fail,frontend,none, +ERROR(error_clang_importer_create_fail,none, "clang importer creation failed", ()) -ERROR(error_missing_arg_value,frontend,none, +ERROR(error_missing_arg_value,none, "missing argument value for '%0', expected %1 argument(s)", (StringRef, unsigned)) -ERROR(error_unknown_arg,frontend,none, +ERROR(error_unknown_arg,none, "unknown argument: '%0'", (StringRef)) -ERROR(error_invalid_arg_value,frontend,none, +ERROR(error_invalid_arg_value,none, "invalid value '%1' in '%0'", (StringRef, StringRef)) -ERROR(error_immediate_mode_missing_stdlib,frontend,none, +ERROR(error_immediate_mode_missing_stdlib,none, "could not load the swift standard library", ()) -ERROR(error_immediate_mode_missing_library,frontend,none, +ERROR(error_immediate_mode_missing_library,none, "could not load %select{shared library|framework}0 '%1'", (unsigned, StringRef)) -ERROR(error_immediate_mode_primary_file,frontend,none, +ERROR(error_immediate_mode_primary_file,none, "immediate mode is incompatible with -primary-file", ()) -ERROR(error_missing_frontend_action,frontend,none, +ERROR(error_missing_frontend_action,none, "no frontend action was selected", ()) -ERROR(error_mode_cannot_emit_dependencies,frontend,none, +ERROR(error_mode_cannot_emit_dependencies,none, "this mode does not support emitting dependency files", ()) -ERROR(error_mode_cannot_emit_header,frontend,none, +ERROR(error_mode_cannot_emit_header,none, "this mode does not support emitting Objective-C headers", ()) -ERROR(error_mode_cannot_emit_module,frontend,none, +ERROR(error_mode_cannot_emit_module,none, "this mode does not support emitting modules", ()) -ERROR(error_mode_cannot_emit_module_doc,frontend,none, +ERROR(error_mode_cannot_emit_module_doc,none, "this mode does not support emitting module documentation files", ()) -WARNING(emit_reference_dependencies_without_primary_file,frontend,none, +WARNING(emit_reference_dependencies_without_primary_file,none, "ignoring -emit-reference-dependencies (requires -primary-file)", ()) -ERROR(error_bad_module_name,frontend,none, +ERROR(error_bad_module_name,none, "module name \"%0\" is not a valid identifier" "%select{|; use -module-name flag to specify an alternate name}1", (StringRef, bool)) -ERROR(error_stdlib_module_name,frontend,none, +ERROR(error_stdlib_module_name,none, "module name \"%0\" is reserved for the standard library" "%select{|; use -module-name flag to specify an alternate name}1", (StringRef, bool)) -ERROR(error_stdlib_not_found,frontend,Fatal, +ERROR(error_stdlib_not_found,Fatal, "unable to load standard library for target '%0'", (StringRef)) -ERROR(error_underlying_module_not_found,frontend,none, +ERROR(error_underlying_module_not_found,none, "underlying Objective-C module %0 not found", (Identifier)) -ERROR(error_repl_requires_no_input_files,frontend,none, +ERROR(error_repl_requires_no_input_files,none, "REPL mode requires no input files", ()) -ERROR(error_mode_requires_one_input_file,frontend,none, +ERROR(error_mode_requires_one_input_file,none, "this mode requires a single input file", ()) -ERROR(error_mode_requires_an_input_file,frontend,none, +ERROR(error_mode_requires_an_input_file,none, "this mode requires at least one input file", ()) -ERROR(error_mode_requires_one_sil_multi_sib,frontend,none, +ERROR(error_mode_requires_one_sil_multi_sib,none, "this mode requires .sil for primary-file and only .sib for other inputs", ()) -ERROR(error_no_output_filename_specified,frontend,none, +ERROR(error_no_output_filename_specified,none, "an output filename was not specified for a mode which requires an output " "filename", ()) -ERROR(error_implicit_output_file_is_directory,frontend,none, +ERROR(error_implicit_output_file_is_directory,none, "the implicit output file '%0' is a directory; explicitly specify a filename " "using -o", (StringRef)) -ERROR(repl_must_be_initialized,sema,none, +ERROR(repl_must_be_initialized,none, "variables currently must have an initial value when entered at the " "top level of the REPL", ()) -ERROR(error_doing_code_completion,frontend,none, +ERROR(error_doing_code_completion,none, "compiler is in code completion mode (benign diagnostic)", ()) -ERROR(verify_encountered_fatal,frontend,none, +ERROR(verify_encountered_fatal,none, "fatal error encountered while in -verify mode", ()) -ERROR(error_parse_input_file,frontend,none, +ERROR(error_parse_input_file,none, "error parsing input file '%0' (%1)", (StringRef, StringRef)) #ifndef DIAG_NO_UNDEF diff --git a/include/swift/AST/DiagnosticsFrontend.h b/include/swift/AST/DiagnosticsFrontend.h index 9fc1b3d98fdef..26eeb6028ae03 100644 --- a/include/swift/AST/DiagnosticsFrontend.h +++ b/include/swift/AST/DiagnosticsFrontend.h @@ -1,8 +1,8 @@ -//===- DiagnosticsFrontend.h - Diagnostic Definitions -----------*- C++ -*-===// +//===--- DiagnosticsFrontend.h - Diagnostic Definitions ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsFrontend.def" } diff --git a/include/swift/AST/DiagnosticsIRGen.def b/include/swift/AST/DiagnosticsIRGen.def index 8eb159a901d92..0e149387e2865 100644 --- a/include/swift/AST/DiagnosticsIRGen.def +++ b/include/swift/AST/DiagnosticsIRGen.def @@ -1,8 +1,8 @@ -//===- DiagnosticsIRGen.def - Diagnostics Text ------------------*- C++ -*-===// +//===--- DiagnosticsIRGen.def - Diagnostics Text ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,45 +22,45 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -ERROR(no_llvm_target,irgen,none, +ERROR(no_llvm_target,none, "error loading LLVM target for triple '%0': %1", (StringRef, StringRef)) -ERROR(error_codegen_init_fail,irgen,none, +ERROR(error_codegen_init_fail,none, "cannot initialize code generation passes for target", ()) -ERROR(irgen_unimplemented,irgen,none, +ERROR(irgen_unimplemented,none, "unimplemented IR generation feature %0", (StringRef)) -ERROR(irgen_failure,irgen,none, "IR generation failure: %0", (StringRef)) +ERROR(irgen_failure,none, "IR generation failure: %0", (StringRef)) -ERROR(type_to_verify_not_found,irgen,none, "unable to find type '%0' to verify", +ERROR(type_to_verify_not_found,none, "unable to find type '%0' to verify", (StringRef)) -ERROR(type_to_verify_ambiguous,irgen,none, "type to verify '%0' is ambiguous", +ERROR(type_to_verify_ambiguous,none, "type to verify '%0' is ambiguous", (StringRef)) -ERROR(type_to_verify_dependent,irgen,none, +ERROR(type_to_verify_dependent,none, "type to verify '%0' has unbound generic parameters", (StringRef)) -ERROR(too_few_output_filenames,irgen,none, +ERROR(too_few_output_filenames,none, "too few output file names specified", ()) -ERROR(no_input_files_for_mt,irgen,none, +ERROR(no_input_files_for_mt,none, "no swift input files for multi-threaded compilation", ()) -ERROR(alignment_dynamic_type_layout_unsupported,irgen,none, +ERROR(alignment_dynamic_type_layout_unsupported,none, "@_alignment is not supported on types with dynamic layout", ()) -ERROR(alignment_less_than_natural,irgen,none, +ERROR(alignment_less_than_natural,none, "@_alignment cannot decrease alignment below natural alignment of %0", (unsigned)) diff --git a/include/swift/AST/DiagnosticsIRGen.h b/include/swift/AST/DiagnosticsIRGen.h index 13a46d7be2343..928bcb6a5b45d 100644 --- a/include/swift/AST/DiagnosticsIRGen.h +++ b/include/swift/AST/DiagnosticsIRGen.h @@ -1,8 +1,8 @@ -//===- DiagnosticsIRGen.h - Diagnostic Definitions --------------*- C++ -*-===// +//===--- DiagnosticsIRGen.h - Diagnostic Definitions ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsIRGen.def" } diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 3cbd855a324fd..133557e90db5b 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1,8 +1,8 @@ -//===- DiagnosticsParse.def - Diagnostics Text ------------------*- C++ -*-===// +//===--- DiagnosticsParse.def - Diagnostics Text ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,1248 +22,1255 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif //============================================================================== // Lexing and Parsing diagnostics //============================================================================== -NOTE(opening_brace,parsing,none, +NOTE(opening_brace,none, "to match this opening '{'", ()) -NOTE(opening_bracket,parsing,none, +NOTE(opening_bracket,none, "to match this opening '['", ()) -NOTE(opening_paren,parsing,none, +NOTE(opening_paren,none, "to match this opening '('", ()) -NOTE(opening_angle,parsing,none, +NOTE(opening_angle,none, "to match this opening '<'", ()) -ERROR(extra_rbrace,parsing,none, +ERROR(extra_rbrace,none, "extraneous '}' at top level", ()) -ERROR(unexpected_config_block_terminator,parsing,none, +ERROR(unexpected_config_block_terminator,none, "unexpected configuration block terminator", ()) -ERROR(expected_build_configuration_expression,parsing,none, +ERROR(expected_build_configuration_expression,none, "expected a build configuration expression to follow the #if clause", ()) -ERROR(extra_tokens_config_directive,parsing,none, +ERROR(extra_tokens_config_directive,none, "extra tokens at the end of the build configuration directive", ()) -ERROR(unexpected_line_directive,parsing,none, +ERROR(unexpected_line_directive,none, "parameterless closing #line directive " "without prior opening #line directive", ()) -ERROR(expected_line_directive_number,parsing,none, +ERROR(expected_line_directive_number,none, "expected starting line number for #line directive", ()) -ERROR(expected_line_directive_name,parsing,none, +ERROR(expected_line_directive_name,none, "expected filename string literal for #line directive", ()) -ERROR(extra_tokens_line_directive,parsing,none, +ERROR(extra_tokens_line_directive,none, "extra tokens at the end of #line directive", ()) -ERROR(line_directive_line_zero,parsing,none, +ERROR(line_directive_line_zero,none, "the line number needs to be greater than zero", ()) +WARNING(escaped_parameter_name,none, + "keyword '%0' does not need to be escaped in argument list", + (StringRef)) + //------------------------------------------------------------------------------ // Lexer diagnostics //------------------------------------------------------------------------------ -WARNING(lex_nul_character,lexing,none, +WARNING(lex_nul_character,none, "nul character embedded in middle of file", ()) -ERROR(lex_utf16_bom_marker,lexing,none, +ERROR(lex_utf16_bom_marker,none, "input files must be encoded as UTF-8 instead of UTF-16", ()) -ERROR(lex_hashbang_not_allowed,lexing,none, +ERROR(lex_hashbang_not_allowed,none, "hashbang line is allowed only in the main file", ()) -ERROR(lex_unprintable_ascii_character,lexing,none, +ERROR(lex_unprintable_ascii_character,none, "unprintable ASCII character found in source file", ()) -ERROR(lex_invalid_utf8,lexing,none, +ERROR(lex_invalid_utf8,none, "invalid UTF-8 found in source file", ()) -ERROR(lex_single_quote_string,lexing,none, +ERROR(lex_single_quote_string,none, "single-quoted string literal found, use '\"'", ()) -ERROR(lex_invalid_curly_quote,lexing,none, +ERROR(lex_invalid_curly_quote,none, "unicode curly quote found, replace with '\"'", ()) -ERROR(lex_unterminated_block_comment,lexing,none, +ERROR(lex_unterminated_block_comment,none, "unterminated '/*' comment", ()) -NOTE(lex_comment_start,lexing,none, +NOTE(lex_comment_start,none, "comment started here", ()) -ERROR(lex_unterminated_string,lexing,none, +ERROR(lex_unterminated_string,none, "unterminated string literal", ()) -ERROR(lex_invalid_escape,lexing,none, +ERROR(lex_invalid_escape,none, "invalid escape sequence in literal", ()) -ERROR(lex_invalid_u_escape,lexing,none, +ERROR(lex_invalid_u_escape,none, "\\u{...} escape sequence expects between 1 and 8 hex digits", ()) -ERROR(lex_invalid_u_escape_rbrace,lexing,none, +ERROR(lex_invalid_u_escape_rbrace,none, "expected '}' in \\u{...} escape sequence", ()) -ERROR(lex_invalid_unicode_scalar,lexing,none, +ERROR(lex_invalid_unicode_scalar,none, "invalid unicode scalar", ()) -ERROR(lex_unicode_escape_braces,lexing,none, +ERROR(lex_unicode_escape_braces,none, "expected hexadecimal code in braces after unicode escape", ()) -ERROR(lex_invalid_character,lexing,none, +ERROR(lex_invalid_character,none, "invalid character in source file", ()) -ERROR(lex_invalid_identifier_start_character,lexing,none, +ERROR(lex_invalid_identifier_start_character,none, "an identifier cannot begin with this character", ()) -ERROR(lex_expected_digit_in_fp_exponent,lexing,none, +ERROR(lex_expected_digit_in_fp_exponent,none, "expected a digit in floating point exponent", ()) -ERROR(lex_expected_digit_in_int_literal,lexing,none, +ERROR(lex_expected_digit_in_int_literal,none, "expected a digit after integer literal prefix", ()) -ERROR(lex_expected_binary_exponent_in_hex_float_literal,lexing,none, +ERROR(lex_expected_binary_exponent_in_hex_float_literal,none, "hexadecimal floating point literal must end with an exponent", ()) -ERROR(lex_unexpected_block_comment_end,lexing,none, +ERROR(lex_unexpected_block_comment_end,none, "unexpected end of block comment", ()) -ERROR(lex_unary_equal_is_reserved,lexing,none, - "%select{prefix|postfix}0 '=' is reserved", (unsigned)) -ERROR(lex_unary_postfix_dot_is_reserved,lexing,none, - "postfix '.' is reserved", ()) -ERROR(lex_editor_placeholder,lexing,none, +ERROR(lex_unary_equal,none, + "'=' must have consistent whitespace on both sides", ()) +ERROR(extra_whitespace_period,none, + "extraneous whitespace after '.' is not permitted", ()) +ERROR(lex_editor_placeholder,none, "editor placeholder in source file", ()) -WARNING(lex_editor_placeholder_in_playground,lexing,none, +WARNING(lex_editor_placeholder_in_playground,none, "editor placeholder in source file", ()) //------------------------------------------------------------------------------ // Declaration parsing diagnostics //------------------------------------------------------------------------------ -ERROR(declaration_same_line_without_semi,decl_parsing,none, +ERROR(declaration_same_line_without_semi,none, "consecutive declarations on a line must be separated by ';'", ()) -ERROR(expected_decl,decl_parsing,none, +ERROR(expected_decl,none, "expected declaration", ()) -ERROR(expected_identifier_in_decl,decl_parsing,none, +ERROR(expected_identifier_in_decl,none, "expected identifier in %0 declaration", (StringRef)) -ERROR(expected_identifier_after_case_comma,decl_parsing,none, +ERROR(expected_identifier_after_case_comma,none, "expected identifier after comma in enum 'case' declaration", ()) -ERROR(decl_redefinition,decl_parsing,none, +ERROR(decl_redefinition,none, "%select{declaration|definition}0 conflicts with previous value", (bool)) -ERROR(let_cannot_be_computed_property,decl_parsing,none, +ERROR(let_cannot_be_computed_property,none, "'let' declarations cannot be computed properties", ()) -ERROR(let_cannot_be_observing_property,decl_parsing,none, +ERROR(let_cannot_be_observing_property,none, "'let' declarations cannot be observing properties", ()) -ERROR(let_cannot_be_addressed_property,decl_parsing,none, +ERROR(let_cannot_be_addressed_property,none, "'let' declarations cannot have addressors", ()) -ERROR(disallowed_var_multiple_getset,decl_parsing,none, +ERROR(disallowed_var_multiple_getset,none, "'var' declarations with multiple variables cannot have explicit" " getters/setters", ()) -ERROR(disallowed_type,decl_parsing,none, +ERROR(disallowed_type,none, "type not allowed here", ()) -ERROR(disallowed_init,decl_parsing,none, +ERROR(disallowed_init,none, "initial value is not allowed here", ()) -ERROR(var_init_self_referential,expr_parsing,none, +ERROR(var_init_self_referential,none, "variable used within its own initial value", ()) -ERROR(disallowed_enum_element,decl_parsing,none, +ERROR(disallowed_enum_element,none, "enum 'case' is not allowed outside of an enum", ()) -ERROR(decl_inner_scope,decl_parsing,none, +ERROR(decl_inner_scope,none, "declaration is only valid at file scope", ()) -ERROR(decl_not_static,decl_parsing,none, +ERROR(decl_not_static,none, "declaration cannot be marked %0", (StaticSpellingKind)) -ERROR(ownership_not_attribute,decl_parsing,none, - "'@%0' is not an attribute, use the '%0' keyword instead", - (StringRef)) - -ERROR(cskeyword_not_attribute,decl_parsing,none, +ERROR(cskeyword_not_attribute,none, "'%0' is a declaration modifier, not an attribute", (StringRef)) -ERROR(convenience_invalid,sema_tcd,none, - "'convenience' is not valid on this declaration", ()) - -ERROR(decl_already_static,decl_parsing,none, +ERROR(decl_already_static,none, "%0 specified twice", (StaticSpellingKind)) -ERROR(autoclosure_is_decl_attribute,attribute_parsing,none, - "@autoclosure is now an attribute of the parameter " - "declaration, not its type", ()) -ERROR(autoclosure_not_on_enums,attribute_parsing,none, - "@autoclosure is only allowed on parameters, not on enum cases", ()) - -ERROR(enum_case_dot_prefix,decl_parsing,none, +ERROR(enum_case_dot_prefix,none, "extraneous '.' in enum 'case' declaration", ()) // Variable getters/setters -ERROR(static_var_decl_global_scope,decl_parsing,none, +ERROR(static_var_decl_global_scope,none, "%select{ERROR|static properties|class properties}0 may only be declared on a type", (StaticSpellingKind)) -ERROR(computed_property_no_accessors, decl_parsing, none, +ERROR(computed_property_no_accessors, none, "computed property must have accessors specified", ()) -ERROR(expected_getset_in_protocol,decl_parsing,none, +ERROR(expected_getset_in_protocol,none, "expected get or set in a protocol property", ()) -ERROR(computed_property_missing_type,decl_parsing,none, +ERROR(computed_property_missing_type,none, "computed property must have an explicit type", ()) -ERROR(getset_nontrivial_pattern,decl_parsing,none, +ERROR(getset_nontrivial_pattern,none, "getter/setter can only be defined for a single variable", ()) -ERROR(expected_rbrace_in_getset,decl_parsing,none, +ERROR(expected_rbrace_in_getset,none, "expected '}' at end of variable get/set clause", ()) -ERROR(duplicate_property_accessor,decl_parsing,none, +ERROR(duplicate_property_accessor,none, "duplicate definition of %0", (StringRef)) -NOTE(previous_accessor,decl_parsing,none, +NOTE(previous_accessor,none, "previous definition of %0 is here", (StringRef)) -ERROR(conflicting_property_addressor,decl_parsing,none, +ERROR(conflicting_property_addressor,none, "%select{variable|subscript}0 already has a " "%select{addressor|mutable addressor}1", (unsigned, unsigned)) -ERROR(expected_accessor_name,decl_parsing,none, +ERROR(expected_accessor_name,none, "expected %select{GETTER|setter|willSet|didSet}0 parameter name", (unsigned)) -ERROR(expected_rparen_set_name,decl_parsing,none, +ERROR(expected_rparen_set_name,none, "expected ')' after setter parameter name",()) -ERROR(expected_rparen_willSet_name,decl_parsing,none, +ERROR(expected_rparen_willSet_name,none, "expected ')' after willSet parameter name",()) -ERROR(expected_rparen_didSet_name,decl_parsing,none, +ERROR(expected_rparen_didSet_name,none, "expected ')' after didSet parameter name",()) -ERROR(expected_lbrace_accessor,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_accessor,PointsToFirstBadToken, "expected '{' to start %0 definition", (StringRef)) -ERROR(expected_accessor_kw,decl_parsing,none, +ERROR(expected_accessor_kw,none, "expected 'get', 'set', 'willSet', or 'didSet' keyword to " "start an accessor definition",()) -ERROR(var_set_without_get,decl_parsing,none, +ERROR(var_set_without_get,none, "variable with a setter must also have a getter", ()) -ERROR(observingproperty_with_getset,decl_parsing,none, +ERROR(observingproperty_with_getset,none, "%select{willSet|didSet}0 variable may not also have a " "%select{get|set}1 specifier", (unsigned, unsigned)) -ERROR(observingproperty_without_mutableaddress,decl_parsing,none, +ERROR(observingproperty_without_mutableaddress,none, "%select{willSet|didSet}0 variable with addressor must provide a " "'mutableAddress' accessor", (unsigned)) -ERROR(observingproperty_in_subscript,decl_parsing,none, +ERROR(observingproperty_in_subscript,none, "%select{willSet|didSet}0 is not allowed in subscripts", (unsigned)) -ERROR(getset_init,decl_parsing,none, +ERROR(getset_init,none, "variable with getter/setter cannot have an initial value", ()) -ERROR(getset_cannot_be_implied,decl_parsing,none, +ERROR(getset_cannot_be_implied,none, "variable with implied type cannot have implied getter/setter", ()) -ERROR(mutableaddressor_without_address,decl_parsing,none, +ERROR(mutableaddressor_without_address,none, "%select{variable|subscript}0 must provide either a getter or " "'address' if it provides 'mutableAddress'", (unsigned)) -ERROR(mutableaddressor_with_setter,decl_parsing,none, +ERROR(mutableaddressor_with_setter,none, "%select{variable|subscript}0 cannot provide both 'mutableAddress' " " and a setter", (unsigned)) -ERROR(addressor_with_getter,decl_parsing,none, +ERROR(addressor_with_getter,none, "%select{variable|subscript}0 cannot provide both 'address' and " "a getter", (unsigned)) -ERROR(addressor_with_setter,decl_parsing,none, +ERROR(addressor_with_setter,none, "%select{variable|subscript}0 cannot provide both 'address' and " "a setter; use an ordinary getter instead", (unsigned)) // Import -ERROR(decl_expected_module_name,decl_parsing,none, +ERROR(decl_expected_module_name,none, "expected module name in import declaration", ()) // Extension -ERROR(expected_lbrace_extension,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_extension,PointsToFirstBadToken, "expected '{' in extension", ()) -ERROR(expected_rbrace_extension,decl_parsing,none, +ERROR(expected_rbrace_extension,none, "expected '}' at end of extension", ()) -ERROR(extension_type_expected,decl_parse,none, +ERROR(extension_type_expected,none, "expected type name in extension declaration", ()) // TypeAlias -ERROR(expected_equal_in_typealias,decl_parsing,PointsToFirstBadToken, +ERROR(expected_equal_in_typealias,PointsToFirstBadToken, "expected '=' in typealias declaration", ()) -ERROR(expected_type_in_typealias,decl_parsing,PointsToFirstBadToken, +ERROR(expected_type_in_typealias,PointsToFirstBadToken, "expected type in typealias declaration", ()) // Func -ERROR(func_decl_nonglobal_operator,decl_parsing,none, +ERROR(func_decl_nonglobal_operator,none, "operators are only allowed at global scope", ()) -ERROR(func_decl_without_paren,decl_parsing,PointsToFirstBadToken, +ERROR(func_decl_without_paren,PointsToFirstBadToken, "expected '(' in argument list of function declaration", ()) -ERROR(static_func_decl_global_scope,decl_parsing,none, +ERROR(static_func_decl_global_scope,none, "%select{ERROR|static methods|class methods}0 may only be declared on a type", (StaticSpellingKind)) -ERROR(func_decl_expected_arrow,decl_parsing,none, +ERROR(func_decl_expected_arrow,none, "expected '->' after function parameter tuple", ()) -ERROR(func_static_not_allowed,decl_parsing,none, - "static functions are not allowed in this context, " - "use 'class' to declare a class method", ()) -ERROR(func_conversion,decl_parsing,none, - "'__conversion' functions are no longer allowed", ()) // Enum -ERROR(expected_lbrace_enum,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_enum,PointsToFirstBadToken, "expected '{' in enum", ()) -ERROR(expected_rbrace_enum,decl_parsing,none, +ERROR(expected_rbrace_enum,none, "expected '}' at end of enum", ()) // Struct -ERROR(expected_lbrace_struct,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_struct,PointsToFirstBadToken, "expected '{' in struct", ()) -ERROR(expected_rbrace_struct,decl_parsing,none, +ERROR(expected_rbrace_struct,none, "expected '}' in struct", ()) // Class -ERROR(expected_lbrace_class,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_class,PointsToFirstBadToken, "expected '{' in class", ()) -ERROR(expected_rbrace_class,decl_parsing,none, +ERROR(expected_rbrace_class,none, "expected '}' in class", ()) // Protocol -ERROR(generic_arguments_protocol,decl_parsing,PointsToFirstBadToken, +ERROR(generic_arguments_protocol,PointsToFirstBadToken, "protocols do not allow generic parameters; use associated types instead", ()) -ERROR(expected_lbrace_protocol,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_protocol,PointsToFirstBadToken, "expected '{' in protocol type", ()) -ERROR(expected_rbrace_protocol,decl_parsing,none, +ERROR(expected_rbrace_protocol,none, "expected '}' in protocol", ()) -ERROR(protocol_setter_name,decl_parsing,none, +ERROR(protocol_setter_name,none, "setter in a protocol cannot have a name", ()) -ERROR(protocol_method_with_body,decl_parsing,none, +ERROR(protocol_method_with_body,none, "protocol methods may not have bodies", ()) -ERROR(protocol_init_with_body,decl_parsing,none, +ERROR(protocol_init_with_body,none, "protocol initializers may not have bodies", ()) // Subscripting -ERROR(subscript_decl_wrong_scope,decl_parsing,none, +ERROR(subscript_decl_wrong_scope,none, "'subscript' functions may only be declared within a type", ()) -ERROR(expected_lparen_subscript,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lparen_subscript,PointsToFirstBadToken, "expected '(' for subscript parameters", ()) -ERROR(expected_arrow_subscript,decl_parsing,PointsToFirstBadToken, +ERROR(expected_arrow_subscript,PointsToFirstBadToken, "expected '->' for subscript element type", ()) -ERROR(expected_type_subscript,type_parsing,PointsToFirstBadToken, +ERROR(expected_type_subscript,PointsToFirstBadToken, "expected subscripting element type", ()) -ERROR(expected_lbrace_subscript,decl_parsing,PointsToFirstBadToken, - "expected '{' for subscripting", ()) -ERROR(subscript_without_get,decl_parsing,none, +ERROR(expected_lbrace_subscript,PointsToFirstBadToken, + "expected '{' in subscript to specify getter and setter implementation", + ()) +ERROR(expected_lbrace_subscript_protocol,PointsToFirstBadToken, + "subscript in protocol must have explicit { get } or " + "{ get set } specifier", ()) +ERROR(subscript_without_get,none, "subscript declarations must have a getter", ()) -ERROR(subscript_static,decl_parsing,none, +ERROR(subscript_static,none, "subscript cannot be marked %0", (StaticSpellingKind)) // initializer -ERROR(initializer_decl_wrong_scope,decl_parsing,none, +ERROR(initializer_decl_wrong_scope,none, "initializers may only be declared within a type", ()) -ERROR(expected_lparen_initializer,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lparen_initializer,PointsToFirstBadToken, "expected '(' for initializer parameters", ()) // Destructor -ERROR(destructor_decl_outside_class,decl_parsing,none, +ERROR(destructor_decl_outside_class,none, "deinitializers may only be declared within a class", ()) -ERROR(expected_lbrace_destructor,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_destructor,PointsToFirstBadToken, "expected '{' for deinitializer", ()) -ERROR(opened_destructor_expected_rparen,attribute_parsing,none, +ERROR(opened_destructor_expected_rparen,none, "expected ')' to close parameter list", ()) -ERROR(destructor_params,decl_parsing,none, +ERROR(destructor_params,none, "no parameter clause allowed on deinitializer", ()) // Operator -ERROR(operator_decl_inner_scope,decl_parsing,none, +ERROR(operator_decl_inner_scope,none, "'operator' may only be declared at file scope", ()) -ERROR(expected_operator_name_after_operator,decl_parsing,PointsToFirstBadToken, +ERROR(expected_operator_name_after_operator,PointsToFirstBadToken, "expected operator name in operator declaration", ()) -ERROR(operator_decl_no_fixity,decl_parsing,none, +ERROR(identifier_when_expecting_operator,PointsToFirstBadToken, + "%0 is considered to be an identifier, not an operator", (Identifier)) + +ERROR(operator_decl_no_fixity,none, "operator must be declared as 'prefix', 'postfix', or 'infix'", ()) -ERROR(expected_lbrace_after_operator,decl_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_operator,PointsToFirstBadToken, "expected '{' after operator name in 'operator' declaration", ()) -ERROR(expected_operator_attribute,decl_parsing,none, +ERROR(expected_operator_attribute,none, "expected operator attribute identifier in 'operator' declaration body", ()) -ERROR(unknown_prefix_operator_attribute,decl_parsing,none, +ERROR(unknown_prefix_operator_attribute,none, "'%0' is not a valid prefix operator attribute", (StringRef)) -ERROR(unknown_postfix_operator_attribute,decl_parsing,none, +ERROR(unknown_postfix_operator_attribute,none, "'%0' is not a valid postfix operator attribute", (StringRef)) -ERROR(unknown_infix_operator_attribute,decl_parsing,none, +ERROR(unknown_infix_operator_attribute,none, "'%0' is not a valid infix operator attribute", (StringRef)) -ERROR(operator_associativity_redeclared,decl_parsing,none, +ERROR(operator_associativity_redeclared,none, "'associativity' for infix operator declared multiple times", ()) -ERROR(expected_infix_operator_associativity,decl_parsing,none, +ERROR(expected_infix_operator_associativity,none, "expected identifier after 'associativity' in 'operator' declaration body", ()) -ERROR(unknown_infix_operator_associativity,decl_parsing,none, +ERROR(unknown_infix_operator_associativity,none, "'%0' is not a valid infix operator associativity; must be 'none', 'left', or 'right'", (StringRef)) -ERROR(operator_precedence_redeclared,decl_parsing,none, +ERROR(operator_precedence_redeclared,none, "'precedence' for infix operator declared multiple times", ()) -ERROR(operator_assignment_redeclared,decl_parsing,none, +ERROR(operator_assignment_redeclared,none, "'assignment' for infix operator declared multiple times", ()) -ERROR(expected_infix_operator_precedence,decl_parsing,none, +ERROR(expected_infix_operator_precedence,none, "expected integer literal after 'precedence' in 'operator' declaration body", ()) -ERROR(invalid_infix_operator_precedence,decl_parsing,none, +ERROR(invalid_infix_operator_precedence,none, "'precedence' must be in the range of 0 to 255", ()) // SIL -ERROR(inout_not_attribute, decl_parsing, none, +ERROR(inout_not_attribute, none, "@inout is no longer an attribute", ()) -ERROR(only_allowed_in_sil, decl_parsing,none, +ERROR(only_allowed_in_sil,none, "'%0' only allowed in SIL modules", (StringRef)) -ERROR(expected_sil_type, decl_parsing,none, +ERROR(expected_sil_type,none, "expected type in SIL code", ()) -ERROR(expected_sil_colon_value_ref,decl_parsing,none, +ERROR(expected_sil_colon_value_ref,none, "expected ':' before type in SIL value reference", ()) -ERROR(expected_sil_value_name,decl_parsing,none, +ERROR(expected_sil_value_name,none, "expected SIL value name", ()) -ERROR(expected_sil_value_name_result_number,decl_parsing,none, - "expected result number in SIL value name", ()) -ERROR(invalid_sil_value_name_result_number,decl_parsing,none, - "invalid result number in SIL value", ()) -ERROR(expected_sil_type_kind, decl_parsing,none, +ERROR(expected_sil_type_kind,none, "expected SIL type to %0", (StringRef)) -ERROR(expected_sil_constant, decl_parsing,none, +ERROR(expected_sil_constant,none, "expected constant in SIL code", ()) -ERROR(referenced_value_no_accessor, decl_parsing,none, +ERROR(referenced_value_no_accessor,none, "referenced declaration has no %select{getter|setter}0", (unsigned)) -ERROR(sil_local_storage_non_address, decl_parsing,none, - "can only work with the address of local storage", ()) // SIL Values -ERROR(sil_value_redefinition, decl_parsing,none, +ERROR(sil_value_redefinition,none, "redefinition of value '%0'", (StringRef)) -ERROR(sil_value_use_type_mismatch, decl_parsing,none, +ERROR(sil_value_use_type_mismatch,none, "value '%0' defined with mismatching type %1 (expected %2)", (StringRef, Type, Type)) -ERROR(sil_value_def_type_mismatch, decl_parsing,none, +ERROR(sil_value_def_type_mismatch,none, "value '%0' used with mismatching type %1 (expected %2)", (StringRef, Type, Type)) -ERROR(sil_use_of_undefined_value, decl_parsing,none, +ERROR(sil_use_of_undefined_value,none, "use of undefined value '%0'", (StringRef)) -NOTE(sil_prior_reference,parsing,none, +NOTE(sil_prior_reference,none, "prior reference was here", ()) // SIL Instructions -ERROR(expected_sil_instr_start_of_line,decl_parsing,none, +ERROR(expected_sil_instr_start_of_line,none, "SIL instructions must be at the start of a line", ()) -ERROR(expected_equal_in_sil_instr,decl_parsing,none, +ERROR(expected_equal_in_sil_instr,none, "expected '=' in SIL instruction", ()) -ERROR(expected_sil_instr_opcode,decl_parsing,none, +ERROR(expected_sil_instr_opcode,none, "expected SIL instruction opcode", ()) -ERROR(expected_tok_in_sil_instr,decl_parsing,none, +ERROR(expected_tok_in_sil_instr,none, "expected '%0' in SIL instruction", (StringRef)) -ERROR(sil_string_no_encoding,decl_parsing,none, +ERROR(sil_string_no_encoding,none, "string_literal instruction requires an encoding", ()) -ERROR(sil_string_invalid_encoding,decl_parsing,none, +ERROR(sil_string_invalid_encoding,none, "unknown string literal encoding '%0'", (StringRef)) -ERROR(expected_tuple_type_in_tuple,decl_parsing,none, +ERROR(expected_tuple_type_in_tuple,none, "tuple instruction requires a tuple type", ()) -ERROR(sil_tuple_inst_wrong_value_count,decl_parsing,none, +ERROR(sil_tuple_inst_wrong_value_count,none, "tuple instruction requires %0 values", (unsigned)) -ERROR(sil_tuple_inst_wrong_field,decl_parsing,none, +ERROR(sil_tuple_inst_wrong_field,none, "tuple instruction requires a field number", ()) -ERROR(sil_struct_inst_wrong_field,decl_parsing,none, +ERROR(sil_struct_inst_wrong_field,none, "struct instruction requires a field name", ()) -ERROR(sil_ref_inst_wrong_field,decl_parsing,none, +ERROR(sil_ref_inst_wrong_field,none, "ref_element_addr instruction requires a field name", ()) -ERROR(sil_invalid_instr_operands,decl_parsing,none, +ERROR(sil_invalid_instr_operands,none, "invalid instruction operands", ()) -ERROR(sil_operand_not_address,decl_parsing,none, +ERROR(sil_operand_not_address,none, "%0 operand of '%1' must have address type", (StringRef, StringRef)) -ERROR(sil_operand_not_unowned_address,decl_parsing,none, +ERROR(sil_operand_not_unowned_address,none, "%0 operand of '%1' must have address of [unowned] type", (StringRef, StringRef)) -ERROR(sil_operand_not_weak_address,decl_parsing,none, +ERROR(sil_operand_not_weak_address,none, "%0 operand of '%1' must have address of [weak] type", (StringRef, StringRef)) -ERROR(sil_integer_literal_not_integer_type,decl_parsing,none, +ERROR(sil_integer_literal_not_integer_type,none, "integer_literal instruction requires a 'Builtin.Int' type", ()) -ERROR(sil_float_literal_not_float_type,decl_parsing,none, +ERROR(sil_float_literal_not_float_type,none, "float_literal instruction requires a 'Builtin.FP' type", ()) -ERROR(sil_apply_archetype_not_found,decl_parsing,none, - "archetype name not found in polymorphic function type of apply instruction", ()) -ERROR(sil_substitutions_on_non_polymorphic_type,decl_parsing,none, +ERROR(sil_substitutions_on_non_polymorphic_type,none, "apply of non-polymorphic function cannot have substitutions", ()) -ERROR(sil_witness_method_not_protocol,decl_parsing,none, +ERROR(sil_witness_method_not_protocol,none, "witness_method is not a protocol method", ()) -ERROR(sil_witness_method_type_does_not_conform,decl_parsing,none, +ERROR(sil_witness_method_type_does_not_conform,none, "witness_method type does not conform to protocol", ()) -ERROR(sil_witness_archetype_not_found,decl_parsing,none, - "archetype name not found in specialized protocol conformance", ()) -ERROR(sil_member_decl_not_found,decl_parsing,none, +ERROR(sil_member_decl_not_found,none, "member not found in method instructions", ()) -ERROR(sil_member_decl_type_mismatch, decl_parsing,none, +ERROR(sil_member_decl_type_mismatch,none, "member defined with mismatching type %0 (expected %1)", (Type, Type)) -ERROR(sil_substitution_mismatch,decl_parsing,none, +ERROR(sil_substitution_mismatch,none, "substitution conformances dont match archetype", ()) -ERROR(sil_missing_substitutions,decl_parsing,none, +ERROR(sil_missing_substitutions,none, "missing substitutions", ()) -ERROR(sil_too_many_substitutions,decl_parsing,none, +ERROR(sil_too_many_substitutions,none, "too many substitutions", ()) -ERROR(sil_dbg_unknown_key,decl_parsing,none, +ERROR(sil_dbg_unknown_key,none, "unknown key '%0' in debug variable declaration", (StringRef)) // SIL Basic Blocks -ERROR(expected_sil_block_name, decl_parsing,none, +ERROR(expected_sil_block_name,none, "expected basic block name or '}'", ()) -ERROR(expected_sil_block_colon, decl_parsing,none, +ERROR(expected_sil_block_colon,none, "expected ':' after basic block name", ()) -ERROR(sil_undefined_basicblock_use, decl_parsing,none, +ERROR(sil_undefined_basicblock_use,none, "use of undefined basic block %0", (Identifier)) -ERROR(sil_basicblock_redefinition, decl_parsing,none, +ERROR(sil_basicblock_redefinition,none, "redefinition of basic block %0", (Identifier)) -ERROR(sil_basicblock_arg_rparen, decl_parsing,none, +ERROR(sil_basicblock_arg_rparen,none, "expected ')' in basic block argument list", ()) // SIL Functions -ERROR(expected_sil_linkage_or_function, decl_parsing,none, - "expected SIL linkage type or function name", ()) -ERROR(expected_sil_function_name, decl_parsing,none, +ERROR(expected_sil_function_name,none, "expected SIL function name", ()) -ERROR(expected_sil_rbrace, decl_parsing,none, +ERROR(expected_sil_rbrace,none, "expected '}' at the end of a sil body", ()) -ERROR(expected_sil_function_type, decl_parsing, none, +ERROR(expected_sil_function_type, none, "sil function expected to have SIL function type", ()) // SIL Stage -ERROR(expected_sil_stage_name, decl_parsing, none, +ERROR(expected_sil_stage_name, none, "expected 'raw' or 'canonical' after 'sil_stage'", ()) -ERROR(multiple_sil_stage_decls, decl_parsing, none, +ERROR(multiple_sil_stage_decls, none, "sil_stage declared multiple times", ()) // SIL VTable -ERROR(expected_sil_vtable_colon, decl_parsing,none, +ERROR(expected_sil_vtable_colon,none, "expected ':' in a vtable entry", ()) -ERROR(sil_vtable_func_not_found, decl_parsing,none, +ERROR(sil_vtable_func_not_found,none, "sil function not found %0", (Identifier)) -ERROR(sil_vtable_class_not_found, decl_parsing,none, +ERROR(sil_vtable_class_not_found,none, "sil class not found %0", (Identifier)) // SIL Global -ERROR(sil_global_variable_not_found, decl_parsing,none, +ERROR(sil_global_variable_not_found,none, "sil global not found %0", (Identifier)) // SIL Witness Table -ERROR(expected_sil_witness_colon, decl_parsing,none, +ERROR(expected_sil_witness_colon,none, "expected ':' in a witness table", ()) -ERROR(expected_sil_witness_lparen, decl_parsing,none, +ERROR(expected_sil_witness_lparen,none, "expected '(' in a witness table", ()) -ERROR(expected_sil_witness_rparen, decl_parsing,none, +ERROR(expected_sil_witness_rparen,none, "expected ')' in a witness table", ()) -ERROR(sil_witness_func_not_found, decl_parsing,none, +ERROR(sil_witness_func_not_found,none, "sil function not found %0", (Identifier)) -ERROR(sil_witness_protocol_not_found, decl_parsing,none, +ERROR(sil_witness_protocol_not_found,none, "sil protocol not found %0", (Identifier)) -ERROR(sil_witness_assoc_not_found, decl_parsing,none, +ERROR(sil_witness_assoc_not_found,none, "sil associated type decl not found %0", (Identifier)) -ERROR(sil_witness_protocol_conformance_not_found, decl_parsing,none, +ERROR(sil_witness_protocol_conformance_not_found,none, "sil protocol conformance not found", ()) // SIL Coverage Map -ERROR(sil_coverage_func_not_found, decl_parsing, none, +ERROR(sil_coverage_func_not_found, none, "sil function not found %0", (Identifier)) -ERROR(sil_coverage_invalid_hash, decl_parsing, none, +ERROR(sil_coverage_invalid_hash, none, "expected coverage hash", ()) -ERROR(sil_coverage_expected_lbrace, decl_parsing, none, +ERROR(sil_coverage_expected_lbrace, none, "expected '{' in coverage map", ()) -ERROR(sil_coverage_expected_loc, decl_parsing, none, +ERROR(sil_coverage_expected_loc, none, "expected line:column pair", ()) -ERROR(sil_coverage_expected_arrow, decl_parsing, none, +ERROR(sil_coverage_expected_arrow, none, "expected '->' after start location", ()) -ERROR(sil_coverage_expected_colon, decl_parsing, none, +ERROR(sil_coverage_expected_colon, none, "expected ':' after source range", ()) -ERROR(sil_coverage_invalid_counter, decl_parsing, none, +ERROR(sil_coverage_invalid_counter, none, "expected counter expression, id, or 'zero'", ()) -ERROR(sil_coverage_expected_rparen, decl_parsing, none, +ERROR(sil_coverage_expected_rparen, none, "expected ')' to end counter expression", ()) -ERROR(sil_coverage_invalid_operator, decl_parsing, none, +ERROR(sil_coverage_invalid_operator, none, "expected '+' or '-'", ()) //------------------------------------------------------------------------------ // Type parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_type,type_parsing,PointsToFirstBadToken, +ERROR(expected_type,PointsToFirstBadToken, "expected type", ()) -ERROR(expected_init_value,expr_parsing,PointsToFirstBadToken, +ERROR(expected_init_value,PointsToFirstBadToken, "expected initial value after '='", ()) // Named types -ERROR(expected_identifier_in_dotted_type,expr_parsing,PointsToFirstBadToken, +ERROR(expected_identifier_in_dotted_type,PointsToFirstBadToken, "expected identifier in dotted type", ()) -ERROR(expected_identifier_for_type,expr_parsing,PointsToFirstBadToken, +ERROR(expected_identifier_for_type,PointsToFirstBadToken, "expected identifier for type name", ()) -ERROR(expected_rangle_generic_arg_list,type_parsing,PointsToFirstBadToken, +ERROR(expected_rangle_generic_arg_list,PointsToFirstBadToken, "expected '>' to complete generic argument list", ()) // Function types -ERROR(expected_type_function_result,type_parsing,PointsToFirstBadToken, +ERROR(expected_type_function_result,PointsToFirstBadToken, "expected type for function result", ()) -ERROR(generic_non_function,type_parsing,PointsToFirstBadToken, +ERROR(generic_non_function,PointsToFirstBadToken, "only syntactic function types can be generic", ()) -ERROR(throwing_non_function,type_parsing,PointsToFirstBadToken, - "only function types may throw", ()) -ERROR(rethrowing_function_type,type_parsing,PointsToFirstBadToken, +ERROR(rethrowing_function_type,PointsToFirstBadToken, "only function declarations may be marked 'rethrows'", ()) -ERROR(throws_after_function_result,type_parsing,none, +ERROR(throws_after_function_result,none, "'throws' may only occur before '->'", ()) -ERROR(rethrows_after_function_result,type_parsing,none, +ERROR(rethrows_after_function_result,none, "'rethrows' may only occur before '->'", ()) -ERROR(throw_in_function_type,type_parsing,none, +ERROR(throw_in_function_type,none, "expected throwing specifier; did you mean 'throws'?", ()) // Enum Types -ERROR(expected_expr_enum_case_raw_value,type_parsing,PointsToFirstBadToken, +ERROR(expected_expr_enum_case_raw_value,PointsToFirstBadToken, "expected expression after '=' in 'case'", ()) -ERROR(nonliteral_enum_case_raw_value,type_parsing,PointsToFirstBadToken, +ERROR(nonliteral_enum_case_raw_value,PointsToFirstBadToken, "raw value for enum case must be a literal", ()) // Collection Types -ERROR(expected_expr_array_type,expr_parsing,PointsToFirstBadToken, - "expected expression for size of array type", ()) -ERROR(expected_rbracket_array_type,type_parsing,PointsToFirstBadToken, +ERROR(new_array_syntax,none, + "array types are now written with the brackets around the element type", + ()) +ERROR(expected_rbracket_array_type,PointsToFirstBadToken, "expected ']' in array type", ()) -ERROR(expected_element_type,type_parsing,PointsToFirstBadToken, +ERROR(expected_element_type,PointsToFirstBadToken, "expected element type", ()) -ERROR(expected_dictionary_value_type,type_parsing,PointsToFirstBadToken, +ERROR(expected_dictionary_value_type,PointsToFirstBadToken, "expected dictionary value type", ()) -ERROR(expected_rbracket_dictionary_type,type_parsing,PointsToFirstBadToken, +ERROR(expected_rbracket_dictionary_type,PointsToFirstBadToken, "expected ']' in dictionary type", ()) // Tuple Types -ERROR(expected_rparen_tuple_type_list,type_parsing,none, +ERROR(expected_rparen_tuple_type_list,none, "expected ')' at end of tuple list", ()) -ERROR(multiple_ellipsis_in_tuple,type_parsing,none, +ERROR(multiple_ellipsis_in_tuple,none, "only a single element can be variadic", ()) -ERROR(tuple_type_init,pattern_parsing,none, +ERROR(tuple_type_init,none, "default argument not permitted in a tuple type", ()) -ERROR(protocol_method_argument_init,type_parsing,none, +ERROR(protocol_method_argument_init,none, "default argument not permitted in a protocol method", ()) -ERROR(protocol_init_argument_init,type_parsing,none, +ERROR(protocol_init_argument_init,none, "default argument not permitted in a protocol initializer", ()) // Protocol Types -ERROR(expected_langle_protocol,type_parsing,PointsToFirstBadToken, +ERROR(expected_langle_protocol,PointsToFirstBadToken, "expected '<' in protocol composition type", ()) -ERROR(expected_rangle_protocol,type_parsing,PointsToFirstBadToken, +ERROR(expected_rangle_protocol,PointsToFirstBadToken, "expected '>' to complete protocol composition type", ()) //------------------------------------------------------------------------------ // Pattern parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_pattern,pattern_parsing,PointsToFirstBadToken, +ERROR(expected_pattern,PointsToFirstBadToken, "expected pattern", ()) -ERROR(expected_pattern_is_keyword,pattern_parsing,none, +ERROR(expected_pattern_is_keyword,none, "keyword '%0' cannot be used as an identifier", (StringRef)) -ERROR(expected_rparen_tuple_pattern_list,pattern_parsing,none, +ERROR(expected_rparen_tuple_pattern_list,none, "expected ')' at end of tuple pattern", ()) -ERROR(untyped_pattern_ellipsis,pattern_parsing,none, +ERROR(untyped_pattern_ellipsis,none, "'...' cannot be applied to a subpattern which is not explicitly typed", ()) -ERROR(non_func_decl_pattern_init,pattern_parsing,none, - "default argument is only permitted for a non-curried function parameter",()) -WARNING(var_not_allowed_in_pattern,pattern_parsing, none, - "Use of '%select{var|let}0' binding here is deprecated and will be removed in a future version of Swift", (unsigned)) -ERROR(var_pattern_in_var,pattern_parsing,none, +ERROR(no_default_arg_closure,none, + "default arguments are not allowed in closures", ()) +ERROR(no_default_arg_subscript,none, + "default arguments are not allowed in subscripts", ()) +ERROR(no_default_arg_curried,none, + "default arguments are not allowed in curried parameter lists", ()) +ERROR(var_not_allowed_in_pattern, none, + "Use of 'var' binding here is not allowed", ()) +WARNING(let_on_param_is_redundant, none, + "'let' keyword is unnecessary; function parameters are immutable by default", (unsigned)) +ERROR(var_pattern_in_var,none, "'%select{var|let}0' cannot appear nested inside another 'var' or " "'let' pattern", (unsigned)) -ERROR(let_pattern_in_immutable_context,pattern_parsing,none, +ERROR(let_pattern_in_immutable_context,none, "'let' pattern is already in an immutable context", ()) -ERROR(inout_must_have_type,pattern_parsing,none, +ERROR(inout_must_have_type,none, "'inout' arguments must have a type specified", ()) -ERROR(inout_must_appear_before_param,pattern_parsing,none, +ERROR(inout_must_appear_before_param,none, "'inout' must appear before the parameter name", ()) -ERROR(expected_rparen_parameter,decl_parsing,PointsToFirstBadToken, +ERROR(expected_rparen_parameter,PointsToFirstBadToken, "expected ')' in parameter", ()) -ERROR(expected_parameter_type,decl_parsing,PointsToFirstBadToken, +ERROR(expected_parameter_type,PointsToFirstBadToken, "expected parameter type following ':'", ()) -ERROR(multiple_parameter_ellipsis,decl_parsing,none, +ERROR(missing_parameter_type,PointsToFirstBadToken, + "parameter requires an explicit type", ()) +ERROR(multiple_parameter_ellipsis,none, "only a single variadic parameter '...' is permitted", ()) -ERROR(parameter_vararg_default,decl_parsing,none, +ERROR(parameter_vararg_default,none, "variadic parameter cannot have a default value", ()) -ERROR(parameter_backtick_missing_name,decl_parsing,PointsToFirstBadToken, - "expected parameter name after '#'", ()) -ERROR(parameter_backtick_empty_name,decl_parsing,none, - "expected non-empty parameter name after '#'", ()) -ERROR(parameter_inout_var_let,decl_parsing,none, +ERROR(parameter_inout_var_let,none, "parameter may not have multiple 'inout', 'var', or 'let' specifiers", ()) -WARNING(parameter_backtick_two_names,decl_parsing,none, - "extraneous '#' in parameter; keyword argument and parameter name " - "already specified separately", ()) -WARNING(parameter_extraneous_double_up,decl_parsing,none, +WARNING(parameter_extraneous_double_up,none, "extraneous duplicate parameter name; %0 already has an argument " "label", (Identifier)) -ERROR(parameter_extraneous_pound,decl_parsing,none, - "'#' has been removed from Swift; %0 already has an argument label", - (Identifier)) -ERROR(parameter_pound_double_up,decl_parsing,none, - "'#' has been removed from Swift; double up '%0 %0' to make the " - "argument label the same as the parameter name", (StringRef)) -WARNING(parameter_extraneous_empty_name,decl_parsing,none, +WARNING(parameter_extraneous_empty_name,none, "extraneous '_' in parameter: %0 has no keyword argument name", (Identifier)) -ERROR(parameter_operator_keyword_argument,decl_parsing,none, - "operator cannot have keyword arguments", ()) +ERROR(parameter_operator_keyword_argument,none, + "%select{operator|closure}0 cannot have keyword arguments", (bool)) -ERROR(parameter_unnamed,decl_parsing,none, +ERROR(parameter_unnamed,none, "unnamed parameters must be written with the empty name '_'", ()) -WARNING(parameter_curry_syntax_removed,decl_parsing,none, - "curried function declaration syntax will be removed in a future version of Swift; use a single parameter list", ()) +ERROR(parameter_curry_syntax_removed,none, + "curried function declaration syntax has been removed; use a single parameter list", ()) //------------------------------------------------------------------------------ // Statement parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_stmt,stmt_parsing,none, +ERROR(expected_stmt,none, "expected statement", ()) -ERROR(illegal_top_level_stmt,stmt_parsing,none, +ERROR(illegal_top_level_stmt,none, "statements are not allowed at the top level", ()) -ERROR(illegal_top_level_expr,stmt_parsing,none, +ERROR(illegal_top_level_expr,none, "expressions are not allowed at the top level", ()) -ERROR(illegal_semi_stmt,stmt_parsing,none, +ERROR(illegal_semi_stmt,none, "';' statements are not allowed", ()) -ERROR(statement_begins_with_closure,stmt_parsing,none, +ERROR(statement_begins_with_closure,none, "statement cannot begin with a closure expression", ()) -ERROR(statement_same_line_without_semi,stmt_parsing,none, +ERROR(statement_same_line_without_semi,none, "consecutive statements on a line must be separated by ';'", ()) -ERROR(brace_stmt_invalid,stmt_parsing,none, +ERROR(brace_stmt_invalid,none, "braced block of statements is an unused closure", ()) -ERROR(invalid_label_on_stmt,stmt_parsing,none, +ERROR(invalid_label_on_stmt,none, "labels are only valid on loops, if, and switch statements", ()) -NOTE(discard_result_of_closure,stmt_parsing,none, +NOTE(discard_result_of_closure,none, "explicitly discard the result of the closure by assigning to '_'", ()) // Assignment statement -ERROR(expected_expr_assignment,stmt_parsing,none, +ERROR(expected_expr_assignment,none, "expected expression in assignment", ()) // Brace Statement -ERROR(expected_rbrace_in_brace_stmt,stmt_parsing,none, +ERROR(expected_rbrace_in_brace_stmt,none, "expected '}' at end of brace statement", ()) /// #if Statement -ERROR(expected_close_to_config_stmt,stmt_parsing,none, +ERROR(expected_close_to_config_stmt,none, "expected #else or #endif at end of configuration block", ()) -ERROR(expected_close_after_else,stmt_parsing,none, +ERROR(expected_close_after_else,none, "further conditions after #else are unreachable", ()) +/// Associatedtype Statement +WARNING(typealias_inside_protocol,none, + "use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead", ()) +ERROR(associatedtype_outside_protocol,none, + "associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement", ()) + // Return Statement -ERROR(expected_expr_return,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_expr_return,PointsToFirstBadToken, "expected expression in 'return' statement", ()) -WARNING(unindented_code_after_return,stmt_parsing,none, +WARNING(unindented_code_after_return,none, "expression following 'return' is treated as an argument of " "the 'return'", ()) -NOTE(indent_expression_to_silence,stmt_parsing,none, +NOTE(indent_expression_to_silence,none, "indent the expression to silence this warning", ()) // Throw Statement -ERROR(expected_expr_throw,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_expr_throw,PointsToFirstBadToken, "expected expression in 'throw' statement", ()) // Defer Statement -ERROR(expected_lbrace_after_defer,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_defer,PointsToFirstBadToken, "expected '{' after 'defer'", ()) // If/While/Guard Conditions -ERROR(expected_expr_conditional_letbinding,stmt_parsing,none, +ERROR(expected_expr_conditional_letbinding,none, "expected 'let' or 'var' in conditional", ()) -ERROR(expected_expr_conditional_letbinding_bool_conditions,stmt_parsing,none, +ERROR(expected_expr_conditional_letbinding_bool_conditions,none, "expected 'let' or 'var' in conditional; " "use '&&' to join boolean conditions", ()) -ERROR(expected_simple_identifier_pattern,stmt_parsing,none, - "expected simple identifier pattern in optional binding condition", ()) -ERROR(expected_expr_conditional_var,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_expr_conditional_var,PointsToFirstBadToken, "expected expression after '=' in conditional binding", ()) -ERROR(expected_expr_conditional_where,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_expr_conditional_where,PointsToFirstBadToken, "expected expression in conditional binding 'where' clause", ()) -ERROR(conditional_var_initializer_required,stmt_parsing,none, +ERROR(conditional_var_initializer_required,none, "variable binding in a condition requires an initializer", ()) -ERROR(wrong_condition_case_location,stmt_parsing,none, +ERROR(wrong_condition_case_location,none, "pattern matching binding is spelled with 'case %0', not '%0 case'", (StringRef)) -ERROR(where_end_of_binding_use_letvar,stmt_parsing,none, +ERROR(where_end_of_binding_use_letvar,none, "binding ended by previous 'where' clause; " "use '%0' to introduce a new one", (StringRef)) -ERROR(comma_should_be_where,stmt_parsing,none, +ERROR(comma_should_be_where,none, "boolean condition requires 'where' to separate it from variable binding", ()) // If Statement -ERROR(expected_condition_if,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_condition_if,PointsToFirstBadToken, "expected expression, var, or let in 'if' condition", ()) -ERROR(missing_condition_after_if,stmt_parsing,none, +ERROR(missing_condition_after_if,none, "missing condition in an 'if' statement", ()) -ERROR(expected_lbrace_after_if,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_if,PointsToFirstBadToken, "expected '{' after 'if' condition", ()) -ERROR(expected_lbrace_after_else,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_else,PointsToFirstBadToken, "expected '{' after 'else'", ()) // Guard Statement -ERROR(expected_condition_guard,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_condition_guard,PointsToFirstBadToken, "expected expression, var, let or case in 'guard' condition", ()) -ERROR(missing_condition_after_guard,stmt_parsing,none, +ERROR(missing_condition_after_guard,none, "missing condition in an 'guard' statement", ()) -ERROR(expected_else_after_guard,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_else_after_guard,PointsToFirstBadToken, "expected 'else' after 'guard' condition", ()) -ERROR(expected_lbrace_after_guard,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_guard,PointsToFirstBadToken, "expected '{' after 'guard' else", ()) -ERROR(bound_var_guard_body,expr_parsing,none, +ERROR(bound_var_guard_body,none, "variable declared in 'guard' condition is not usable in its body", ()) // While Statement -ERROR(expected_condition_while,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_condition_while,PointsToFirstBadToken, "expected expression, var, or let in 'while' condition", ()) -ERROR(missing_condition_after_while,stmt_parsing,none, +ERROR(missing_condition_after_while,none, "missing condition in a 'while' statement", ()) -ERROR(expected_lbrace_after_while,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_while,PointsToFirstBadToken, "expected '{' after 'while' condition", ()) // Repeat/While Statement -ERROR(expected_lbrace_after_repeat,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_repeat,PointsToFirstBadToken, "expected '{' after 'repeat'", ()) -ERROR(expected_while_after_repeat_body,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_while_after_repeat_body,PointsToFirstBadToken, "expected 'while' after body of 'repeat' statement", ()) -ERROR(expected_expr_repeat_while,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_expr_repeat_while,PointsToFirstBadToken, "expected expression in 'repeat-while' condition", ()) -ERROR(missing_condition_after_repeat_while,stmt_parsing,none, - "missing condition in a 'repeat-while' statement", ()) -ERROR(do_while_now_repeat_while,stmt_parsing,none, +ERROR(do_while_now_repeat_while,none, "'do-while' statement is not allowed; use 'repeat-while' instead", ()) // Do/Catch Statement -ERROR(expected_lbrace_after_do,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_do,PointsToFirstBadToken, "expected '{' after 'do'", ()) -ERROR(expected_lbrace_after_catch,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_catch,PointsToFirstBadToken, "expected '{' after 'catch' pattern", ()) -ERROR(expected_catch_where_expr,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_catch_where_expr,PointsToFirstBadToken, "expected expression for 'where' guard of 'catch'", ()) +ERROR(docatch_not_trycatch,PointsToFirstBadToken, + "the 'do' keyword is used to specify a 'catch' region", + ()) + + // C-Style For Stmt -ERROR(expected_init_for_stmt,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_init_for_stmt,PointsToFirstBadToken, "expected initialization in a 'for' statement", ()) -ERROR(missing_init_for_stmt,stmt_parsing,none, +ERROR(missing_init_for_stmt,none, "missing initialization in a 'for' statement", ()) -ERROR(expected_semi_for_stmt,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_semi_for_stmt,PointsToFirstBadToken, "expected ';' in 'for' statement", ()) -ERROR(expected_cond_for_stmt,stmt_parsing,none, +ERROR(expected_cond_for_stmt,none, "expected condition in 'for' statement", ()) -ERROR(expected_rparen_for_stmt,stmt_parsing,none, +ERROR(expected_rparen_for_stmt,none, "expected ')' in 'for' statement", ()) -ERROR(expected_lbrace_after_for,stmt_parsing,none, +ERROR(expected_lbrace_after_for,none, "expected '{' in 'for' statement", ()) -ERROR(expected_var_decl_for_stmt,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_var_decl_for_stmt,PointsToFirstBadToken, "expected var declaration in a 'for' statement", ()) // For-each Stmt -ERROR(expected_foreach_in,stmt_parsing,none, +ERROR(expected_foreach_in,none, "expected 'in' after for-each pattern", ()) -ERROR(expected_foreach_container,stmt_parsing,none, +ERROR(expected_foreach_container,none, "expected SequenceType expression for for-each loop", ()) -ERROR(expected_foreach_lbrace,stmt_parsing,none, +ERROR(expected_foreach_lbrace,none, "expected '{' to start the body of for-each loop", ()) -ERROR(expected_foreach_where_expr,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_foreach_where_expr,PointsToFirstBadToken, "expected expression in 'where' guard of 'for/in'", ()) // Switch Stmt -ERROR(expected_switch_expr,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_switch_expr,PointsToFirstBadToken, "expected expression in 'switch' statement", ()) -ERROR(expected_lbrace_after_switch,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_lbrace_after_switch,PointsToFirstBadToken, "expected '{' after 'switch' subject expression", ()) -ERROR(expected_rbrace_switch,stmt_parsing,none, +ERROR(expected_rbrace_switch,none, "expected '}' at end of 'switch' statement", ()) -ERROR(case_outside_of_switch,stmt_parsing,none, +ERROR(case_outside_of_switch,none, "'%0' label can only appear inside a 'switch' statement", (StringRef)) -ERROR(stmt_in_switch_not_covered_by_case,stmt_parsing,none, +ERROR(stmt_in_switch_not_covered_by_case,none, "all statements inside a switch must be covered by a 'case' or 'default'", ()) -ERROR(case_after_default,stmt_parsing,none, +ERROR(case_after_default,none, "additional 'case' blocks cannot appear after the 'default' block of a 'switch'", ()) -ERROR(empty_switch_stmt,stmt_parsing,none, +ERROR(empty_switch_stmt,none, "'switch' statement body must have at least one 'case' or 'default' block", ()) // Case Stmt -ERROR(expected_case_where_expr,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_case_where_expr,PointsToFirstBadToken, "expected expression for 'where' guard of 'case'", ()) -ERROR(expected_case_colon,stmt_parsing,PointsToFirstBadToken, +ERROR(expected_case_colon,PointsToFirstBadToken, "expected ':' after '%0'", (StringRef)) -ERROR(default_with_where,stmt_parsing,none, +ERROR(default_with_where,none, "'default' cannot be used with a 'where' guard expression", ()) -ERROR(var_binding_with_multiple_case_patterns,stmt_parsing,none, +ERROR(var_binding_with_multiple_case_patterns,none, "'case' labels with multiple patterns cannot declare variables", ()) -ERROR(case_stmt_without_body,stmt_parsing,none, +ERROR(case_stmt_without_body,none, "%select{'case'|'default'}0 label in a 'switch' should have at least one " "executable statement", (bool)) // 'try' on statements -ERROR(try_on_stmt,stmt_parsing,none, +ERROR(try_on_stmt,none, "'try' cannot be used with '%0'", (StringRef)) -ERROR(try_on_return_throw,stmt_parsing,none, +ERROR(try_on_return_throw,none, "'try' must be placed on the %select{returned|thrown}0 expression", (bool)) -ERROR(try_on_var_let,stmt_parsing,none, +ERROR(try_on_var_let,none, "'try' must be placed on the initial value expression", ()) //------------------------------------------------------------------------------ // Expression parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_expr,expr_parsing,none, +ERROR(expected_expr,none, "expected expression", ()) -ERROR(expected_separator,expr_parsing,PointsToFirstBadToken, +ERROR(expected_separator,PointsToFirstBadToken, "expected '%0' separator", (StringRef)) -ERROR(unexpected_separator,expr_parsing,none, +ERROR(unexpected_separator,none, "unexpected '%0' separator", (StringRef)) -ERROR(expected_expr_after_operator,expr_parsing,none, +ERROR(expected_expr_after_operator,none, "expected expression after operator", ()) -ERROR(expected_expr_after_unary_operator,expr_parsing,none, +ERROR(expected_expr_after_unary_operator,none, "expected expression after unary operator", ()) -ERROR(expected_prefix_operator,expr_parsing,none, +ERROR(expected_prefix_operator,none, "unary operator cannot be separated from its operand", ()) -ERROR(expected_operator_ref,expr_parsing,none, +ERROR(expected_operator_ref,none, "expected operator name in operator reference", ()) -ERROR(invalid_postfix_operator,expr_parsing,none, +ERROR(invalid_postfix_operator,none, "operator with postfix spacing cannot start a subexpression", ()) -ERROR(expected_member_name,expr_parsing,PointsToFirstBadToken, +ERROR(expected_member_name,PointsToFirstBadToken, "expected member name following '.'", ()) -ERROR(expected_dollar_numeric,expr_parsing,none, +ERROR(expected_dollar_numeric,none, "expected numeric value following '$'", ()) -ERROR(dollar_numeric_too_large,expr_parsing,none, +ERROR(dollar_numeric_too_large,none, "numeric value following '$' is too large", ()) -ERROR(numeric_literal_numeric_member,expr_parsing,none, +ERROR(numeric_literal_numeric_member,none, "expected named member of numeric literal", ()) -ERROR(anon_closure_arg_not_in_closure,expr_parsing,none, +ERROR(anon_closure_arg_not_in_closure,none, "anonymous closure argument not contained in a closure", ()) -ERROR(anon_closure_arg_in_closure_with_args,expr_parsing,none, +ERROR(anon_closure_arg_in_closure_with_args,none, "anonymous closure arguments cannot be used inside a closure that has " "explicit arguments", ()) -ERROR(expected_closure_parameter_name,expr_parsing,none, +ERROR(expected_closure_parameter_name,none, "expected the name of a closure parameter", ()) -ERROR(expected_capture_specifier,expr_parsing,none, +ERROR(expected_capture_specifier,none, "expected 'weak', 'unowned', or no specifier in capture list", ()) -ERROR(expected_capture_specifier_name,attribute_parsing,none, +ERROR(expected_capture_specifier_name,none, "expected name of in closure capture list", ()) -ERROR(expected_init_capture_specifier,attribute_parsing,none, +ERROR(expected_init_capture_specifier,none, "expected initializer for closure capture specifier", ()) -ERROR(expected_capture_list_end_rsquare,attribute_parsing,none, +ERROR(expected_capture_list_end_rsquare,none, "expected ']' at end of capture list", ()) -ERROR(cannot_capture_fields,attribute_parsing,none, +ERROR(cannot_capture_fields,none, "fields may only be captured by assigning to a specific name", ()) -ERROR(expected_closure_result_type,expr_parsing,none, +ERROR(expected_closure_result_type,none, "expected closure result type after '->'", ()) -ERROR(expected_closure_in,expr_parsing,none, +ERROR(expected_closure_in,none, "expected 'in' after the closure signature", ()) -ERROR(unexpected_tokens_before_closure_in,expr_parsing,none, +ERROR(unexpected_tokens_before_closure_in,none, "unexpected tokens prior to 'in'", ()) -ERROR(expected_closure_rbrace,expr_parsing,none, +ERROR(expected_closure_rbrace,none, "expected '}' at end of closure", ()) -WARNING(trailing_closure_excess_newlines,expr_parsing,none, +WARNING(trailing_closure_excess_newlines,none, "trailing closure is separated from call site by multiple newlines", ()) -NOTE(trailing_closure_call_here,expr_parsing,none, +NOTE(trailing_closure_call_here,none, "parsing trailing closure for this call", ()) -ERROR(string_literal_no_atsign,expr_parsing,none, +ERROR(string_literal_no_atsign,none, "string literals in Swift are not preceded by an '@' sign", ()) -ERROR(invalid_float_literal_missing_leading_zero,expr_parsing,none, +ERROR(invalid_float_literal_missing_leading_zero,none, "'.%0' is not a valid floating point literal; it must be written '0.%0'", (StringRef)) -ERROR(availability_query_outside_if_stmt_guard, expr_parsing, none, +ERROR(availability_query_outside_if_stmt_guard, none, "#available may only be used as condition of an 'if', 'guard'" " or 'while' statement", ()) -ERROR(expected_identifier_after_dot_expr,expr_parsing,none, +ERROR(empty_arg_label_underscore, none, + "an empty argument label is spelled with '_'", ()) + +ERROR(expected_identifier_after_dot_expr,none, "expected identifier after '.' expression", ()) -ERROR(expected_field_spec_name_tuple_expr,expr_parsing,none, - "expected field specifier name in tuple expression", ()) -ERROR(expected_identifier_after_super_dot_expr,expr_parsing, +ERROR(expected_identifier_after_super_dot_expr, PointsToFirstBadToken, "expected identifier or 'init' after super '.' expression", ()) -ERROR(expected_dot_or_subscript_after_super,expr_parsing,PointsToFirstBadToken, +ERROR(expected_dot_or_subscript_after_super,PointsToFirstBadToken, "expected '.' or '[' after 'super'", ()) -ERROR(super_in_closure_with_capture,expr_parsing,none, +ERROR(super_in_closure_with_capture,none, "using 'super' in a closure where 'self' is explicitly captured is " "not yet supported", ()) -NOTE(super_in_closure_with_capture_here,expr_parsing,none, +NOTE(super_in_closure_with_capture_here,none, "'self' explicitly captured here", ()) // Tuples and parenthesized expressions -ERROR(expected_expr_in_expr_list,expr_parsing,none, +ERROR(expected_expr_in_expr_list,none, "expected expression in list of expressions", ()) -ERROR(expected_expr_in_collection_literal,expr_parsing,none, +ERROR(expected_expr_in_collection_literal,none, "expected expression in container literal", ()) -ERROR(expected_key_in_dictionary_literal,expr_parsing,none, +ERROR(expected_key_in_dictionary_literal,none, "expected key expression in dictionary literal", ()) -ERROR(expected_value_in_dictionary_literal,expr_parsing,none, +ERROR(expected_value_in_dictionary_literal,none, "expected value in dictionary literal", ()) -ERROR(expected_colon_in_dictionary_literal,expr_parsing,none, +ERROR(expected_colon_in_dictionary_literal,none, "expected ':' in dictionary literal", ()) -ERROR(expected_rparen_expr_list,expr_parsing,none, +ERROR(expected_rparen_expr_list,none, "expected ')' in expression list", ()) -ERROR(expected_rsquare_expr_list,expr_parsing,none, +ERROR(expected_rsquare_expr_list,none, "expected ']' in expression list", ()) // Array literal expressions -ERROR(expected_rsquare_array_expr,expr_parsing,PointsToFirstBadToken, +ERROR(expected_rsquare_array_expr,PointsToFirstBadToken, "expected ']' in container literal expression", ()) // Object literal expressions -ERROR(expected_identifier_after_l_square_lit,expr_parsing,none, +ERROR(expected_identifier_after_l_square_lit,none, "expected identifier after '[#' in object literal expression", ()) -ERROR(expected_arg_list_in_object_literal,expr_parsing,none, +ERROR(expected_arg_list_in_object_literal,none, "expected argument list in object literal", ()) -ERROR(expected_r_square_lit_after_object_literal,expr_parsing,none, +ERROR(expected_r_square_lit_after_object_literal,none, "expected '#]' at end of object literal expression", ()) // If expressions -ERROR(expected_expr_after_if_question,expr_parsing,none, +ERROR(expected_expr_after_if_question,none, "expected expression after '?' in ternary expression", ()) -ERROR(expected_colon_after_if_question,expr_parsing,none, +ERROR(expected_colon_after_if_question,none, "expected ':' after '? ...' in ternary expression", ()) -ERROR(expected_expr_after_if_colon,expr_parsing,none, +ERROR(expected_expr_after_if_colon,none, "expected expression after '? ... :' in ternary expression", ()) // Cast expressions -ERROR(expected_type_after_is,expr_parsing,none, +ERROR(expected_type_after_is,none, "expected type after 'is'", ()) -ERROR(expected_type_after_as,expr_parsing,none, +ERROR(expected_type_after_as,none, "expected type after 'as'", ()) // Extra tokens in string interpolation like in " >> \( $0 } ) << " -ERROR(string_interpolation_extra,expr_parsing,none, +ERROR(string_interpolation_extra,none, "extra tokens after interpolated string expression", ()) +// Selector expressions. +ERROR(expr_selector_expected_lparen,PointsToFirstBadToken, + "expected '(' following '#selector'", ()) +ERROR(expr_selector_expected_expr,PointsToFirstBadToken, + "expected expression naming a method within '#selector(...)'", ()) +ERROR(expr_selector_expected_rparen,PointsToFirstBadToken, + "expected ')' to complete '#selector' expression", ()) + //------------------------------------------------------------------------------ // Attribute-parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_attribute_name,attribute_parsing,none, +ERROR(expected_attribute_name,none, "expected an attribute name", ()) -ERROR(unknown_attribute,attribute_parsing,none, +ERROR(unknown_attribute,none, "unknown attribute '%0'", (StringRef)) -ERROR(duplicate_attribute,attribute_parsing,none, +ERROR(duplicate_attribute,none, "duplicate %select{attribute|modifier}0", (bool)) -NOTE(previous_attribute,parsing,none, +NOTE(previous_attribute,none, "%select{attribute|modifier}0 already specified here", (bool)) -ERROR(cannot_combine_attribute,attribute_parsing,none, +ERROR(cannot_combine_attribute,none, "attribute '%0' cannot be combined with this attribute", (StringRef)) -ERROR(expected_in_attribute_list,attribute_parsing,none, +ERROR(expected_in_attribute_list,none, "expected ']' or ',' in attribute list", ()) -ERROR(type_attribute_applied_to_decl,attribute_parsing,none, +ERROR(type_attribute_applied_to_decl,none, "attribute can only be applied to types, not declarations", ()) -ERROR(decl_attribute_applied_to_type,attribute_parsing,none, +ERROR(decl_attribute_applied_to_type,none, "attribute can only be applied to declarations, not types", ()) -ERROR(attr_expected_lparen,attribute_parsing,none, +ERROR(attr_expected_lparen,none, "expected '(' in '%0' %select{attribute|modifier}1", (StringRef, bool)) -ERROR(attr_expected_rparen,attribute_parsing,none, +ERROR(attr_expected_rparen,none, "expected ')' in '%0' %select{attribute|modifier}1", (StringRef, bool)) -ERROR(attr_expected_comma,attribute_parsing,none, +ERROR(attr_expected_comma,none, "expected ',' in '%0' %select{attribute|modifier}1", (StringRef, bool)) -ERROR(attr_expected_string_literal,attribute_parsing,none, +ERROR(attr_expected_string_literal,none, "expected string literal in '%0' attribute", (StringRef)) -ERROR(alignment_must_be_positive_integer,attribute_parsing,none, +ERROR(alignment_must_be_positive_integer,none, "alignment value must be a positive integer literal", ()) -ERROR(swift_native_objc_runtime_base_must_be_identifier,attribute_parsing,none, +ERROR(swift_native_objc_runtime_base_must_be_identifier,none, "@_swift_native_objc_runtime_base class name must be an identifier", ()) -ERROR(attr_interpolated_string,attribute_parsing,none, +ERROR(attr_interpolated_string,none, "%0 cannot be an interpolated string literal", (StringRef)) -ERROR(attr_only_at_non_local_scope, attribute_parsing, none, +ERROR(attr_only_at_non_local_scope, none, "attribute '%0' can only be used in a non-local scope", (StringRef)) +ERROR(attr_expected_equal_separator,none, + "expected '=' following '%0' argument of '%1'", + (StringRef, StringRef)) + +ERROR(attr_expected_string_literal_arg,none, + "expected string literal for '%0' argument of '%1'", + (StringRef, StringRef)) + +ERROR(attr_duplicate_argument,none, + "duplicate '%0' argument", (StringRef)) + // accessibility -ERROR(attr_accessibility_expected_set,attribute_parsing,none, +ERROR(attr_accessibility_expected_set,none, "expected 'set' as subject of '%0' modifier", (StringRef)) // availability -ERROR(attr_availability_platform,attribute_parsing,none, +ERROR(attr_availability_platform,none, "expected platform name or '*' for '%0' attribute", (StringRef)) -ERROR(attr_availability_unavailable_deprecated,attribute_parsing,none, +ERROR(attr_availability_unavailable_deprecated,none, "'%0' attribute cannot be both unconditionally 'unavailable' and " "'deprecated'", (StringRef)) -WARNING(attr_availability_unknown_platform,attribute_parsing,none, +WARNING(attr_availability_unknown_platform,none, "unknown platform '%0' for attribute '%1'", (StringRef, StringRef)) -ERROR(attr_availability_expected_option,attribute_parsing,none, +ERROR(attr_availability_expected_option,none, "expected '%0' option such as 'unavailable', 'introduced', 'deprecated', " "'obsoleted', 'message', or 'renamed'", (StringRef)) -ERROR(attr_availability_expected_equal,attribute_parsing,none, -"expected '=' after '%1' in '%0' attribute", (StringRef, StringRef)) +ERROR(attr_availability_expected_equal,none, + "expected '=' after '%1' in '%0' attribute", (StringRef, StringRef)) -ERROR(attr_availability_expected_version,attribute_parsing,none, +ERROR(attr_availability_expected_version,none, "expected version number in '%0' attribute", (StringRef)) -ERROR(attr_availability_renamed, attribute_parsing, none, +ERROR(attr_availability_renamed, none, "@availability has been renamed to @available", ()) // autoclosure -ERROR(attr_autoclosure_expected_r_paren,attribute_parsing,PointsToFirstBadToken, +ERROR(attr_autoclosure_expected_r_paren,PointsToFirstBadToken, "expected ')' in @autoclosure", ()) -// cc -ERROR(cc_attribute_expected_lparen,attribute_parsing,none, - "expected '(' after 'cc' attribute", ()) -ERROR(cc_attribute_expected_name,attribute_parsing,none, - "expected calling convention name identifier in 'cc' attribute", ()) -ERROR(cc_attribute_expected_rparen,attribute_parsing,none, - "expected ')' after calling convention name for 'cc' attribute", ()) - // convention -ERROR(convention_attribute_expected_lparen,attribute_parsing,none, +ERROR(convention_attribute_expected_lparen,none, "expected '(' after 'convention' attribute", ()) -ERROR(convention_attribute_expected_name,attribute_parsing,none, +ERROR(convention_attribute_expected_name,none, "expected convention name identifier in 'convention' attribute", ()) -ERROR(convention_attribute_expected_rparen,attribute_parsing,none, +ERROR(convention_attribute_expected_rparen,none, "expected ')' after convention name for 'convention' attribute", ()) // objc -ERROR(attr_objc_missing_colon,attribute_parsing,none, +ERROR(attr_objc_missing_colon,none, "missing ':' after selector piece in @objc attribute", ()) -ERROR(attr_objc_expected_rparen,attribute_parsing,none, +ERROR(attr_objc_expected_rparen,none, "expected ')' after name for @objc", ()) -ERROR(attr_objc_empty_name,attribute_parsing,none, +ERROR(attr_objc_empty_name,none, "expected name within parentheses of @objc attribute", ()) // opened -ERROR(opened_attribute_expected_lparen,attribute_parsing,none, +ERROR(opened_attribute_expected_lparen,none, "expected '(' after 'opened' attribute", ()) -ERROR(opened_attribute_id_value,attribute_parsing,none, +ERROR(opened_attribute_id_value,none, "known id for 'opened' attribute must be a UUID string", ()) -ERROR(opened_attribute_expected_rparen,attribute_parsing,none, +ERROR(opened_attribute_expected_rparen,none, "expected ')' after id value for 'opened' attribute", ()) // inline -ERROR(inline_attribute_expect_option,attribute_parsing,none, +ERROR(inline_attribute_expect_option,none, "expected '%0' option such as 'never'", (StringRef)) -ERROR(inline_attribute_unknown_option,attribute_parsing,none, +ERROR(inline_attribute_unknown_option,none, "unknown option '%0' for attribute '%1'", (StringRef, StringRef)) // effects -ERROR(effects_attribute_expect_option,attribute_parsing,none, +ERROR(effects_attribute_expect_option,none, "expected '%0' option (readnone, readonly, readwrite)", (StringRef)) -ERROR(effects_attribute_unknown_option,attribute_parsing,none, +ERROR(effects_attribute_unknown_option,none, "unknown option '%0' for attribute '%1'", (StringRef, StringRef)) +// swift3_migration +ERROR(attr_swift3_migration_label,none, + "expected 'renamed' or 'message' in 'swift3_migration' attribute", ()) +WARNING(warn_attr_swift3_migration_unknown_label,none, + "expected 'renamed' or 'message' in 'swift3_migration' attribute", ()) +ERROR(attr_swift3_migration_expected_rparen,none, + "expected ')' after name for 'swift3_migration' attribute", ()) +ERROR(attr_bad_swift_name,none, + "ill-formed Swift name '%0'", (StringRef)) + + // unowned -ERROR(attr_unowned_invalid_specifier,attribute_parsing,none, +ERROR(attr_unowned_invalid_specifier,none, "expected 'safe' or 'unsafe'", ()) -ERROR(attr_unowned_expected_rparen,attribute_parsing,none, +ERROR(attr_unowned_expected_rparen,none, "expected ')' after specifier for 'unowned'", ()) // warn_unused_result -WARNING(attr_warn_unused_result_expected_name,attribute_parsing,none, +WARNING(attr_warn_unused_result_expected_name,none, "expected parameter 'message' or 'mutable_variant'", ()) -WARNING(attr_warn_unused_result_duplicate_parameter,attribute_parsing,none, +WARNING(attr_warn_unused_result_duplicate_parameter,none, "duplicate '%0' parameter; previous value will be ignored", (StringRef)) -ERROR(attr_warn_unused_result_expected_eq,attribute_parsing,none, +ERROR(attr_warn_unused_result_expected_eq,none, "expected '=' following '%0' parameter", (StringRef)) -ERROR(attr_warn_unused_result_expected_string,attribute_parsing,none, +ERROR(attr_warn_unused_result_expected_string,none, "expected a string following '=' for '%0' parameter", (StringRef)) -WARNING(attr_warn_unused_result_unknown_parameter,attribute_parsing,none, +WARNING(attr_warn_unused_result_unknown_parameter,none, "unknown parameter '%0' in 'warn_unused_result' attribute", (StringRef)) -ERROR(attr_warn_unused_result_expected_rparen,attribute_parsing,none, +ERROR(attr_warn_unused_result_expected_rparen,none, "expected ')' after 'warn_unused_result' attribute", ()) //------------------------------------------------------------------------------ // Generics parsing diagnostics //------------------------------------------------------------------------------ -ERROR(expected_rangle_generics_param,parsing,PointsToFirstBadToken, +ERROR(expected_rangle_generics_param,PointsToFirstBadToken, "expected '>' to complete generic parameter list", ()) -ERROR(expected_generics_parameter_name,parsing,PointsToFirstBadToken, +ERROR(expected_generics_parameter_name,PointsToFirstBadToken, "expected an identifier to name generic parameter", ()) -ERROR(expected_generics_type_restriction,parsing,none, +ERROR(expected_generics_type_restriction,none, "expected a type name or protocol composition restricting %0", (Identifier)) -ERROR(requires_single_equal,parsing,none, +ERROR(requires_single_equal,none, "use '==' for same-type requirements rather than '='", ()) -ERROR(expected_requirement_delim,parsing,none, +ERROR(expected_requirement_delim,none, "expected ':' or '==' to indicate a conformance or same-type requirement", ()) -ERROR(invalid_class_requirement,decl_parsing,none, +ERROR(invalid_class_requirement,none, "'class' requirement only applies to protocols", ()) -ERROR(redundant_class_requirement,decl_parsing,none, +ERROR(redundant_class_requirement,none, "redundant 'class' requirement", ()) -ERROR(late_class_requirement,decl_parsing,none, +ERROR(late_class_requirement,none, "'class' must come first in the requirement list", ()) //------------------------------------------------------------------------------ // Build configuration parsing diagnostics //------------------------------------------------------------------------------ -ERROR(unsupported_build_config_binary_expression,parsing,none, +ERROR(unsupported_build_config_binary_expression,none, "expected '&&' or '||' expression", ()) -ERROR(unsupported_build_config_unary_expression,parsing,none, +ERROR(unsupported_build_config_unary_expression,none, "expected unary '!' expression", ()) -ERROR(unsupported_target_config_expression,parsing,none, - "unexpected target configuration expression (expected 'os' or 'arch')",()) -ERROR(unsupported_target_config_runtime_argument,parsing,none, +ERROR(unsupported_target_config_expression,none, + "unexpected target configuration expression (expected 'os', 'arch', or 'swift')", + ()) +ERROR(target_config_expected_one_argument,none, + "expected only one argument to target configuration expression", + ()) +ERROR(unsupported_target_config_runtime_argument,none, "unexpected argument for the '_runtime' target configuration, " "expected '_Native' or '_ObjC'", ()) -ERROR(unsupported_target_config_argument,parsing,none, - "unexpected target configuration expression argument: expected %0", +ERROR(unsupported_target_config_argument,none, + "unexpected target configuration argument: expected %0", (StringRef)) -ERROR(unsupported_config_conditional_expression_type,parsing,none, +ERROR(unexpected_version_comparison_operator,none, + "expected '>=' prefix operator on a version requirement", + ()) +ERROR(unsupported_config_conditional_expression_type,none, "unexpected configuration expression type", ()) -ERROR(unsupported_config_integer,parsing,none, +ERROR(unsupported_config_integer,none, "'%0' is not a valid configuration option, use '%1'", (StringRef, StringRef)) -ERROR(compiler_version_component_not_number,parsing,none, - "compiler version component is not a number", ()) -ERROR(compiler_version_too_many_components,parsing,none, +ERROR(version_component_not_number,none, + "version component contains non-numeric characters", ()) +ERROR(compiler_version_too_many_components,none, "compiler version must not have more than five components", ()) -WARNING(unused_compiler_version_component,parsing,none, +WARNING(unused_compiler_version_component,none, "the second version component is not used for comparison", ()) -ERROR(empty_compiler_version_component,parsing,none, - "found empty compiler version component", ()) -ERROR(compiler_version_component_out_of_range,parsing,none, +ERROR(empty_version_component,none, + "found empty version component", ()) +ERROR(compiler_version_component_out_of_range,none, "compiler version component out of range: must be in [0, %0]", (unsigned)) -ERROR(empty_compiler_version_string,parsing,none, - "compiler version requirement is empty", ()) -ERROR(cannot_combine_compiler_version,parsing,none, - "cannot combine _compiler_version with binary operators", ()) -WARNING(unknown_build_config,parsing,none, +ERROR(empty_version_string,none, + "version requirement is empty", ()) +WARNING(unknown_build_config,none, "unknown %0 for build configuration '%1'", (StringRef, StringRef)) //------------------------------------------------------------------------------ // Availability query parsing diagnostics //------------------------------------------------------------------------------ -ERROR(avail_query_not_enabled,parsing,Fatal, - "experimental availability checking not enabled", ()) - -ERROR(avail_query_expected_condition,parsing,PointsToFirstBadToken, +ERROR(avail_query_expected_condition,PointsToFirstBadToken, "expected availability condition", ()) -ERROR(avail_query_expected_platform_name,parsing,PointsToFirstBadToken, +ERROR(avail_query_expected_platform_name,PointsToFirstBadToken, "expected platform name", ()) -ERROR(avail_query_expected_version_number,parsing,PointsToFirstBadToken, +ERROR(avail_query_expected_version_number,PointsToFirstBadToken, "expected version number", ()) -ERROR(avail_query_expected_rparen,parsing,PointsToFirstBadToken, +ERROR(avail_query_expected_rparen,PointsToFirstBadToken, "expected ')' in availability query", ()) -ERROR(avail_query_unrecognized_platform_name,parsing, +ERROR(avail_query_unrecognized_platform_name, PointsToFirstBadToken, "unrecognized platform name %0", (Identifier)) -ERROR(avail_query_disallowed_operator,parsing, PointsToFirstBadToken, +ERROR(avail_query_disallowed_operator, PointsToFirstBadToken, "'%0' cannot be used in an availability condition", (StringRef)) -ERROR(avail_query_version_comparison_not_needed,parsing, +ERROR(avail_query_version_comparison_not_needed, none,"version comparison not needed", ()) -ERROR(availability_query_wildcard_required, parsing, none, +ERROR(availability_query_wildcard_required, none, "must handle potential future platforms with '*'", ()) -ERROR(availability_query_repeated_platform, parsing, none, +ERROR(availability_query_repeated_platform, none, "version for '%0' already specified", (StringRef)) #ifndef DIAG_NO_UNDEF diff --git a/include/swift/AST/DiagnosticsParse.h b/include/swift/AST/DiagnosticsParse.h index e50840cfb8fd1..8108431f693c9 100644 --- a/include/swift/AST/DiagnosticsParse.h +++ b/include/swift/AST/DiagnosticsParse.h @@ -1,8 +1,8 @@ -//===- DiagnosticsParse.h - Diagnostic Definitions --------------*- C++ -*-===// +//===--- DiagnosticsParse.h - Diagnostic Definitions ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsParse.def" } diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index a75690c391399..36bd41c2699d6 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -1,8 +1,8 @@ -//===- DiagnosticsSILAnalysis.def - Diagnostics Text ------------*- C++ -*-===// +//===--- DiagnosticsSIL.def - Diagnostics Text ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,230 +22,236 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif // SILGen issues. -ERROR(bridging_module_missing,sil_gen,none, +ERROR(bridging_module_missing,none, "unable to find module '%0' for implicit conversion function '%0.%1'", (StringRef, StringRef)) -ERROR(bridging_function_missing,sil_gen,none, +ERROR(bridging_function_missing,none, "unable to find implicit conversion function '%0.%1'", (StringRef, StringRef)) -ERROR(bridging_function_overloaded,sil_gen,none, +ERROR(bridging_function_overloaded,none, "multiple definitions of implicit conversion function '%0.%1'", (StringRef, StringRef)) -ERROR(bridging_function_not_function,sil_gen,none, +ERROR(bridging_function_not_function,none, "definition of implicit conversion function '%0.%1' is not a function", (StringRef, StringRef)) -ERROR(bridging_function_not_correct_type,sil_gen,none, +ERROR(bridging_function_not_correct_type,none, "definition of implicit conversion function '%0.%1' is not of the correct" " type", (StringRef, StringRef)) -ERROR(invalid_sil_builtin,sil_gen,none, +ERROR(invalid_sil_builtin,none, "INTERNAL ERROR: invalid use of builtin: %0", (StringRef)) -ERROR(could_not_find_bridge_type,sil_gen,none, +ERROR(could_not_find_bridge_type,none, "could not find Objective-C bridge type for type %0; " "did you forget to import Foundation?", (Type)) -ERROR(could_not_find_pointer_memory_property,sil_gen,none, +ERROR(could_not_find_pointer_memory_property,none, "could not find 'memory' property of pointer type %0", (Type)) -ERROR(writeback_overlap_property,sil_gen,none, +ERROR(writeback_overlap_property,none, "inout writeback to computed property %0 occurs in multiple arguments to" " call, introducing invalid aliasing", (Identifier)) -ERROR(writeback_overlap_subscript,sil_gen,none, +ERROR(writeback_overlap_subscript,none, "inout writeback through subscript occurs in multiple arguments to call," " introducing invalid aliasing", ()) -NOTE(writebackoverlap_note,sil_gen,none, +NOTE(writebackoverlap_note,none, "concurrent writeback occurred here", ()) -ERROR(inout_argument_alias,sil_gen,none, +ERROR(inout_argument_alias,none, "inout arguments are not allowed to alias each other", ()) -NOTE(previous_inout_alias,sil_gen,none, +NOTE(previous_inout_alias,none, "previous aliasing argument", ()) -ERROR(unsupported_recursive_type,sil_gen,none, +ERROR(unsupported_recursive_type,none, "recursive value type %0 is not allowed", (Type)) -ERROR(recursive_enum_not_indirect,sil_gen,none, +ERROR(recursive_enum_not_indirect,none, "recursive enum %0 is not marked 'indirect'", (Type)) -ERROR(unsupported_c_function_pointer_conversion,sil_gen,none, +ERROR(unsupported_c_function_pointer_conversion,none, "C function pointer signature %0 is not compatible with expected type %1", (Type, Type)) +ERROR(objc_selector_malformed,none,"the type ObjectiveC.Selector is malformed", + ()) + // Definite initialization diagnostics. -NOTE(variable_defined_here,sil_analysis,none, +NOTE(variable_defined_here,none, "%select{variable|constant}0 defined here", (bool)) -ERROR(variable_used_before_initialized,sil_analysis,none, +ERROR(variable_used_before_initialized,none, "%select{variable|constant}1 '%0' used before being initialized", (StringRef, bool)) -ERROR(variable_inout_before_initialized,sil_analysis,none, +ERROR(variable_inout_before_initialized,none, "%select{variable|constant}1 '%0' passed by reference before being" " initialized", (StringRef, bool)) -ERROR(variable_closure_use_uninit,sil_analysis,none, +ERROR(variable_closure_use_uninit,none, "%select{variable|constant}1 '%0' captured by a closure before being" " initialized", (StringRef, bool)) +ERROR(self_closure_use_uninit,none, + "'self' captured by a closure before all members were initialized", ()) + -ERROR(variable_addrtaken_before_initialized,sil_analysis,none, +ERROR(variable_addrtaken_before_initialized,none, "address of %select{variable|constant}1 '%0' taken before it is" " initialized", (StringRef, bool)) -ERROR(ivar_not_initialized_at_superinit,sil_analysis,none, +ERROR(ivar_not_initialized_at_superinit,none, "property '%0' not initialized at super.init call", (StringRef, bool)) -ERROR(ivar_not_initialized_at_implicit_superinit,sil_analysis,none, +ERROR(ivar_not_initialized_at_implicit_superinit,none, "property '%0' not initialized at implicitly generated super.init call", (StringRef, bool)) -ERROR(self_use_before_fully_init,sil_analysis,none, +ERROR(self_use_before_fully_init,none, "use of 'self' in %select{method call|property access}1 %0 before " "%select{all stored properties are initialized|" "super.init initializes self|" "self.init initializes self}2", (Identifier, bool, unsigned)) -ERROR(use_of_self_before_fully_init,sil_analysis,none, +ERROR(use_of_self_before_fully_init,none, "'self' used before all stored properties are initialized", ()) -ERROR(use_of_self_before_fully_init_protocol,sil_analysis,none, +ERROR(use_of_self_before_fully_init_protocol,none, "'self' used before chaining to another self.init requirement", ()) -NOTE(stored_property_not_initialized,sil_analysis,none, +NOTE(stored_property_not_initialized,none, "'%0' not initialized", (StringRef)) -ERROR(selfinit_multiple_times,sil_analysis,none, +ERROR(selfinit_multiple_times,none, "%select{super|self}0.init called multiple times in initializer", (unsigned)) -ERROR(superselfinit_not_called_before_return,sil_analysis,none, +ERROR(superselfinit_not_called_before_return,none, "%select{super|self}0.init isn't called on all paths before returning " "from initializer", (unsigned)) -ERROR(self_before_superselfinit,sil_analysis,none, +ERROR(self_before_superselfinit,none, "'self' used before %select{super|self}0.init call", (unsigned)) -ERROR(self_inside_catch_superselfinit,sil_analysis,none, +ERROR(self_inside_catch_superselfinit,none, "'self' used inside 'catch' block reachable from " "%select{super|self}0.init call", (unsigned)) -ERROR(return_from_init_without_initing_self,sil_analysis,none, +ERROR(return_from_init_without_initing_self,none, "return from enum initializer method without storing to 'self'", ()) -ERROR(return_from_protocol_init_without_initing_self,sil_analysis,none, +ERROR(return_from_protocol_init_without_initing_self,none, "protocol extension initializer never chained to 'self.init'", ()) -ERROR(return_from_init_without_initing_stored_properties,sil_analysis,none, +ERROR(return_from_init_without_initing_stored_properties,none, "return from initializer without initializing all" " stored properties", ()) -ERROR(variable_function_use_uninit,sil_analysis,none, +ERROR(variable_function_use_uninit,none, "%select{variable|constant}1 '%0' used by function definition before" " being initialized", (StringRef, bool)) -ERROR(struct_not_fully_initialized,sil_analysis,none, +ERROR(struct_not_fully_initialized,none, "struct '%0' must be completely initialized before a member is stored to", (StringRef, bool)) -ERROR(immutable_property_already_initialized,sil_analysis,none, +ERROR(immutable_property_already_initialized,none, "immutable value '%0' may only be initialized once", (StringRef)) -NOTE(initial_value_provided_in_let_decl,sil_analysis,none, +NOTE(initial_value_provided_in_let_decl,none, "initial value already provided in 'let' declaration", ()) -ERROR(mutating_method_called_on_immutable_value,sil_analysis,none, +ERROR(mutating_method_called_on_immutable_value,none, "mutating %select{method|property access|subscript|operator}1 %0 may not" " be used on immutable value '%2'", (Identifier, unsigned, StringRef)) -ERROR(immutable_value_passed_inout,sil_analysis,none, +ERROR(immutable_value_passed_inout,none, "immutable value '%0' may not be passed inout", (StringRef)) -ERROR(assignment_to_immutable_value,sil_analysis,none, +ERROR(assignment_to_immutable_value,none, "immutable value '%0' may not be assigned to", (StringRef)) // Control flow diagnostics. -ERROR(missing_return,sil_analysis,none, +ERROR(missing_return,none, "missing return in a %select{function|closure}1 expected to return %0", (Type, unsigned)) -ERROR(return_from_noreturn,sil_analysis,none, +ERROR(return_from_noreturn,none, "return from a 'noreturn' function", ()) -ERROR(non_exhaustive_switch,sil_analysis,none, +ERROR(non_exhaustive_switch,none, "switch must be exhaustive, consider adding a default clause", ()) -ERROR(guard_body_must_not_fallthrough,sil_analysis,none, +ERROR(guard_body_must_not_fallthrough,none, "'guard' body may not fall through, consider using 'return' or 'break'" " to exit the scope", ()) -WARNING(unreachable_code,sil_analysis,none, "will never be executed", ()) -NOTE(unreachable_code_branch,sil_analysis,none, +WARNING(unreachable_code,none, "will never be executed", ()) +NOTE(unreachable_code_branch,none, "condition always evaluates to %select{false|true}0", (bool)) -NOTE(call_to_noreturn_note,sil_analysis,none, +NOTE(call_to_noreturn_note,none, "a call to a noreturn function", ()) -WARNING(unreachable_code_after_stmt,sil_analysis,none, +WARNING(unreachable_code_after_stmt,none, "code after '%select{return|break|continue|throw}0' will never " "be executed", (unsigned)) -WARNING(unreachable_case,sil_analysis,none, +WARNING(unreachable_case,none, "%select{case|default}0 will never be executed", (bool)) -WARNING(switch_on_a_constant,sil_analysis,none, +WARNING(switch_on_a_constant,none, "switch condition evaluates to a constant", ()) -NOTE(unreachable_code_note,sil_analysis,none, "will never be executed", ()) +NOTE(unreachable_code_note,none, "will never be executed", ()) // 'transparent' diagnostics -ERROR(circular_transparent,sil_analysis,none, +ERROR(circular_transparent,none, "inlining 'transparent' functions forms circular loop", ()) -NOTE(note_while_inlining,sil_analysis,none, +NOTE(note_while_inlining,none, "while inlining here", ()) // Arithmetic diagnostics. -ERROR(integer_conversion_overflow,sil_analysis,none, +ERROR(integer_conversion_overflow,none, "integer overflows when converted from %0 to %1", (Type, Type)) -ERROR(integer_conversion_overflow_builtin_types,sil_analysis,none, +ERROR(integer_conversion_overflow_builtin_types,none, "integer overflows when converted from %select{unsigned|signed}0 " "%1 to %select{unsigned|signed}2 %3", (bool, Type, bool, Type)) -WARNING(integer_conversion_overflow_warn,sil_analysis,none, +WARNING(integer_conversion_overflow_warn,none, "integer overflows when converted from %0 to %1", (Type, Type)) -ERROR(integer_conversion_sign_error,sil_analysis,none, +ERROR(integer_conversion_sign_error,none, "negative integer cannot be converted to unsigned type %0", (Type)) -ERROR(negative_integer_literal_overflow_unsigned,sil_analysis,none, +ERROR(negative_integer_literal_overflow_unsigned,none, "negative integer '%1' overflows when stored into unsigned type %0", (Type, StringRef)) -ERROR(integer_literal_overflow,sil_analysis,none, +ERROR(integer_literal_overflow,none, "integer literal '%1' overflows when stored into %0", (Type, StringRef)) -ERROR(integer_literal_overflow_builtin_types,sil_analysis,none, +ERROR(integer_literal_overflow_builtin_types,none, "integer literal '%2' overflows when stored into " "%select{unsigned|signed}0 %1", (bool, Type, StringRef)) -WARNING(integer_literal_overflow_warn,sil_analysis,none, +WARNING(integer_literal_overflow_warn,none, "integer literal overflows when stored into %0", (Type)) -ERROR(arithmetic_operation_overflow,sil_analysis,none, +ERROR(arithmetic_operation_overflow,none, "arithmetic operation '%0 %1 %2' (on type %3) results in an overflow", (StringRef, StringRef, StringRef, Type)) -ERROR(arithmetic_operation_overflow_generic_type,sil_analysis,none, +ERROR(arithmetic_operation_overflow_generic_type,none, "arithmetic operation '%0 %1 %2' (on %select{unsigned|signed}3 " "%4-bit integer type) results in an overflow", (StringRef, StringRef, StringRef, bool, unsigned)) -ERROR(division_overflow,sil_analysis,none, +ERROR(division_overflow,none, "division '%0 %1 %2' results in an overflow", (StringRef, StringRef, StringRef)) -ERROR(division_by_zero,sil_analysis,none, "division by zero", ()) -ERROR(wrong_non_negative_assumption,sil_analysis,none, +ERROR(division_by_zero,none, "division by zero", ()) +ERROR(wrong_non_negative_assumption,none, "assumed non-negative value '%0' is negative", (StringRef)) -ERROR(shifting_all_significant_bits,sil_analysis,none, +ERROR(shifting_all_significant_bits,none, "shift amount is greater than or equal to type size in bits", ()) // FIXME: We won't need this as it will be replaced with user-generated strings. // staticReport diagnostics. -ERROR(static_report_error, sil_analysis, none, +ERROR(static_report_error, none, "static report error", ()) diff --git a/include/swift/AST/DiagnosticsSIL.h b/include/swift/AST/DiagnosticsSIL.h index 7c9e24d2c11a7..bc9b47164baea 100644 --- a/include/swift/AST/DiagnosticsSIL.h +++ b/include/swift/AST/DiagnosticsSIL.h @@ -1,8 +1,8 @@ -//===- DiagnosticsSIL.h - Diagnostic Definitions ----------------*- C++ -*-===// +//===--- DiagnosticsSIL.h - Diagnostic Definitions --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsSIL.def" } diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ba12db1bc9f72..2977008b5a04a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1,8 +1,8 @@ -//===- DiagnosticsSema.def - Diagnostics Text -------------------*- C++ -*-===// +//===--- DiagnosticsSema.def - Diagnostics Text -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,888 +23,970 @@ #endif #ifndef ERROR -# define ERROR(ID,Category,Options,Text,Signature) \ - DIAG(ERROR,ID,Category,Options,Text,Signature) +# define ERROR(ID,Options,Text,Signature) \ + DIAG(ERROR,ID,Options,Text,Signature) #endif #ifndef WARNING -# define WARNING(ID,Category,Options,Text,Signature) \ - DIAG(WARNING,ID,Category,Options,Text,Signature) +# define WARNING(ID,Options,Text,Signature) \ + DIAG(WARNING,ID,Options,Text,Signature) #endif #ifndef NOTE -# define NOTE(ID,Category,Options,Text,Signature) \ - DIAG(NOTE,ID,Category,Options,Text,Signature) +# define NOTE(ID,Options,Text,Signature) \ + DIAG(NOTE,ID,Options,Text,Signature) #endif -NOTE(type_declared_here,sema,none, +NOTE(type_declared_here,none, "type declared here", ()) -NOTE(decl_declared_here,sema,none, - "%0 declared here", (Identifier)) -NOTE(extended_type_declared_here,sema,none, +NOTE(decl_declared_here,none, + "%0 declared here", (DeclName)) +NOTE(extended_type_declared_here,none, "extended type declared here", ()) -NOTE(while_converting_default_tuple_value,sema,none, +NOTE(while_converting_default_tuple_value,none, "while converting default tuple value to element type %0", (Type)) -NOTE(while_converting_subscript_index,sema,none, +NOTE(while_converting_subscript_index,none, "while converting subscript index to expected type %0", (Type)) //------------------------------------------------------------------------------ // Constraint solver diagnostics //------------------------------------------------------------------------------ -ERROR(ambiguous_member_overload_set,sema,none, - "ambiguous reference to member '%0'", (StringRef)) +ERROR(ambiguous_member_overload_set,none, + "ambiguous reference to member %0", (DeclName)) -ERROR(ambiguous_subscript,sema,none, +ERROR(ambiguous_subscript,none, "ambiguous subscript with base type %0 and index type %1", (Type, Type)) -ERROR(type_not_subscriptable,sema,none, +ERROR(type_not_subscriptable,none, "type %0 has no subscript members", (Type)) -ERROR(could_not_find_tuple_member,sema,none, +ERROR(could_not_find_tuple_member,none, "value of tuple type %0 has no member %1", (Type, DeclName)) -ERROR(could_not_find_value_member,sema,none, +ERROR(could_not_find_value_member,none, "value of type %0 has no member %1", (Type, DeclName)) -ERROR(could_not_find_type_member,sema,none, +ERROR(could_not_find_type_member,none, "type %0 has no member %1", (Type, DeclName)) -ERROR(expected_argument_in_contextual_member,sema,none, - "contextual member %0 expects argument of type %1", (Identifier, Type)) -ERROR(unexpected_argument_in_contextual_member,sema,none, - "contextual member %0 has no associated value", (Identifier)) +NOTE(did_you_mean_raw_type,none, + "did you mean to specify a raw type on the enum declaration?", ()) + +ERROR(expected_argument_in_contextual_member,none, + "contextual member %0 expects argument of type %1", (DeclName, Type)) + +ERROR(expected_result_in_contextual_member,none, + "member %0 in %2 produces result of type %1, but context expects %2", + (DeclName, Type, Type)) -ERROR(could_not_use_value_member,sema,none, +ERROR(unexpected_argument_in_contextual_member,none, + "contextual member %0 has no associated value", (DeclName)) + +ERROR(could_not_use_value_member,none, "member %1 cannot be used on value of type %0", (Type, DeclName)) -ERROR(could_not_use_type_member,sema,none, +ERROR(could_not_use_type_member,none, "member %1 cannot be used on type %0", (Type, DeclName)) -ERROR(could_not_use_type_member_on_instance,sema,none, +ERROR(could_not_use_type_member_on_instance,none, "static member %1 cannot be used on instance of type %0", (Type, DeclName)) -ERROR(could_not_use_instance_member_on_type,sema,none, +ERROR(could_not_use_instance_member_on_type,none, "instance member %1 cannot be used on type %0", (Type, DeclName)) -ERROR(could_not_use_member_on_existential,sema,none, +ERROR(could_not_use_member_on_existential,none, "member %1 cannot be used on value of protocol type %0; use a generic" " constraint instead", (Type, DeclName)) +ERROR(candidate_inaccessible,none, + "%0 is inaccessible due to '%select{private|internal|PUBLIC}1' " + "protection level", (DeclName, Accessibility)) + +ERROR(init_candidate_inaccessible,none, + "%0 initializer is inaccessible due to '%select{private|internal|PUBLIC}1' " + "protection level", (Type, Accessibility)) + -ERROR(cannot_pass_rvalue_mutating_subelement,sema_tcs,none, +ERROR(cannot_pass_rvalue_mutating_subelement,none, "cannot use mutating member on immutable value: %0", (StringRef)) -ERROR(cannot_pass_rvalue_mutating,sema_tcs,none, +ERROR(cannot_pass_rvalue_mutating,none, "cannot use mutating member on immutable value of type %0", (Type)) -ERROR(cannot_pass_rvalue_mutating_getter_subelement,sema_tcs,none, +ERROR(cannot_pass_rvalue_mutating_getter_subelement,none, "cannot use mutating getter on immutable value: %0", (StringRef)) -ERROR(cannot_pass_rvalue_mutating_getter,sema_tcs,none, +ERROR(cannot_pass_rvalue_mutating_getter,none, "cannot use mutating getter on immutable value of type %0", (Type)) -ERROR(expression_too_complex,sema,none, +ERROR(expression_too_complex,none, "expression was too complex to be solved in reasonable time; " "consider breaking up the expression into distinct sub-expressions", ()) -ERROR(comparison_with_nil_illegal,sema,none, +ERROR(comparison_with_nil_illegal,none, "value of type %0 can never be nil, comparison isn't allowed", (Type)) -ERROR(cannot_match_expr_pattern_with_value,sema,none, +ERROR(cannot_match_expr_pattern_with_value,none, "expression pattern of type %0 cannot match values of type %1", (Type, Type)) -ERROR(cannot_apply_binop_to_args,sema,none, +ERROR(cannot_apply_binop_to_args,none, "binary operator '%0' cannot be applied to operands of type " "%1 and %2", (StringRef, Type, Type)) -ERROR(cannot_apply_binop_to_same_args,sema,none, +ERROR(cannot_apply_binop_to_same_args,none, "binary operator '%0' cannot be applied to two %1 operands", (StringRef, Type)) -ERROR(cannot_apply_unop_to_arg,sema,none, +ERROR(cannot_apply_unop_to_arg,none, "unary operator '%0' cannot be applied to an operand of type %1", (StringRef, Type)) -ERROR(cannot_apply_lvalue_unop_to_subelement,sema_tcs,none, +ERROR(cannot_apply_lvalue_unop_to_subelement,none, "cannot pass immutable value to mutating operator: %0", (StringRef)) -ERROR(cannot_apply_lvalue_unop_to_rvalue,sema,none, +ERROR(cannot_apply_lvalue_unop_to_rvalue,none, "cannot pass immutable value of type %0 to mutating operator", (Type)) -ERROR(cannot_apply_lvalue_binop_to_subelement,sema_tcs,none, +ERROR(cannot_apply_lvalue_binop_to_subelement,none, "left side of mutating operator isn't mutable: %0", (StringRef)) -ERROR(cannot_apply_lvalue_binop_to_rvalue,sema,none, +ERROR(cannot_apply_lvalue_binop_to_rvalue,none, "left side of mutating operator has immutable type %0", (Type)) -ERROR(cannot_subscript_with_index,sema,none, +ERROR(cannot_subscript_with_index,none, "cannot subscript a value of type %0 with an index of type %1", (Type, Type)) -ERROR(cannot_subscript_base,sema,none, +ERROR(cannot_subscript_base,none, "cannot subscript a value of type %0", (Type)) -ERROR(cannot_pass_rvalue_inout_subelement,sema_tcs,none, +ERROR(cannot_pass_rvalue_inout_subelement,none, "cannot pass immutable value as inout argument: %0", (StringRef)) -ERROR(cannot_pass_rvalue_inout,sema_tcs,none, +ERROR(cannot_pass_rvalue_inout,none, "cannot pass immutable value of type %0 as inout argument", (Type)) -ERROR(cannot_assign_to_literal,sema,none, +ERROR(cannot_assign_to_literal,none, "cannot assign to a literal value", ()) -ERROR(cannot_call_with_no_params,sema,none, +ERROR(cannot_call_with_no_params,none, "cannot invoke %select{|initializer for type }1'%0' with no arguments", (StringRef, bool)) -ERROR(cannot_call_with_params, sema, none, +ERROR(cannot_call_with_params, none, "cannot invoke %select{|initializer for type }2'%0' with an argument list" " of type '%1'", (StringRef, StringRef, bool)) -ERROR(expected_do_in_statement,sema,none, +ERROR(expected_do_in_statement,none, "expected 'do' keyword to designate a block of statements", ()) -ERROR(cannot_call_non_function_value,sema,none, +ERROR(cannot_call_non_function_value,none, "cannot call value of non-function type %0", (Type)) -ERROR(wrong_argument_labels_overload,sema,none, +ERROR(wrong_argument_labels_overload,none, "argument labels '%0' do not match any available overloads", (StringRef)) -ERROR(no_candidates_match_result_type,sema,none, +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,sema,none, +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,sema,none, +ERROR(invalid_callee_result_type,none, "cannot convert call result type %0 to expected type %1", (Type, Type)) -ERROR(cannot_invoke_closure,sema,none, +ERROR(cannot_invoke_closure,none, "cannot invoke closure expression with an argument list of type '%0'", (StringRef)) -ERROR(cannot_invoke_closure_type,sema,none, +ERROR(cannot_invoke_closure_type,none, "cannot invoke closure of type %0 with an argument list of type '%1'", (Type, StringRef)) -ERROR(cannot_infer_closure_type,sema,none, +ERROR(cannot_infer_closure_type,none, "unable to infer closure type in the current context", ()) -ERROR(cannot_infer_closure_result_type,sema,none, +ERROR(cannot_infer_closure_result_type,none, "unable to infer closure return type in current context", ()) -ERROR(incorrect_explicit_closure_result,sema,none, +ERROR(incorrect_explicit_closure_result,none, "declared closure result %0 is incompatible with contextual type %1", (Type, Type)) -ERROR(cannot_call_function_value,sema,none, +ERROR(cannot_call_function_value,none, "cannot invoke value of function type with argument list '%0'", (StringRef)) -ERROR(cannot_call_value_of_function_type,sema,none, +ERROR(cannot_call_value_of_function_type,none, "cannot invoke value of type %0 with argument list '%1'", (Type, StringRef)) -NOTE(suggest_expected_match,sema,none, +NOTE(suggest_expected_match,none, "%select{expected an argument list|produces result}0 of type '%1'", (bool, StringRef)) -NOTE(suggest_partial_overloads,sema,none, +NOTE(suggest_partial_overloads,none, "overloads for '%1' exist with these %select{" "partially matching parameter lists|result types}0: %2", (bool, StringRef, StringRef)) -ERROR(cannot_convert_initializer_value,sema,none, +ERROR(cannot_convert_initializer_value,none, "cannot convert value of type %0 to specified type %1", (Type,Type)) -ERROR(cannot_convert_initializer_value_protocol,sema,none, +ERROR(cannot_convert_initializer_value_protocol,none, "value of type %0 does not conform to specified type %1", (Type,Type)) -ERROR(cannot_convert_initializer_value_nil,sema_tcd,none, +ERROR(cannot_convert_initializer_value_nil,none, "nil cannot initialize specified type %0", (Type)) -ERROR(cannot_convert_to_return_type,sema,none, +ERROR(cannot_convert_to_return_type,none, "cannot convert return expression of type %0 to return type %1", (Type,Type)) -ERROR(cannot_convert_to_return_type_protocol,sema,none, +ERROR(cannot_convert_to_return_type_protocol,none, "return expression of type %0 does not conform to %1", (Type,Type)) -ERROR(cannot_convert_to_return_type_nil,sema,none, +ERROR(cannot_convert_to_return_type_nil,none, "nil is incompatible with return type %0", (Type)) -ERROR(cannot_convert_thrown_type,sema,none, +ERROR(cannot_convert_thrown_type,none, "thrown expression type %0 does not conform to 'ErrorType'", (Type)) -ERROR(cannot_throw_nil,sema,none, +ERROR(cannot_throw_nil,none, "cannot infer concrete ErrorType for thrown 'nil' value", ()) -ERROR(cannot_convert_raw_initializer_value,sema,none, +ERROR(cannot_convert_raw_initializer_value,none, "cannot convert value of type %0 to raw type %1", (Type,Type)) -ERROR(cannot_convert_raw_initializer_value_nil,sema,none, - "cannot convert nil to raw type %1", (Type)) +ERROR(cannot_convert_raw_initializer_value_nil,none, + "cannot convert nil to raw type %0", (Type)) -ERROR(cannot_convert_default_arg_value,sema,none, +ERROR(cannot_convert_default_arg_value,none, "default argument value of type %0 cannot be converted to type %1", (Type,Type)) -ERROR(cannot_convert_default_arg_value_protocol,sema,none, +ERROR(cannot_convert_default_arg_value_protocol,none, "default argument value of type %0 does not conform to %1", (Type,Type)) -ERROR(cannot_convert_default_arg_value_nil,sema,none, +ERROR(cannot_convert_default_arg_value_nil,none, "nil default argument value of cannot be converted to type %0", (Type)) -ERROR(cannot_convert_argument_value,sema,none, +ERROR(cannot_convert_argument_value,none, "cannot convert value of type %0 to expected argument type %1", (Type,Type)) -ERROR(cannot_convert_argument_value_protocol,sema_tcd,none, +ERROR(cannot_convert_argument_value_protocol,none, "argument type %0 does not conform to expected type %1", (Type, Type)) -ERROR(cannot_convert_argument_value_nil,sema,none, +ERROR(cannot_convert_argument_value_nil,none, "nil is not compatible with expected argument type %0", (Type)) -ERROR(cannot_convert_closure_result,sema,none, +ERROR(cannot_convert_closure_result,none, "cannot convert value of type %0 to closure result type %1", (Type,Type)) -ERROR(cannot_convert_closure_result_protocol,sema_tcd,none, +ERROR(cannot_convert_closure_result_protocol,none, "result value of type %0 does not conform to closure result type %1", (Type, Type)) -ERROR(cannot_convert_closure_result_nil,sema,none, +ERROR(cannot_convert_closure_result_nil,none, "nil is not compatible with closure result type %0", (Type)) // Array Element -ERROR(cannot_convert_array_element,sema,none, +ERROR(cannot_convert_array_element,none, "cannot convert value of type %0 to expected element type %1", (Type,Type)) -ERROR(cannot_convert_array_element_protocol,sema_tcd,none, +ERROR(cannot_convert_array_element_protocol,none, "value of type %0 does not conform to expected element type %1", (Type, Type)) -ERROR(cannot_convert_array_element_nil,sema,none, +ERROR(cannot_convert_array_element_nil,none, "nil is not compatible with expected element type %0", (Type)) // Dictionary Key -ERROR(cannot_convert_dict_key,sema,none, +ERROR(cannot_convert_dict_key,none, "cannot convert value of type %0 to expected dictionary key type %1", (Type,Type)) -ERROR(cannot_convert_dict_key_protocol,sema_tcd,none, +ERROR(cannot_convert_dict_key_protocol,none, "value of type %0 does not conform to expected dictionary key type %1", (Type, Type)) -ERROR(cannot_convert_dict_key_nil,sema,none, +ERROR(cannot_convert_dict_key_nil,none, "nil is not compatible with expected dictionary key type %0", (Type)) // Dictionary Value -ERROR(cannot_convert_dict_value,sema,none, +ERROR(cannot_convert_dict_value,none, "cannot convert value of type %0 to expected dictionary value type %1", (Type,Type)) -ERROR(cannot_convert_dict_value_protocol,sema_tcd,none, +ERROR(cannot_convert_dict_value_protocol,none, "value of type %0 does not conform to expected dictionary value type %1", (Type, Type)) -ERROR(cannot_convert_dict_value_nil,sema,none, +ERROR(cannot_convert_dict_value_nil,none, "nil is not compatible with expected dictionary value type %0", (Type)) // Coerce Expr -ERROR(cannot_convert_coerce,sema,none, +ERROR(cannot_convert_coerce,none, "cannot convert value of type %0 to type %1 in coercion", (Type,Type)) -ERROR(cannot_convert_coerce_protocol,sema_tcd,none, +ERROR(cannot_convert_coerce_protocol,none, "value of type %0 does not conform to %1 in coercion", (Type, Type)) -ERROR(cannot_convert_coerce_nil,sema,none, +ERROR(cannot_convert_coerce_nil,none, "nil is not compatible with type %0 in coercion", (Type)) // Assign Expr -ERROR(cannot_convert_assign,sema,none, +ERROR(cannot_convert_assign,none, "cannot assign value of type %0 to type %1", (Type,Type)) -ERROR(cannot_convert_assign_protocol,sema_tcd,none, +ERROR(cannot_convert_assign_protocol,none, "value of type %0 does not conform to %1 in assignment", (Type, Type)) -ERROR(cannot_convert_assign_nil,sema,none, +ERROR(cannot_convert_assign_nil,none, "nil cannot be assigned to type %0", (Type)) -ERROR(throws_functiontype_mismatch,sema_tcc,none, +ERROR(throws_functiontype_mismatch,none, "invalid conversion from throwing function of type %0 to " "non-throwing function type %1", (Type, Type)) -ERROR(noescape_functiontype_mismatch,sema_tcc,none, +ERROR(noescape_functiontype_mismatch,none, "invalid conversion from non-escaping function of type %0 to " "potentially escaping function type %1", (Type, Type)) +// Selector expressions. +ERROR(expr_selector_no_objc_runtime,none, + "'#selector' can only be used with the Objective-C runtime", ()) +ERROR(expr_selector_module_missing,none, + "import the 'ObjectiveC' module to use '#selector'", ()) +ERROR(expr_selector_no_declaration,none, + "argument of '#selector' does not refer to an initializer or method", ()) +ERROR(expr_selector_property,none, + "argument of '#selector' cannot refer to a property", ()) +ERROR(expr_selector_not_method_or_init,none, + "argument of '#selector' does not refer to a method or initializer", ()) +ERROR(expr_selector_not_objc,none, + "argument of '#selector' refers to %select{a method|an initializer}0 " + "that is not exposed to Objective-C", + (bool)) +NOTE(expr_selector_make_objc,none, + "add '@objc' to expose this %select{method|initializer}0 to Objective-C", + (bool)) - - -ERROR(cannot_return_value_from_void_func,sema,none, +// Selectors-as-string-literals. +WARNING(selector_literal_invalid,none, + "string literal is not a valid Objective-C selector", ()) +WARNING(selector_literal_undeclared,none, + "no method declared with Objective-C selector %0", (ObjCSelector)) +WARNING(selector_literal_deprecated,none, + "use of string literal for Objective-C selectors is deprecated; " + "use '#selector' or explicitly construct a 'Selector'", ()) +WARNING(selector_literal_deprecated_suggest,none, + "use of string literal for Objective-C selectors is deprecated; " + "use '#selector' instead", ()) +WARNING(selector_construction_suggest,none, + "use '#selector' instead of explicitly constructing a 'Selector'", ()) + +ERROR(cannot_return_value_from_void_func,none, "unexpected non-void return value in void function", ()) //------------------------------------------------------------------------------ // Name Binding //------------------------------------------------------------------------------ -ERROR(sema_no_import,sema_nb,Fatal, +ERROR(sema_no_import,Fatal, "no such module '%0'", (StringRef)) -ERROR(sema_no_import_repl,sema_nb,none, +ERROR(sema_no_import_repl,none, "no such module '%0'", (StringRef)) -NOTE(sema_no_import_no_sdk,sema_nb,none, +NOTE(sema_no_import_no_sdk,none, "did you forget to set an SDK using -sdk or SDKROOT?", ()) -NOTE(sema_no_import_no_sdk_xcrun,sema_nb,none, +NOTE(sema_no_import_no_sdk_xcrun,none, "use \"xcrun -sdk macosx swiftc\" to select the default OS X SDK " "installed with Xcode", ()) -WARNING(sema_import_current_module,sema_nb,none, +WARNING(sema_import_current_module,none, "this file is part of module %0; ignoring import", (Identifier)) -WARNING(sema_import_current_module_with_file,sema_nb,none, +WARNING(sema_import_current_module_with_file,none, "file '%0' is part of module %1; ignoring import", (StringRef, Identifier)) -ERROR(sema_opening_import,sema_nb,Fatal, +ERROR(sema_opening_import,Fatal, "opening import file for module %0: %1", (Identifier, StringRef)) -ERROR(serialization_load_failed,sema,Fatal, +ERROR(serialization_load_failed,Fatal, "failed to load module %0", (Identifier)) -ERROR(serialization_malformed_module,sema,Fatal, +ERROR(serialization_malformed_module,Fatal, "malformed module file: %0", (StringRef)) -ERROR(serialization_module_too_new,sema,Fatal, +ERROR(serialization_module_too_new,Fatal, "module file was created by a newer version of the compiler: %0", (StringRef)) -ERROR(serialization_module_too_old,sema,Fatal, +ERROR(serialization_module_too_old,Fatal, "module file was created by an older version of the compiler; " "rebuild %0 and try again: %1", (Identifier, StringRef)) -ERROR(serialization_missing_single_dependency,sema,Fatal, +ERROR(serialization_missing_single_dependency,Fatal, "missing required module '%0'", (StringRef)) -ERROR(serialization_missing_dependencies,sema,Fatal, +ERROR(serialization_missing_dependencies,Fatal, "missing required modules: %0", (StringRef)) -ERROR(serialization_missing_shadowed_module,sema,Fatal, +ERROR(serialization_missing_shadowed_module,Fatal, "cannot load underlying module for %0", (Identifier)) -ERROR(serialization_name_mismatch,sema,Fatal, +ERROR(serialization_name_mismatch,Fatal, "cannot load module '%0' as %1", (StringRef, Identifier)) -ERROR(serialization_name_mismatch_repl,sema,none, +ERROR(serialization_name_mismatch_repl,none, "cannot load module '%0' as %1", (StringRef, Identifier)) -ERROR(serialization_target_incompatible,sema,Fatal, +ERROR(serialization_target_incompatible,Fatal, "module file was created for incompatible target %0: %1", (StringRef, StringRef)) -ERROR(serialization_target_incompatible_repl,sema,none, +ERROR(serialization_target_incompatible_repl,none, "module file was created for incompatible target %0: %1", (StringRef, StringRef)) -ERROR(serialization_target_too_new,sema,Fatal, +ERROR(serialization_target_too_new,Fatal, "module file's minimum deployment target is %0 v%1.%2%select{|.%3}3: %4", (StringRef, unsigned, unsigned, unsigned, StringRef)) -ERROR(serialization_target_too_new_repl,sema,none, +ERROR(serialization_target_too_new_repl,none, "module file's minimum deployment target is %0 v%1.%2%select{|.%3}3: %4", (StringRef, unsigned, unsigned, unsigned, StringRef)) -ERROR(unknown_name_in_type,sema_nb,none, - "use of unknown scope %0 in type reference", (Identifier)) +ERROR(reserved_member_name,none, + "type member may not be named %0, since it would conflict with the" + " 'foo.%1' expression", (DeclName, StringRef)) +NOTE(backticks_to_escape,none, + "backticks can escape this name if it is important to use", ()) -ERROR(invalid_redecl,sema_nb,none,"invalid redeclaration of %0", (DeclName)) -NOTE(invalid_redecl_prev,sema_nb,none, +ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName)) +NOTE(invalid_redecl_prev,none, "%0 previously declared here", (DeclName)) -ERROR(ambiguous_type_base,sema_nb,none, +ERROR(ambiguous_type_base,none, "%0 is ambiguous for type lookup in this context", (Identifier)) -ERROR(invalid_member_type,sema_nb,none, +ERROR(invalid_member_type,none, "%0 is not a member type of %1", (Identifier, Type)) -ERROR(invalid_member_type_suggest,sema_nb,none, +ERROR(invalid_member_type_suggest,none, "%0 does not have a member type named %1; did you mean %2?", (Type, Identifier, Identifier)) -ERROR(ambiguous_member_type,sema_nb,none, +ERROR(ambiguous_member_type,none, "ambiguous type name %0 in %1", (Identifier, Type)) -ERROR(no_module_type,sema_nb,none, +ERROR(no_module_type,none, "no type named %0 in module %1", (Identifier, Identifier)) -ERROR(ambiguous_module_type,sema_nb,none, +ERROR(ambiguous_module_type,none, "ambiguous type name %0 in module %1", (Identifier, Identifier)) -ERROR(use_nonmatching_operator,sema_nb,none, +ERROR(use_nonmatching_operator,none, "%0 is not a %select{binary|prefix unary|postfix unary}1 operator", (Identifier, unsigned)) -ERROR(use_unresolved_identifier,sema_nb,none, - "use of unresolved identifier %0", (Identifier)) -ERROR(use_undeclared_type,sema_nb,none, + +ERROR(unspaced_binary_operator_fixit,none, + "missing whitespace between %0 and %1 operators", + (Identifier, Identifier, bool)) +ERROR(unspaced_binary_operator,none, + "ambiguous missing whitespace between unary and binary operators", ()) +NOTE(unspaced_binary_operators_candidate,none, + "could be %select{binary|postfix}2 %0 and %select{prefix|binary}2 %1", + (Identifier, Identifier, bool)) +ERROR(unspaced_unary_operator,none, + "unary operators may not be juxtaposed; parenthesize inner expression", + ()) + + +ERROR(use_unresolved_identifier,none, + "use of unresolved %select{identifier|operator}1 %0", (DeclName, bool)) +ERROR(use_undeclared_type,none, "use of undeclared type %0", (Identifier)) -ERROR(use_undeclared_type_did_you_mean,sema_nb,none, -"use of undeclared type %0; did you mean to use '%1'?", (Identifier, StringRef)) -NOTE(note_remapped_type,sema_nb,none, - "did you mean to use '%0'?", (StringRef)) -ERROR(identifier_init_failure,sema_nb,none, - "could not infer type for %0", (Identifier)) -ERROR(pattern_used_in_type,sema_nb,none, +ERROR(use_undeclared_type_did_you_mean,none, + "use of undeclared type %0; did you mean to use '%1'?", (Identifier, StringRef)) +NOTE(note_remapped_type,none, + "did you mean to use '%0'?", (StringRef)) +ERROR(identifier_init_failure,none, + "could not infer type for %0", (Identifier)) +ERROR(pattern_used_in_type,none, "%0 used within its own type", (Identifier)) -NOTE(note_module_as_type,sema_nb,none, +NOTE(note_module_as_type,none, "cannot use module %0 as a type", (Identifier)) -ERROR(use_unknown_object_literal,sema_nb,none, +ERROR(use_unknown_object_literal,none, "use of unknown object literal name %0", (Identifier)) +ERROR(object_literal_default_type_missing,none, + "could not infer type of %0 literal", (StringRef)) +NOTE(object_literal_resolve_import,none, + "import %0 to use '%1' as the default %2 literal type", + (StringRef, StringRef, StringRef)) -ERROR(use_non_type_value,sema_nb,none, +ERROR(use_non_type_value,none, "%0 is not a type", (Identifier)) -NOTE(use_non_type_value_prev,sema_nb,none, +NOTE(use_non_type_value_prev,none, "%0 declared here", (Identifier)) -ERROR(use_local_before_declaration,sema_nb,none, - "use of local variable %0 before its declaration", (Identifier)) -ERROR(unsupported_existential_type,sema_nb,none, +ERROR(use_local_before_declaration,none, + "use of local variable %0 before its declaration", (DeclName)) +ERROR(unsupported_existential_type,none, "protocol %0 can only be used as a generic constraint because it has " "Self or associated type requirements", (Identifier)) -ERROR(no_decl_in_module,sema_nb,none, +ERROR(no_decl_in_module,none, "no such decl in module", ()) -ERROR(imported_decl_is_wrong_kind,sema_nb,none, +ERROR(imported_decl_is_wrong_kind,none, "%0 was imported as '%1', but is a " "%select{**MODULE**|type|struct|class|enum|protocol|variable|function}2", (Identifier, StringRef, /*ImportKind*/ unsigned)) -ERROR(ambiguous_decl_in_module,sema_nb,none, +ERROR(ambiguous_decl_in_module,none, "ambiguous name %0 in module %1", (Identifier, Identifier)) -ERROR(module_not_testable,sema_nb,none, +ERROR(module_not_testable,none, "module %0 was not compiled for testing", (Identifier)) // Operator decls -ERROR(ambiguous_operator_decls,sema_nb,none, +ERROR(ambiguous_operator_decls,none, "ambiguous operator declarations found for operator", ()) -NOTE(found_this_operator_decl,sema_nb,none, +NOTE(found_this_operator_decl,none, "found this matching operator declaration", ()) -ERROR(operator_redeclared,sema_nb,none, +ERROR(operator_redeclared,none, "operator redeclared", ()) -NOTE(previous_operator_decl,sema_nb,none, +NOTE(previous_operator_decl,none, "previous operator declaration here", ()) -ERROR(declared_operator_without_operator_decl,sema_nb,none, +ERROR(declared_operator_without_operator_decl,none, "operator implementation without matching operator declaration", ()) -ERROR(declared_unary_op_without_attribute,sema_nb,none, +ERROR(declared_unary_op_without_attribute,none, "unary operator implementation must have a 'prefix' or 'postfix' modifier", ()) -ERROR(unary_op_missing_prepos_attribute,sema_nb,none, +ERROR(unary_op_missing_prepos_attribute,none, "%select{prefix|postfix}0 unary operator missing " "'%select{prefix|postfix}0' modifier", (bool)) -NOTE(unary_operator_declaration_here,sema_nb,none, +NOTE(unary_operator_declaration_here,none, "%select{prefix|postfix}0 operator found here", (bool)) -ERROR(invalid_arg_count_for_operator,sema_nb,none, +ERROR(invalid_arg_count_for_operator,none, "operators must have one or two arguments", ()) //------------------------------------------------------------------------------ // Type Check Coercions //------------------------------------------------------------------------------ -ERROR(tuple_conversion_not_expressible,sema_tcc,none, +ERROR(tuple_conversion_not_expressible,none, "cannot express tuple conversion %0 to %1", (Type, Type)) -ERROR(load_of_explicit_lvalue,sema_tcc,none, +ERROR(load_of_explicit_lvalue,none, "%0 variable is not being passed by reference", (Type)) //------------------------------------------------------------------------------ // Expression Type Checking Errors //------------------------------------------------------------------------------ -ERROR(types_not_convertible,sema_tcc,none, +ERROR(types_not_convertible,none, "%1 is not %select{convertible to|a subtype of}0 %2", (bool, Type, Type)) -NOTE(in_cast_expr_types,sema_tcc,none, +NOTE(in_cast_expr_types,none, "in cast from type %0 to %1", (Type, Type)) -ERROR(tuple_types_not_convertible,sema_tcc,none, +ERROR(tuple_types_not_convertible_nelts,none, "%0 is not convertible to %1, " "tuples have a different number of elements", (Type, Type)) -ERROR(invalid_force_unwrap,sema_tcc,none, +ERROR(tuple_types_not_convertible,none, + "tuple type %0 is not convertible to tuple %1", (Type, Type)) + +ERROR(invalid_force_unwrap,none, "cannot force unwrap value of non-optional type %0", (Type)) -ERROR(invalid_optional_chain,sema_tcc,none, +ERROR(invalid_optional_chain,none, "cannot use optional chaining on non-optional value of type %0", (Type)) -ERROR(if_expr_cases_mismatch,sema_tcc,none, +ERROR(if_expr_cases_mismatch,none, "result values in '? :' expression have mismatching types %0 and %1", (Type, Type)) -ERROR(did_not_call_function_value,sema_tcc,none, +ERROR(did_not_call_function_value,none, "function value was used as a property; add () to call it", ()) -ERROR(did_not_call_function,sema_tcc,none, +ERROR(did_not_call_function,none, "function %0 was used as a property; add () to call it", (Identifier)) -ERROR(did_not_call_method,sema_tcc,none, +ERROR(did_not_call_method,none, "method %0 was used as a property; add () to call it", (Identifier)) -ERROR(init_not_instance_member,sema_tcc,none, +ERROR(init_not_instance_member,none, "'init' is a member of the type; insert '.dynamicType' to initialize " "a new object of the same dynamic type", ()) -ERROR(super_initializer_not_in_initializer,sema_tcc,none, +ERROR(super_initializer_not_in_initializer,none, "'super.init' cannot be called outside of an initializer", ()) -WARNING(isa_is_always_true,sema_tcc,none, "'%0' test is always true", +WARNING(isa_is_always_true,none, "'%0' test is always true", (StringRef)) -WARNING(conditional_downcast_coercion,sema_tcc,none, +WARNING(conditional_downcast_coercion,none, "conditional cast from %0 to %1 always succeeds", (Type, Type)) -WARNING(forced_downcast_noop,sema_tcc,none, +WARNING(forced_downcast_noop,none, "forced cast of %0 to same type has no effect", (Type)) -WARNING(forced_downcast_coercion,sema_tcc,none, +WARNING(forced_downcast_coercion,none, "forced cast from %0 to %1 always succeeds; did you mean to use 'as'?", (Type, Type)) -ERROR(downcast_same_type,sema_tcc,none, +ERROR(downcast_same_type,none, "downcast from %0 to %1 only unwraps optionals; did you mean to use " "'%2'?", (Type, Type, StringRef)) -WARNING(downcast_to_unrelated,sema_tcc,none, +WARNING(downcast_to_unrelated,none, "cast from %0 to unrelated type %1 always fails", (Type, Type)) -ERROR(downcast_from_existential_to_unrelated,sema_tcc,none, - "cannot cast from protocol type %0 to non-conforming type %1", - (Type, Type)) -ERROR(downcast_to_more_optional,sema_tcc,none, +ERROR(downcast_to_more_optional,none, "cannot downcast from %0 to a more optional type %1", (Type, Type)) -ERROR(optional_chain_noop,sema_tcc,none, +ERROR(optional_chain_noop,none, "optional chain has no effect, expression already produces %0", (Type)) -ERROR(optional_chain_isnt_chaining,sema_tcc,none, +ERROR(optional_chain_isnt_chaining,none, "'?' must be followed by a call, member lookup, or subscript", ()) -ERROR(pattern_in_expr,sema_tcc,none, +ERROR(pattern_in_expr,none, "%0 cannot appear in an expression", (PatternKind)) -NOTE(note_call_to_operator,sema_tcc,none, +NOTE(note_call_to_operator,none, "in call to operator %0", (Identifier)) -NOTE(note_call_to_func,sema_tcc,none, +NOTE(note_call_to_func,none, "in call to function %0", (Identifier)) -NOTE(note_call_to_initializer,sema_tcc,none, +NOTE(note_call_to_initializer,none, "in call to initializer", ()) -NOTE(note_init_parameter,sema_tcc,none, +NOTE(note_init_parameter,none, "in initialization of parameter %0", (Identifier)) -ERROR(missing_nullary_call,sema_tcc,none, + + +ERROR(missing_nullary_call,none, "function produces expected type %0; did you mean to call it with '()'?", (Type)) -ERROR(missing_unwrap_optional,sema_tcc,none, +ERROR(missing_unwrap_optional,none, "value of optional type %0 not unwrapped; did you mean to use '!' " "or '?'?", (Type)) -ERROR(missing_unwrap_optional_try,sema_tcc,none, +ERROR(missing_unwrap_optional_try,none, "value of optional type %0 not unwrapped; did you mean to use 'try!' " "or chain with '?'?", (Type)) -ERROR(missing_forced_downcast,sema_tcc,none, +ERROR(missing_forced_downcast,none, "%0 is not convertible to %1; " "did you mean to use 'as!' to force downcast?", (Type, Type)) -ERROR(missing_explicit_conversion,sema_tcc,none, +ERROR(missing_explicit_conversion,none, "%0 is not implicitly convertible to %1; " "did you mean to use 'as' to explicitly convert?", (Type, Type)) -ERROR(missing_address_of,sema_tcc,none, +ERROR(missing_address_of,none, "passing value of type %0 to an inout parameter requires explicit '&'", (Type)) -ERROR(extra_address_of,sema_tcc,none, +ERROR(extra_address_of,none, "'&' used with non-inout argument of type %0", (Type)) -ERROR(extra_address_of_unsafepointer,sema_tcc,none, +ERROR(extra_address_of_unsafepointer,none, "'&' is not allowed passing array value as %0 argument", (Type)) -ERROR(missing_init_on_metatype_initialization,sema_tcc,none, +ERROR(missing_init_on_metatype_initialization,none, "initializing from a metatype value must reference 'init' explicitly", ()) -ERROR(extra_call_nonfunction,sema_tcc,none, +ERROR(extra_call_nonfunction,none, "invalid use of '()' to call a value of non-function type %0", (Type)) -ERROR(extra_argument_labels,sema_tcc,none, +ERROR(extra_argument_labels,none, "extraneous argument label%select{|s}0 '%1' in %select{call|subscript}2", (bool, StringRef, bool)) -ERROR(missing_argument_labels,sema_tcc,none, +ERROR(missing_argument_labels,none, "missing argument label%select{|s}0 '%1' in %select{call|subscript}2", (bool, StringRef, bool)) -ERROR(wrong_argument_labels,sema_tcc,none, +ERROR(wrong_argument_labels,none, "incorrect argument label%select{|s}0 in %select{call|subscript}3 " "(have '%1', expected '%2')", (bool, StringRef, StringRef, bool)) -ERROR(extra_named_single_element_tuple,sema_tcc,none, +ERROR(extra_named_single_element_tuple,none, "cannot treat single-element named tuple as a scalar; use '.%0' to " "access its element", (StringRef)) -ERROR(argument_out_of_order,sema_tcc,none, +ERROR(argument_out_of_order,none, "argument %0 must precede argument %1", (Identifier, Identifier)) -ERROR(argument_out_of_order_named_unnamed,sema_tcc,none, +ERROR(argument_out_of_order_named_unnamed,none, "argument %0 must precede unnamed parameter #%1", (Identifier, unsigned)) -ERROR(instance_member_use_on_type,sema_tcc,none, +ERROR(instance_member_use_on_type,none, "use of instance member %1 on type %0; " - "did you mean to use a value of type %0 instead?", (Type, Identifier)) + "did you mean to use a value of type %0 instead?", (Type, DeclName)) +ERROR(instance_member_in_initializer,none, + "cannot use instance member %0 within property initializer; " + "property initializers run before 'self' is available", (DeclName)) -ERROR(missing_argument_named,sema_tcc,none, +ERROR(missing_argument_named,none, "missing argument for parameter %0 in call", (Identifier)) -ERROR(missing_argument_positional,sema_tcc,none, +ERROR(missing_argument_positional,none, "missing argument for parameter #%0 in call", (unsigned)) -ERROR(extra_argument_named,sema_tcc,none, +ERROR(extra_argument_named,none, "extra argument %0 in call", (Identifier)) -ERROR(extra_argument_positional,sema_tcc,none, +ERROR(extra_argument_positional,none, "extra argument in call", ()) -ERROR(extra_argument_to_nullary_call,sema_tcc,none, +ERROR(extra_argument_to_nullary_call,none, "argument passed to call that takes no arguments", ()) -ERROR(extra_trailing_closure_in_call,sema_tcc,none, +ERROR(extra_trailing_closure_in_call,none, "extra trailing closure passed in call", ()) -ERROR(no_accessible_initializers,sema_tcc,none, +ERROR(no_accessible_initializers,none, "%0 cannot be constructed because it has no accessible initializers", (Type)) -ERROR(unbound_generic_parameter,sema_tcc,none, +ERROR(unbound_generic_parameter,none, "generic parameter %0 could not be inferred", (Type)) -ERROR(cannot_bind_generic_parameter_to_type,sema_tcc,none, - "cannot bind generic parameter to type %0", +ERROR(unbound_generic_parameter_cast,none, + "generic parameter %0 could not be inferred in cast to %1", (Type, Type)) +NOTE(archetype_declared_in_type,none, + "%0 declared as parameter to type %1", (Type, Type)) + + +ERROR(string_index_not_integer,none, + "String may not be indexed with %0, it has variable size elements", (Type)) +NOTE(string_index_not_integer_note,none, + "consider using an existing high level algorithm, " + "str.startIndex.advancedBy(n), or a projection like str.utf8", ()) -ERROR(invalid_c_function_pointer_conversion_expr,sema_tcc,none, +ERROR(invalid_c_function_pointer_conversion_expr,none, "a C function pointer can only be formed from a reference to a 'func' or " "a literal closure", ()) -ERROR(c_function_pointer_from_method,sema_tcc,none, +ERROR(c_function_pointer_from_method,none, "a C function pointer cannot be formed from a method", ()) -ERROR(c_function_pointer_from_generic_function,sema_tcc,none, +ERROR(c_function_pointer_from_generic_function,none, "a C function pointer cannot be formed from a reference to a generic " "function", ()) -ERROR(c_function_pointer_from_function_with_context,sema_tcc,none, +ERROR(c_function_pointer_from_function_with_context,none, "a C function pointer cannot be formed from a " "%select{local function|closure}0 that captures " "%select{context|generic parameters}1", (bool, bool)) -NOTE(c_function_pointer_captures_here,sema_tcc,none, +NOTE(c_function_pointer_captures_here,none, "%0 captured here", (Identifier)) //------------------------------------------------------------------------------ // Type Check Declarations //------------------------------------------------------------------------------ -ERROR(var_type_not_materializable,sema_tcd,none, +ERROR(var_type_not_materializable,none, "type %0 of variable is not materializable", (Type)) -ERROR(enum_element_not_materializable,sema_tcd,none, +ERROR(enum_element_not_materializable,none, "type of enum case is not materializable", ()) -ERROR(missing_initializer_def,decl_parsing,PointsToFirstBadToken, +ERROR(missing_initializer_def,PointsToFirstBadToken, "initializer requires a body", ()) // Attributes -ERROR(operator_not_func,sema_tcd,none, +ERROR(operator_not_func,none, "operators must be declared with 'func'", ()) -ERROR(redefining_builtin_operator,sema_tcd,none, +ERROR(redefining_builtin_operator,none, "cannot declare a custom %0 '%1' operator", (StringRef, StringRef)) -ERROR(invalid_infix_on_func,sema_tcd,none, +ERROR(invalid_infix_on_func,none, "'infix' modifier is not required or allowed on func declarations", ()) -ERROR(attribute_requires_operator_identifier,sema_tcd,none, +ERROR(attribute_requires_operator_identifier,none, "'%0' requires a function with an operator identifier", (StringRef)) -ERROR(attribute_requires_single_argument,sema_tcd,none, +ERROR(attribute_requires_single_argument,none, "'%0' requires a function with one argument", (StringRef)) -ERROR(inout_cant_be_variadic,sema_tce,none, +ERROR(inout_cant_be_variadic,none, "inout arguments cannot be variadic", ()) -ERROR(inout_only_parameter,sema_tce,none, +ERROR(inout_only_parameter,none, "'inout' is only valid in parameter lists", ()) -ERROR(mutating_invalid_global_scope,sema_tcd,none, +ERROR(mutating_invalid_global_scope,none, "'mutating' is only valid on methods", ()) -ERROR(mutating_invalid_classes,sema_tcd,none, +ERROR(mutating_invalid_classes,none, "'mutating' isn't valid on methods in classes or class-bound protocols", ()) -ERROR(functions_mutating_and_not,sema_tcd,none, +ERROR(functions_mutating_and_not,none, "method may not be declared both mutating and nonmutating", ()) -ERROR(static_functions_not_mutating,sema_tcd,none, +ERROR(static_functions_not_mutating,none, "static functions may not be declared mutating", ()) -ERROR(transparent_stored_property,sema_tcd,none, +ERROR(transparent_stored_property,none, "@_transparent cannot be applied to stored properties", ()) -ERROR(transparent_on_invalid_extension,sema_tcd,none, +ERROR(transparent_on_invalid_extension,none, "@_transparent is only supported on struct and enum extensions", ()) -ERROR(transparent_in_protocols_not_supported,sema_tcd,none, +ERROR(transparent_in_protocols_not_supported,none, "@_transparent is not supported on declarations within protocols", ()) -ERROR(transparent_in_classes_not_supported,sema_tcd,none, +ERROR(transparent_in_classes_not_supported,none, "@_transparent is not supported on declarations within classes", ()) -ERROR(invalid_iboutlet,sema_tcd,none, +ERROR(invalid_iboutlet,none, "only instance properties can be declared @IBOutlet", ()) -ERROR(iboutlet_nonobjc_class,sema_tcd,none, +ERROR(iboutlet_nonobjc_class,none, "@IBOutlet property cannot %select{have|be an array of}0 " "non-'@objc' class type %1", (bool, Type)) -ERROR(iboutlet_nonobjc_protocol,sema_tcd,none, +ERROR(iboutlet_nonobjc_protocol,none, "@IBOutlet property cannot %select{have|be an array of}0 " "non-'@objc' protocol type %1", (bool, Type)) -ERROR(iboutlet_nonobject_type,sema_tcd,none, +ERROR(iboutlet_nonobject_type,none, "@IBOutlet property cannot %select{have|be an array of}0 " "non-object type %1", (bool, Type)) -ERROR(iboutlet_only_mutable,sema_tcd,none, +ERROR(iboutlet_only_mutable,none, "@IBOutlet attribute requires property to be mutable", ()) -ERROR(iboutlet_non_optional,sema_tcd,none, +ERROR(iboutlet_non_optional,none, "@IBOutlet property has non-optional type %0", (Type)) -NOTE(note_make_optional,sema_tcd,none, +NOTE(note_make_optional,none, "add '?' to form the optional type %0", (Type)) -NOTE(note_make_implicitly_unwrapped_optional,sema_tcd,none, +NOTE(note_make_implicitly_unwrapped_optional,none, "add '!' to form the implicitly unwrapped optional type %0", (Type)) -ERROR(invalid_ibdesignable_extension,sema_tcd,none, +ERROR(invalid_ibdesignable_extension,none, "@IBDesignable can only be applied to classes and extensions " "of classes", ()) -ERROR(invalid_ibinspectable,sema_tcd,none, +ERROR(invalid_ibinspectable,none, "only instance properties can be declared @IBInspectable", ()) -ERROR(invalid_ibaction_decl,sema_tcd,none, +ERROR(invalid_ibaction_decl,none, "only instance methods can be declared @IBAction", ()) -ERROR(invalid_ibaction_result,sema_tcd,none, +ERROR(invalid_ibaction_result,none, "methods declared @IBAction must return 'Void' (not %0)", (Type)) -ERROR(invalid_ibaction_argument_count,sema_tcd,none, +ERROR(invalid_ibaction_argument_count,none, "@IBAction methods %select{must have a single argument" "|can only have up to 2 arguments}0", (bool)) -ERROR(ibaction_nonobjc_class_argument,sema_tcd,none, +ERROR(ibaction_nonobjc_class_argument,none, "argument to @IBAction method cannot have non-'@objc' class type %0", (Type)) -ERROR(ibaction_nonobject_argument,sema_tcd,none, +ERROR(ibaction_nonobject_argument,none, "argument to @IBAction method cannot have non-object type %0", (Type)) -ERROR(no_objc_tagged_pointer_not_class_protocol,sema_tcd,none, +ERROR(no_objc_tagged_pointer_not_class_protocol,none, "@unsafe_no_objc_tagged_pointer can only be applied to class protocols", ()) -ERROR(swift_native_objc_runtime_base_not_on_root_class,sema_tcd,none, +ERROR(swift_native_objc_runtime_base_not_on_root_class,none, "@_swift_native_objc_runtime_base_not_on_root_class can only be applied " "to root classes", ()) -ERROR(attr_methods_only,sema_tcd,none, +ERROR(attr_methods_only,none, "only methods can be declared %0", (DeclAttribute)) -ERROR(access_control_in_protocol,sema_tcd,none, +ERROR(access_control_in_protocol,none, "%0 modifier cannot be used in protocols", (DeclAttribute)) -ERROR(access_control_setter,sema_tcd,none, +ERROR(access_control_setter,none, "'%select{private|internal|public}0(set)' modifier can only be applied " "to variables and subscripts", (Accessibility)) -ERROR(access_control_setter_read_only,sema_tcd,none, +ERROR(access_control_setter_read_only,none, "'%select{private|internal|public}0(set)' modifier cannot be applied to " "%select{constants|read-only variables|read-only properties" "|read-only subscripts}1", (Accessibility, unsigned)) -ERROR(access_control_setter_more,sema_tcd,none, +ERROR(access_control_setter_more,none, "%select{private|internal|PUBLIC}0 " "%select{variable|property|subscript}1 cannot have " "%select{PRIVATE|an internal|a public}2 setter", (Accessibility, unsigned, Accessibility)) -WARNING(access_control_member_more,sema_tcd,none, +WARNING(access_control_member_more,none, "declaring %select{PRIVATE|an internal|a public}0 %1 for " "%select{a private|an internal|PUBLIC}2 %3", (Accessibility, DescriptiveDeclKind, Accessibility, DescriptiveDeclKind)) -WARNING(access_control_ext_member_more,sema_tcd,none, +WARNING(access_control_ext_member_more,none, "declaring %select{PRIVATE|an internal|a public}0 %1 in " "%select{a private|an internal|PUBLIC}2 extension", (Accessibility, DescriptiveDeclKind, Accessibility)) -ERROR(access_control_ext_requirement_member_more,sema_tcd,none, +ERROR(access_control_ext_requirement_member_more,none, "cannot declare %select{PRIVATE|an internal|a public}0 %1 in " "an extension with %select{private|internal|PUBLIC}2 requirements", (Accessibility, DescriptiveDeclKind, Accessibility)) -ERROR(access_control_extension_more,sema_tcd,none, +ERROR(access_control_extension_more,none, "extension of %select{private|internal|PUBLIC}0 %1 cannot be " "declared %select{PRIVATE|internal|public}2", (Accessibility, DescriptiveDeclKind, Accessibility)) -ERROR(invalid_decl_attribute_simple,sema_tcd,none, +ERROR(invalid_decl_attribute_simple,none, "attribute cannot be applied to declaration", ()) -ERROR(invalid_decl_attribute,sema_tcd,none, +ERROR(invalid_decl_attribute,none, "%0 cannot be applied to this declaration", (DeclAttribute)) -ERROR(invalid_decl_modifier,sema_tcd,none, +ERROR(invalid_decl_modifier,none, "%0 modifier cannot be applied to this declaration", (DeclAttribute)) -ERROR(attribute_does_not_apply_to_type,type_parsing,none, +ERROR(attribute_does_not_apply_to_type,none, "attribute does not apply to type", ()) -ERROR(optional_attribute_non_protocol,sema_tcd,none, +ERROR(optional_attribute_non_protocol,none, "'optional' can only be applied to protocol members", ()) -ERROR(optional_attribute_non_objc_protocol,sema_tcd,none, +ERROR(optional_attribute_non_objc_protocol,none, "'optional' can only be applied to members of an @objc protocol", ()) -ERROR(optional_attribute_initializer,sema_tcd,none, +ERROR(optional_attribute_initializer,none, "'optional' cannot be applied to an initializer", ()) -ERROR(unavailable_method_non_objc_protocol,sema_tcd,none, +ERROR(unavailable_method_non_objc_protocol,none, "protocol members can only be marked unavailable in an @objc protocol", ()) -ERROR(missing_in_class_init_1,sema_tcd,none, +ERROR(missing_in_class_init_1,none, "stored property %0 requires an initial value%select{| or should be " "@NSManaged}1", (Identifier, bool)) -ERROR(missing_in_class_init_2,sema_tcd,none, +ERROR(missing_in_class_init_2,none, "stored properties %0 and %1 require initial values%select{| or should " "be @NSManaged}2", (Identifier, Identifier, bool)) -ERROR(missing_in_class_init_3plus,sema_tcd,none, +ERROR(missing_in_class_init_3plus,none, "stored properties %0, %1, %select{and %2|%2, and others}3 " "require initial values%select{| or should be @NSManaged}4", (Identifier, Identifier, Identifier, bool, bool)) -NOTE(requires_stored_property_inits_here,sema_tcd,none, +NOTE(requires_stored_property_inits_here,none, "%select{superclass|class}1 %0 requires all stored properties to have " "initial values%select{| or use @NSManaged}2", (Type, bool, bool)) -ERROR(class_without_init,sema_tcd,none, +ERROR(class_without_init,none, "class %0 has no initializers", (Type)) -NOTE(note_no_in_class_init_1,sema_tcd,none, +NOTE(note_no_in_class_init_1,none, "stored property %0 without initial value prevents synthesized " "initializers", (Identifier)) -NOTE(note_no_in_class_init_2,sema_tcd,none, +NOTE(note_no_in_class_init_2,none, "stored properties %0 and %1 without initial values prevent synthesized " "initializers", (Identifier, Identifier)) -NOTE(note_no_in_class_init_3plus,sema_tcd,none, +NOTE(note_no_in_class_init_3plus,none, "stored properties %0, %1, %select{and %2|%2, and others}3 " "without initial values prevent synthesized initializers", (Identifier, Identifier, Identifier, bool)) -ERROR(missing_unimplemented_init_runtime,sema_tcd,none, +ERROR(missing_unimplemented_init_runtime,none, "standard library error: missing _unimplemented_initializer", ()) -ERROR(missing_undefined_runtime,sema_tcd,none, +ERROR(missing_undefined_runtime,none, "standard library error: missing _undefined", ()) -WARNING(unsupported_synthesize_init_variadic,sema_tcd,none, +WARNING(unsupported_synthesize_init_variadic,none, "synthesizing a variadic inherited initializer for subclass %0 is " "unsupported", (Type)) -NOTE(variadic_superclass_init_here,sema_tcd,none, +NOTE(variadic_superclass_init_here,none, "variadic superclass initializer defined here", ()) // Alignment attribute -ERROR(alignment_not_power_of_two,sema_tcd,none, +ERROR(alignment_not_power_of_two,none, "alignment value must be a power of two", ()) // Indirect enums -ERROR(indirect_case_without_payload,sema_tcd,none, +ERROR(indirect_case_without_payload,none, "enum case %0 without associated value cannot be 'indirect'", (Identifier)) -ERROR(indirect_case_in_indirect_enum,sema_tcd,none, +ERROR(indirect_case_in_indirect_enum,none, "enum case in 'indirect' enum cannot also be 'indirect'", ()) // Variables (var and let). -ERROR(unimplemented_type_var,decl_parsing,none, +ERROR(unimplemented_type_var,none, "%select{ERROR|static|class}1 stored properties not yet supported" "%select{ in this context| in generic types| in classes}0" "%select{|; did you mean 'static'?}2", (unsigned, StaticSpellingKind, unsigned)) -ERROR(observingprop_requires_initializer,decl_parsing,none, +ERROR(observingprop_requires_initializer,none, "non-member observing properties require an initializer", ()) -ERROR(global_requires_initializer,decl_parsing,none, +ERROR(global_requires_initializer,none, "global '%select{var|let}0' declaration requires an initializer expression" "%select{ or getter/setter specifier}0", (bool)) -ERROR(static_requires_initializer,decl_parsing,none, +ERROR(static_requires_initializer,none, "%select{ERROR|'static var'|'class var'|}0 declaration requires an initializer " "expression or getter/setter specifier", (StaticSpellingKind)) -ERROR(pattern_type_access,sema_tcd,none, +ERROR(pattern_type_access,none, "%select{%select{variable|constant}0|property}1 " "%select{must be declared %select{private|internal|PUBLIC}4" "|cannot be declared %select{PRIVATE|internal|public}3}2 because its " "type uses %select{a private|an internal|PUBLIC}4 type", (bool, bool, bool, Accessibility, Accessibility)) -ERROR(pattern_type_access_inferred,sema_tcd,none, +ERROR(pattern_type_access_inferred,none, "%select{%select{variable|constant}0|property}1 " "%select{must be declared %select{private|internal|PUBLIC}4" "|cannot be declared %select{PRIVATE|internal|public}3}2 because its " "type %5 uses %select{a private|an internal|PUBLIC}4 type", (bool, bool, bool, Accessibility, Accessibility, Type)) -ERROR(pattern_binds_no_variables,sema_tcd,none, +ERROR(pattern_binds_no_variables,none, "%select{property|global variable}0 declaration does not bind any " "variables", (unsigned)) // Generic types -ERROR(unsupported_generic_nested_in_type,sema_tcd,none, +ERROR(unsupported_generic_nested_in_type,none, "generic type %0 nested in type %1 is not allowed", (Identifier, Type)) -ERROR(unsupported_type_nested_in_generic_type,sema_tcd,none, +ERROR(unsupported_type_nested_in_generic_type,none, "type %0 nested in generic type %1 is not allowed", (Identifier, Type)) -ERROR(unsupported_type_nested_in_generic_function,sema_tcd,none, +ERROR(unsupported_type_nested_in_generic_function,none, "type %0 nested in generic function %1 is not allowed", (Identifier, Identifier)) // Type aliases -ERROR(circular_type_alias,sema_tct,none, +ERROR(circular_type_alias,none, "type alias %0 circularly references itself", (Identifier)) -ERROR(type_alias_underlying_type_access,sema_tcd,none, +ERROR(type_alias_underlying_type_access,none, "type alias %select{must be declared %select{private|internal|PUBLIC}2" "|cannot be declared %select{PRIVATE|internal|public}1}0 because its " "underlying type uses %select{a private|an internal|PUBLIC}2 type", (bool, Accessibility, Accessibility)) // Subscripts -ERROR(subscript_type_access,sema_tcd,none, +ERROR(subscript_type_access,none, "subscript %select{must be declared %select{private|internal|PUBLIC}2" "|cannot be declared %select{PRIVATE|internal|public}1}0 because its " "%select{index|element type}3 uses " @@ -912,615 +994,606 @@ ERROR(subscript_type_access,sema_tcd,none, (bool, Accessibility, Accessibility, bool)) // Functions -ERROR(function_type_access,sema_tcd,none, +ERROR(function_type_access,none, "%select{function|method|initializer}3 " "%select{must be declared %select{private|internal|PUBLIC}2" "|cannot be declared %select{PRIVATE|internal|public}1}0 because its " "%select{parameter|result}4 uses " "%select{a private|an internal|PUBLIC}2 type", (bool, Accessibility, Accessibility, unsigned, bool)) -WARNING(non_trailing_closure_before_default_args,sema_tcd,none, +WARNING(non_trailing_closure_before_default_args,none, "closure parameter prior to parameters with default arguments will " "not be treated as a trailing closure", ()) // Extensions -ERROR(non_nominal_extension,sema_tcd,none, +ERROR(non_nominal_extension,none, "non-nominal type %0 cannot be extended", (Type)) -ERROR(extension_access_with_conformances,sema_tcd,none, +ERROR(extension_access_with_conformances,none, "%0 modifier cannot be used with extensions that declare " "protocol conformances", (DeclAttribute)) -ERROR(extension_metatype,sema_tcd,none, +ERROR(extension_metatype,none, "cannot extend a metatype %0", (Type)) -ERROR(extension_specialization,decl_parsing,none, +ERROR(extension_specialization,none, "constrained extension must be declared on the unspecialized generic " "type %0 with constraints specified by a 'where' clause", (Identifier)) -ERROR(extension_stored_property,sema_tcd,none, +ERROR(extension_stored_property,none, "extensions may not contain stored properties", ()) -ERROR(extension_nongeneric_trailing_where,sema_tcd,none, +ERROR(extension_nongeneric_trailing_where,none, "trailing 'where' clause for extension of non-generic type %0", (Type)) -ERROR(extension_constrained_inheritance,sema_tcd,none, +ERROR(extension_constrained_inheritance,none, "extension of type %0 with constraints cannot have an " "inheritance clause", (Type)) -ERROR(extension_protocol_inheritance,sema_tcd,none, +ERROR(extension_protocol_inheritance,none, "extension of protocol %0 cannot have an inheritance clause", (Type)) -ERROR(extension_protocol_type_definition,sema_tcd,none, +ERROR(extension_protocol_type_definition,none, "type %0 cannot be defined within a protocol extension", (DeclName)) -ERROR(extension_protocol_via_typealias,sema_tcd,none, +ERROR(extension_protocol_via_typealias,none, "protocol %0 in the module being compiled cannot be extended via a " "typealias", (Type)) -ERROR(extension_anyobject,sema_tcd,none, +ERROR(extension_anyobject,none, "'AnyObject' protocol cannot be extended", ()) // Protocols -ERROR(type_does_not_conform,sema_tcd,none, +ERROR(type_does_not_conform,none, "type %0 does not conform to protocol %1", (Type, Type)) -ERROR(cannot_use_nil_with_this_type,sema_tcd,none, +ERROR(cannot_use_nil_with_this_type,none, "nil cannot be used in context expecting type %0", (Type)) -ERROR(use_of_equal_instead_of_equality,sema_tcd,none, +ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) -ERROR(protocol_does_not_conform_objc,sema_tcc,none, +ERROR(protocol_does_not_conform_objc,none, "using %0 as a concrete type conforming to protocol %1 is not supported", (Type, Type)) -ERROR(protocol_does_not_conform_static,sema_tcc,none, +ERROR(protocol_does_not_conform_static,none, "%0 cannot be used as a type conforming to protocol %1 because %1 " "has static requirements", (Type, Type)) -ERROR(protocol_derivation_is_broken,sema_tcd,none, +ERROR(protocol_derivation_is_broken,none, "protocol %0 is broken; cannot derive conformance for type %1", (Type, Type)) -ERROR(type_does_not_inherit,sema_tcd,none, +ERROR(type_does_not_inherit,none, "%0 requires that %1 inherit from %2", (Type, Type, Type)) -NOTE(type_does_not_inherit_requirement,sema_tcd,none, +NOTE(type_does_not_inherit_requirement,none, "requirement specified as %0 : %1%2", (Type, Type, StringRef)) -ERROR(types_not_equal,sema_tcd,none, +ERROR(types_not_equal,none, "%0 requires the types %1 and %2 be equivalent", (Type, Type, Type)) -NOTE(types_not_equal_requirement,sema_tcd,none, +NOTE(types_not_equal_requirement,none, "requirement specified as %0 == %1%2", (Type, Type, StringRef)) -ERROR(non_class_cannot_conform_to_class_protocol,sema_tcd,none, +ERROR(non_class_cannot_conform_to_class_protocol,none, "non-class type %0 cannot conform to class protocol %1", (Type, Type)) -ERROR(foreign_class_cannot_conform_to_objc_protocol,sema_tcd,none, +ERROR(foreign_class_cannot_conform_to_objc_protocol,none, "Core Foundation class %0 cannot conform to @objc protocol %1 because " "Core Foundation types are not classes in Objective-C", (Type, Type)) -ERROR(protocol_has_missing_requirements,sema_tcd,none, +ERROR(protocol_has_missing_requirements,none, "type %0 cannot conform to protocol %1 because it has requirements that " "cannot be satisfied", (Type, Type)) -ERROR(witness_argument_name_mismatch,sema_tcd,none, +ERROR(witness_argument_name_mismatch,none, "%select{method|initializer}0 %1 has different argument names from those " "required by protocol %2 (%3)", (bool, DeclName, Type, DeclName)) -ERROR(witness_initializer_not_required,sema_tcd,none, +ERROR(witness_initializer_not_required,none, "initializer requirement %0 can only be satisfied by a `required` " "initializer in%select{| the definition of}1 non-final class %2", (DeclName, bool, Type)) -ERROR(witness_initializer_failability,sema_tcd,none, +ERROR(witness_initializer_failability,none, "non-failable initializer requirement %0" "%select{| in Objective-C protocol}1 cannot be satisfied by a " "failable initializer ('init%select{?|!}1')", (DeclName, bool)) -ERROR(witness_self_non_subtype,sema_tcd,none, +ERROR(witness_self_non_subtype,none, "protocol %0 requirement %1 cannot be satisfied by a non-final class " "(%2) because it uses 'Self' in a non-parameter, non-result type " "position", (Type, DeclName, Type)) -ERROR(witness_requires_dynamic_self,sema_tcd,none, +ERROR(witness_requires_dynamic_self,none, "method %0 in non-final class %1 must return `Self` to conform to " "protocol %2", (DeclName, Type, Type)) -ERROR(witness_not_accessible_proto,sema_tcd,none, +ERROR(witness_not_accessible_proto,none, "%select{initializer %1|method %1|%select{|setter for }2property %1" "|subscript%select{| setter}2}0 must be declared " "%select{PRIVATE|internal|public}3 because it matches a requirement " "in %select{PRIVATE|internal|public}3 protocol %4", (RequirementKind, DeclName, bool, Accessibility, DeclName)) -ERROR(witness_not_accessible_type,sema_tcd,none, +ERROR(witness_not_accessible_type,none, "%select{initializer %1|method %1|%select{|setter for }2property %1" "|subscript%select{| setter}2}0 must be as accessible as its enclosing " "type because it matches a requirement in protocol %4", (RequirementKind, DeclName, bool, Accessibility, DeclName)) -ERROR(type_witness_not_accessible_proto,sema_tcd,none, +ERROR(type_witness_not_accessible_proto,none, "%0 %1 must be declared %select{PRIVATE|internal|public}2 because it " "matches a requirement in %select{PRIVATE|internal|public}2 protocol %3", (DescriptiveDeclKind, DeclName, Accessibility, DeclName)) -ERROR(type_witness_not_accessible_type,sema_tcd,none, +ERROR(type_witness_not_accessible_type,none, "%0 %1 must be as accessible as its enclosing type because it " "matches a requirement in protocol %3", (DescriptiveDeclKind, DeclName, Accessibility, DeclName)) -ERROR(protocol_refine_access,sema_tcd,none, +ERROR(protocol_refine_access,none, "%select{protocol must be declared %select{private|internal|PUBLIC}2 " "because it refines" "|%select{PRIVATE|internal|public}1 protocol cannot refine}0 " "%select{a private|an internal|PUBLIC}2 protocol", (bool, Accessibility, Accessibility)) -ERROR(protocol_property_must_be_computed_var,sema_tcd,none, +ERROR(protocol_property_must_be_computed_var,none, "immutable property requirement must be declared as 'var' with a " "'{ get }' specifier", ()) -ERROR(protocol_property_must_be_computed,sema_tcd,none, +ERROR(protocol_property_must_be_computed,none, "property in protocol must have explicit { get } or { get set } specifier", ()) -NOTE(inherited_protocol_does_not_conform,sema_tcd,none, +NOTE(inherited_protocol_does_not_conform,none, "type %0 does not conform to inherited protocol %1", (Type, Type)) -NOTE(no_witnesses,sema_tcd,none, +NOTE(no_witnesses,none, "protocol requires %select{initializer %1|function %1|property %1|" "subscript}0 with type %2", (RequirementKind, DeclName, Type)) -NOTE(ambiguous_witnesses,sema_tcd,none, +NOTE(ambiguous_witnesses,none, "multiple matching " "%select{initializers named %1|functions named %1|properties named %1|" "subscript operators}0 with type %2", (RequirementKind, DeclName, Type)) -NOTE(ambiguous_witnesses_wrong_name,sema_tcd,none, +NOTE(ambiguous_witnesses_wrong_name,none, "multiple matching " "%select{initializers named %1|functions named %1|properties named %1|" "subscript operators}0 with type %2", (RequirementKind, DeclName, Type)) -NOTE(no_witnesses_type,sema_tcd,none, +NOTE(no_witnesses_type,none, "protocol requires nested type %0", (Identifier)) -NOTE(default_associated_type_req_fail,sema_tcd,none, +NOTE(default_associated_type_req_fail,none, "default type %0 for associated type %1 (from protocol %2) " "does not conform to %3", (Type, DeclName, Type, Type)) -ERROR(associated_type_access,sema_tcd,none, +ERROR(associated_type_access,none, "associated type in %select{PRIVATE|an internal|a public}0 protocol " "uses %select{a private|an internal|PUBLIC}1 type in its " "%select{default definition|requirement}2 ", (Accessibility, Accessibility, unsigned)) -NOTE(bad_associated_type_deduction,sema_tcd,none, +NOTE(bad_associated_type_deduction,none, "unable to infer associated type %0 for protocol %1", (DeclName, DeclName)) -NOTE(associated_type_deduction_witness_failed,sema_tcd,none, +NOTE(associated_type_deduction_witness_failed,none, "inferred type %1 (by matching requirement %0) is invalid: " "does not conform to %2", (DeclName, Type, DeclName)) -NOTE(ambiguous_associated_type_deduction,sema_tcd,none, +NOTE(ambiguous_associated_type_deduction,none, "ambiguous inference of associated type %0: %1 vs. %2", (DeclName, Type, Type)) -NOTE(associated_type_deduction_witness,sema_tcd,none, +NOTE(associated_type_deduction_witness,none, "matching requirement %0 to this declaration inferred associated type to " "%1", (DeclName, Type)) -NOTE(associated_type_deduction_default,sema_tcd,none, +NOTE(associated_type_deduction_default,none, "using associated type default %0", (Type)) -NOTE(ambiguous_witnesses_type,sema_tcd,none, +NOTE(ambiguous_witnesses_type,none, "multiple matching types named %0", (Identifier)) -NOTE(protocol_witness_exact_match,sema_tcd,none, +NOTE(protocol_witness_exact_match,none, "candidate exactly matches%0", (StringRef)) -NOTE(protocol_witness_renamed,sema_tcd,none, +NOTE(protocol_witness_renamed,none, "candidate matches (with renaming)%0", (StringRef)) -NOTE(protocol_witness_kind_conflict,sema_tcd,none, +NOTE(protocol_witness_kind_conflict,none, "candidate is not %select{an initializer|a function|a variable|" "a subscript}0", (RequirementKind)) -NOTE(protocol_witness_type_conflict,sema_tcd,none, +NOTE(protocol_witness_type_conflict,none, "candidate has non-matching type %0%1", (Type, StringRef)) -NOTE(protocol_witness_optionality_conflict,sema_tcd,none, +NOTE(protocol_witness_optionality_conflict,none, "candidate %select{type has|result type has|parameter type has|" "parameter types have|result and parameter types have}0 incorrect " "optionality%1", (unsigned, StringRef)) -ERROR(err_protocol_witness_optionality,sema_tcd,none, +ERROR(err_protocol_witness_optionality,none, "%select{type|result|parameter|parameters|" "result and parameters}0 of %1 %select{has|has|has|have|have|}0" " different optionality than required by protocol %2", (unsigned, DeclName, DeclName)) -WARNING(warn_protocol_witness_optionality,sema_tcd,none, +WARNING(warn_protocol_witness_optionality,none, "%select{type|result|parameter|parameters|" "result and parameters}0 of %1 %select{has|has|has|have|have|}0" " different optionality than expected by protocol %2", (unsigned, DeclName, DeclName)) -NOTE(protocol_witness_static_conflict,sema_tcd,none, +NOTE(protocol_witness_static_conflict,none, "candidate operates on %select{a type|an instance}0, not " "%select{an instance|a type}0 as required", (bool)) -NOTE(protocol_witness_prefix_postfix_conflict,sema_tcd,none, +NOTE(protocol_witness_prefix_postfix_conflict,none, "candidate is %select{|prefix, |postfix, }1not " "%select{prefix|postfix}0 as required", (bool, unsigned)) -NOTE(protocol_witness_mutating_conflict,sema_tcd,none, +NOTE(protocol_witness_mutating_conflict,none, "candidate is marked 'mutating' but protocol does not allow it", ()) -NOTE(protocol_witness_settable_conflict,sema_tcd,none, +NOTE(protocol_witness_settable_conflict,none, "candidate is not settable, but protocol requires it", ()) -NOTE(protocol_witness_noreturn_conflict,sema_tcd,none, +NOTE(protocol_witness_noreturn_conflict,none, "candidate is not @noreturn, but protocol requires it", ()) -NOTE(protocol_witness_rethrows_conflict,sema_tcd,none, +NOTE(protocol_witness_rethrows_conflict,none, "candidate is not 'rethrows', but protocol requires it", ()) -NOTE(protocol_witness_throws_conflict,sema_tcd,none, +NOTE(protocol_witness_throws_conflict,none, "candidate throws, but protocol does not allow it", ()) -NOTE(protocol_witness_not_objc,sema_tcd,none, +NOTE(protocol_witness_not_objc,none, "candidate is not '@objc', but protocol requires it", ()) -NOTE(protocol_witness_type,sema_tcd,none, +NOTE(protocol_witness_type,none, "possibly intended match", ()) -NOTE(protocol_witness_nonconform_type,sema_tcd,none, +NOTE(protocol_witness_nonconform_type,none, "possibly intended match %0 does not conform to %1", (Type, Type)) -NOTE(protocol_requirement_here,sema_tcd,none, +NOTE(protocol_requirement_here,none, "requirement %0 declared here", (DeclName)) -NOTE(protocol_conformance_here,sema_tcd,none, +NOTE(protocol_conformance_here,none, "%select{|class }0%1 declares conformance to protocol %2 here", (bool, DeclName, DeclName)) -NOTE(declared_protocol_conformance_here,sema_tcd,none, +NOTE(declared_protocol_conformance_here,none, "%select{%0 inherits conformance to protocol %2 from superclass|" "%0 declares conformance to protocol %2|" "%0 implicitly conforms to protocol %2 (via conformance to %3)|" "%0 implicitly conforms to protocol %2}1 here", (Type, unsigned, DeclName, DeclName)) -ERROR(redundant_conformance,sema_tcd,none, +ERROR(redundant_conformance,none, "redundant conformance of %0 to protocol %1", (Type, DeclName)) -NOTE(protocol_conformance_implied_here,sema_tcd,none, +NOTE(protocol_conformance_implied_here,none, "implied protocol conformance %0 here can be made explicit", (Identifier)) -WARNING(optional_req_nonobjc_near_match,sema_tcd,none, +WARNING(optional_req_nonobjc_near_match,none, "non-@objc %select{initializer %1|method %1|property %1|subscript}0 " "cannot satisfy optional requirement of @objc protocol %2", (RequirementKind, DeclName, DeclName)) // Protocols and existentials -ERROR(assoc_type_outside_of_protocol,sema_nb,none, +ERROR(assoc_type_outside_of_protocol,none, "cannot use associated type %0 outside of its protocol", (Identifier)) -ERROR(circular_protocol_def,sema_tcd,none, +ERROR(circular_protocol_def,none, "circular protocol inheritance %0", (StringRef)) -NOTE(protocol_here,sema_tcd,none, +NOTE(protocol_here,none, "protocol %0 declared here", (Identifier)) -ERROR(protocol_composition_not_protocol,sema_tcd,none, +ERROR(protocol_composition_not_protocol,none, "non-protocol type %0 cannot be used within 'protocol<...>'", (Type)) -ERROR(objc_protocol_inherits_non_objc_protocol,sema_tcd,none, +ERROR(objc_protocol_inherits_non_objc_protocol,none, "@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type)) -ERROR(requires_conformance_nonprotocol,sema_tcd,none, +ERROR(requires_conformance_nonprotocol,none, "type %0 constrained to non-protocol type %1", (TypeLoc, TypeLoc)) -ERROR(requires_not_suitable_archetype,sema_tcd,none, +ERROR(requires_not_suitable_archetype,none, "%select{|first |second }0type %1 in %select{conformance|same-type}2 " "requirement does not refer to a generic parameter or associated type", (int, TypeLoc, int)) -ERROR(requires_no_same_type_archetype,sema_tcd,none, +ERROR(requires_no_same_type_archetype,none, "neither type in same-type refers to a generic parameter or " "associated type", ()) -ERROR(requires_generic_params_made_equal,sema_tcd,none, +ERROR(requires_generic_params_made_equal,none, "same-type requirement makes generic parameters %0 and %1 equivalent", (Identifier, Identifier)) -ERROR(requires_generic_param_made_equal_to_concrete,sema_tcd,none, +ERROR(requires_generic_param_made_equal_to_concrete,none, "same-type requirement makes generic parameter %0 non-generic", (Identifier)) -ERROR(requires_superclass_conflict,sema_tcd,none, +ERROR(requires_superclass_conflict,none, "generic parameter %0 cannot be a subclass of both %1 and %2", (Identifier, Type, Type)) -ERROR(recursive_requirement_reference,sema_tcd,none, +ERROR(recursive_requirement_reference,none, "type may not reference itself as a requirement",()) -ERROR(recursive_same_type_constraint,sema_tcd,none, +ERROR(recursive_same_type_constraint,none, "same-type constraint %0 == %1 is recursive", (Type, Type)) -ERROR(requires_same_type_conflict,sema_tcd,none, +ERROR(requires_same_type_conflict,none, "generic parameter %0 cannot be equal to both %1 and %2", (Identifier, Type, Type)) -ERROR(requires_generic_param_same_type_does_not_conform,sema_tcd,none, +ERROR(requires_generic_param_same_type_does_not_conform,none, "same-type constraint type %0 does not conform to required protocol %1", (Type, Identifier)) -ERROR(dependent_superclass_constraint,sema_tcd,none, +ERROR(dependent_superclass_constraint,none, "superclass constraint %0 cannot depend on a type parameter", (Type)) -ERROR(generic_param_access,sema_tcd,none, +ERROR(generic_param_access,none, "%0 %select{must be declared %select{private|internal|PUBLIC}3" "|cannot be declared %select{PRIVATE|internal|public}2}1 because its " "generic %select{parameter|requirement}4 uses " "%select{a private|an internal|PUBLIC}3 type", (DescriptiveDeclKind, bool, Accessibility, Accessibility, bool)) -ERROR(override_multiple_decls_base,sema_tcd,none, +ERROR(override_multiple_decls_base,none, "declaration %0 cannot override more than one superclass declaration", (DeclName)) -ERROR(override_multiple_decls_arg_mismatch,sema_tcd,none, +ERROR(override_multiple_decls_arg_mismatch,none, "declaration %0 has different argument names from any potential " "overrides", (DeclName)) -ERROR(override_multiple_decls_derived,sema_tcd,none, - "declaration cannot be overridden by more than one subclass " - "declaration", ()) -NOTE(overridden_near_match_here,sema_tcd,none, +NOTE(overridden_near_match_here,none, "potential overridden %select{method|initializer}0 %1 here", (bool, DeclName)) -ERROR(override_decl_extension,sema_tcd,none, +ERROR(override_decl_extension,none, "declarations %select{in extensions|from extensions}0 cannot " "%select{override|be overridden}0 yet", (bool)) -NOTE(overridden_here,sema_tcd,none, +NOTE(overridden_here,none, "overridden declaration is here", ()) -ERROR(override_objc_type_mismatch_method,sema_tcd,none, +ERROR(override_objc_type_mismatch_method,none, "overriding method with selector %0 has incompatible type %1", (ObjCSelector, Type)) -ERROR(override_objc_type_mismatch_subscript,sema_tcd,none, +ERROR(override_objc_type_mismatch_subscript,none, "overriding %select{|indexed |keyed }0subscript with incompatible type " "%1", (unsigned, Type)) -NOTE(overridden_here_with_type,sema_tcd,none, +NOTE(overridden_here_with_type,none, "overridden declaration here has type %0", (Type)) -ERROR(missing_override,sema_tcd,none, +ERROR(missing_override,none, "overriding declaration requires an 'override' keyword", ()) -ERROR(override_unavailable,sema_tcd,none, +ERROR(override_unavailable,none, "cannot override %0 which has been marked unavailable", (Identifier)) -ERROR(override_less_available,sema_tcd,none, +ERROR(override_less_available,none, "overriding %0 must be as available as declaration it overrides", (Identifier)) -ERROR(override_accessor_less_available,sema_tcd,none, +ERROR(override_accessor_less_available,none, "overriding %0 for %1 must be as available as declaration it overrides", (DescriptiveDeclKind, Identifier)) -ERROR(override_let_property,sema_tcd,none, +ERROR(override_let_property,none, "cannot override immutable 'let' property %0 with the getter of a 'var'", (Identifier)) -ERROR(override_not_accessible,sema_tcd,none, +ERROR(override_not_accessible,none, "%select{|setter of }0overriding %1 must be as accessible as " "%select{its enclosing type|the declaration it overrides}2", (bool, DescriptiveDeclKind, bool)) -ERROR(method_does_not_override,sema_tcd,none, +ERROR(method_does_not_override,none, "method does not override any method from its superclass", ()) -ERROR(property_does_not_override,sema_tcd,none, +ERROR(property_does_not_override,none, "property does not override any property from its superclass", ()) -ERROR(subscript_does_not_override,sema_tcd,none, +ERROR(subscript_does_not_override,none, "subscript does not override any subscript from its superclass", ()) -ERROR(initializer_does_not_override,sema_tcd,none, +ERROR(initializer_does_not_override,none, "initializer does not override a designated initializer from its " "superclass", ()) -ERROR(failable_initializer_override,sema_tcd,none, +ERROR(failable_initializer_override,none, "failable initializer %0 cannot override a non-failable initializer", (DeclName)) -NOTE(nonfailable_initializer_override_here,sema_tcd,none, +NOTE(nonfailable_initializer_override_here,none, "non-failable initializer %0 overridden here", (DeclName)) -NOTE(property_override_here,sema_tcd,none, +NOTE(property_override_here,none, "attempt to override property here", ()) -NOTE(subscript_override_here,sema_tcd,none, +NOTE(subscript_override_here,none, "attempt to override subscript here", ()) -NOTE(convenience_init_override_here,sema_tcd,none, +NOTE(convenience_init_override_here,none, "attempt to override convenience initializer here", ()) -ERROR(override_nonclass_decl,sema_tcd,none, +ERROR(override_nonclass_decl,none, "'override' can only be specified on class members", ()) -ERROR(override_property_type_mismatch,sema_tcd,none, +ERROR(override_property_type_mismatch,none, "property %0 with type %1 cannot override a property with type %2", (Identifier, Type, Type)) -ERROR(override_with_stored_property,sema_tcd,none, +ERROR(override_with_stored_property,none, "cannot override with a stored property %0", (Identifier)) -ERROR(observing_readonly_property,sema_tcd,none, +ERROR(observing_readonly_property,none, "cannot observe read-only property %0; it can't change", (Identifier)) -ERROR(override_mutable_with_readonly_property,sema_tcd,none, +ERROR(override_mutable_with_readonly_property,none, "cannot override mutable property with read-only property %0", (Identifier)) -ERROR(override_argument_name_mismatch,sema_tcd,none, +ERROR(override_argument_name_mismatch,none, "argument names for %select{method|initializer}0 %1 do not match those " "of overridden %select{method|initializer}0 %2", (bool, DeclName, DeclName)) -ERROR(override_ownership_mismatch,sema_tcd,none, +ERROR(override_ownership_mismatch,none, "cannot override %select{strong|weak|unowned|unowned(unsafe)}0 property " "with %select{strong|weak|unowned|unowned(unsafe)}1 property", (/*Ownership*/unsigned, /*Ownership*/unsigned)) -ERROR(override_throws,sema_tcd,none, +ERROR(override_throws,none, "cannot override non-throwing %select{method|initializer}0 with " "throwing %select{method|initializer}0", (bool)) -ERROR(override_throws_objc,sema_tcd,none, +ERROR(override_throws_objc,none, "overriding a throwing @objc %select{method|initializer}0 with " "a non-throwing %select{method|initializer}0 is not supported", (bool)) -WARNING(override_unnecessary_IUO,sema_tcd,none, +WARNING(override_unnecessary_IUO,none, "overriding %0 parameter of type %1 with implicitly unwrapped optional " "type %2", (DescriptiveDeclKind, Type, Type)) -WARNING(override_unnecessary_result_IUO,sema_tcd,none, +WARNING(override_unnecessary_result_IUO,none, "overriding %0 optional result type %1 with implicitly unwrapped " "optional type %2", (DescriptiveDeclKind, Type, Type)) -NOTE(override_unnecessary_IUO_remove,sema_tcd,none, +NOTE(override_unnecessary_IUO_remove,none, "remove '!' to make the parameter required", ()) -NOTE(override_unnecessary_IUO_use_strict,sema_tcd,none, +NOTE(override_unnecessary_IUO_use_strict,none, "use '?' to make the result optional", ()) -NOTE(override_unnecessary_IUO_silence,sema_tcd,none, +NOTE(override_unnecessary_IUO_silence,none, "add parentheses to silence this warning", ()) -ERROR(override_mutable_covariant_property,sema_tcd,none, +ERROR(override_mutable_covariant_property,none, "cannot override mutable property %0 of type %1 with covariant type %2", (Identifier, Type, Type)) -ERROR(override_mutable_covariant_subscript,sema_tcd,none, +ERROR(override_mutable_covariant_subscript,none, "cannot override mutable subscript of type %0 with covariant type %1", (Type, Type)) -ERROR(decl_already_final,sema_tcd,none, +ERROR(decl_already_final,none, "static declarations are already final", ()) -ERROR(decl_no_default_init,sema_tcd,none, - "cannot default-initialize variable of type %0", (Type)) -ERROR(decl_no_default_init_ivar_hole,sema_tcd,none, - "cannot use initial value when one of the variables is '_'", ()) -NOTE(decl_init_here,sema_tcd,none, +NOTE(decl_init_here,none, "initial value is here", ()) // Inheritance -ERROR(duplicate_inheritance,sema_tcd,none, +ERROR(duplicate_inheritance,none, "duplicate inheritance from %0", (Type)) -ERROR(multiple_inheritance,sema_tcd,none, +ERROR(multiple_inheritance,none, "multiple inheritance from classes %0 and %1", (Type, Type)) -ERROR(non_class_inheritance,sema_tcd,none, +ERROR(non_class_inheritance,none, "non-class type %0 cannot inherit from class %1", (Type, Type)) -ERROR(extension_class_inheritance,sema_tcd,none, +ERROR(extension_class_inheritance,none, "extension of type %0 cannot inherit from class %1", (Type, Type)) -ERROR(inheritance_from_non_protocol_or_class,sema_tcd,none, +ERROR(inheritance_from_non_protocol_or_class,none, "inheritance from non-protocol, non-class type %0", (Type)) -ERROR(inheritance_from_non_protocol,sema_tcd,none, +ERROR(inheritance_from_non_protocol,none, "inheritance from non-protocol type %0", (Type)) -ERROR(superclass_not_first,sema_tcd,none, +ERROR(superclass_not_first,none, "superclass %0 must appear first in the inheritance clause", (Type)) -ERROR(circular_class_inheritance,sema_tcd,none, +ERROR(circular_class_inheritance,none, "circular class inheritance %0", (StringRef)) -NOTE(class_here,sema_tcd,none, +NOTE(class_here,none, "class %0 declared here", (Identifier)) -ERROR(inheritance_from_final_class,sema_tcd,none, +ERROR(inheritance_from_final_class,none, "inheritance from a final class %0", (Identifier)) // Enums -ERROR(enum_case_access,sema_tcd,none, +ERROR(enum_case_access,none, "enum case in %select{PRIVATE|an internal|a public}0 enum uses " "%select{a private|an internal|PUBLIC}1 type", (Accessibility, Accessibility)) -ERROR(enum_stored_property,sema_tcd,none, +ERROR(enum_stored_property,none, "enums may not contain stored properties", ()) // Enum raw types -ERROR(multiple_enum_raw_types,sema_tcd,none, +ERROR(multiple_enum_raw_types,none, "multiple enum raw types %0 and %1", (Type, Type)) -ERROR(circular_enum_inheritance,sema_tcd,none, +ERROR(circular_enum_inheritance,none, "circular enum raw types %0", (StringRef)) -ERROR(raw_type_not_first,sema_tcd,none, +ERROR(raw_type_not_first,none, "raw type %0 must appear first in the enum inheritance clause", (Type)) -ERROR(raw_type_not_literal_convertible,sema_tcd,none, +ERROR(raw_type_not_literal_convertible,none, "raw type %0 is not convertible from any literal", (Type)) -ERROR(enum_raw_type_not_equatable,sema_tcd,none, +ERROR(enum_raw_type_not_equatable,none, "RawRepresentable 'init' cannot be synthesized because raw type %0 is not " "Equatable", (Type)) -ERROR(enum_raw_type_access,sema_tcd,none, +ERROR(enum_raw_type_access,none, "enum %select{must be declared %select{private|internal|PUBLIC}2" "|cannot be declared %select{PRIVATE|internal|public}1}0 because its " "raw type uses %select{a private|an internal|PUBLIC}2 type", (bool, Accessibility, Accessibility)) -NOTE(enum_here,sema_tcd,none, +NOTE(enum_here,none, "enum %0 declared here", (Identifier)) -ERROR(empty_enum_raw_type,sema_tcd,none, +ERROR(empty_enum_raw_type,none, "an enum with no cases cannot declare a raw type", ()) -ERROR(enum_raw_value_without_raw_type,sema_tcd,none, +ERROR(enum_raw_value_without_raw_type,none, "enum case cannot have a raw value if the enum does not have a raw type", ()) -ERROR(enum_with_raw_type_case_with_argument,sema_tcd,none, +ERROR(enum_with_raw_type_case_with_argument,none, "enum with raw type cannot have cases with arguments", ()) -NOTE(enum_raw_type_here,sema_tcd,none, +NOTE(enum_raw_type_here,none, "declared raw type %0 here", (Type)) -ERROR(objc_enum_no_raw_type,sema_tcd,none, +ERROR(objc_enum_no_raw_type,none, "'@objc' enum must declare an integer raw type", ()) -ERROR(objc_enum_raw_type_not_integer,sema_tcd,none, +ERROR(objc_enum_raw_type_not_integer,none, "'@objc' enum raw type %0 is not an integer type", (Type)) -ERROR(enum_non_integer_raw_value_auto_increment,sema_tcd,none, +ERROR(enum_non_integer_raw_value_auto_increment,none, "enum case must declare a raw value when the preceding raw value is not an integer", ()) -ERROR(enum_non_integer_convertible_raw_type_no_value,sema_tcd,none, +ERROR(enum_non_integer_convertible_raw_type_no_value,none, "enum cases require explicit raw values when the raw type is not integer " "or string literal convertible", ()) -ERROR(enum_raw_value_not_unique,sema_tcd,none, +ERROR(enum_raw_value_not_unique,none, "raw value for enum case is not unique", ()) -NOTE(enum_raw_value_used_here,sema_tcd,none, +NOTE(enum_raw_value_used_here,none, "raw value previously used here", ()) -NOTE(enum_raw_value_incrementing_from_here,sema_tcd,none, +NOTE(enum_raw_value_incrementing_from_here,none, "raw value auto-incremented from here",()) -NOTE(enum_raw_value_incrementing_from_zero,sema_tcd,none, +NOTE(enum_raw_value_incrementing_from_zero,none, "raw value implicitly auto-incremented from zero",()) // Derived conformances -ERROR(broken_raw_representable_requirement,sema_tcd,none, +ERROR(broken_raw_representable_requirement,none, "RawRepresentable protocol is broken: unexpected requirement", ()) -ERROR(broken_equatable_requirement,sema_tcd,none, +ERROR(broken_equatable_requirement,none, "Equatable protocol is broken: unexpected requirement", ()) -ERROR(broken_hashable_requirement,sema_tcd,none, +ERROR(broken_hashable_requirement,none, "Hashable protocol is broken: unexpected requirement", ()) -ERROR(broken_errortype_requirement,sema_tcd,none, +ERROR(broken_errortype_requirement,none, "ErrorType protocol is broken: unexpected requirement", ()) -ERROR(broken_int_hashable_conformance,sema_tcd,none, +ERROR(broken_int_hashable_conformance,none, "Int type is broken: does not conform to Hashable", ()) -ERROR(broken_int_integer_literal_convertible_conformance,sema_tcd,none, +ERROR(broken_int_integer_literal_convertible_conformance,none, "Int type is broken: does not conform to IntegerLiteralConvertible", ()) -ERROR(broken_equatable_eq_operator,sema_tcd,none, +ERROR(broken_equatable_eq_operator,none, "Equatable protocol is broken: no infix operator declaration for '=='", ()) -ERROR(no_equal_overload_for_int,sema_tcd,none, +ERROR(no_equal_overload_for_int,none, "no overload of '==' for Int", ()) // Dynamic Self -ERROR(dynamic_self_non_method,sema_tcd,none, +ERROR(dynamic_self_non_method,none, "%select{global|local}0 function cannot return 'Self'", (bool)) -ERROR(dynamic_self_struct_enum,sema_tcd,none, +ERROR(dynamic_self_struct_enum,none, "%select{struct|enum}0 method cannot return 'Self'; " "did you mean to use the %select{struct|enum}0 type %1?", (int, Identifier)) // Duplicate declarations -ERROR(duplicate_enum_element,sema_tcd,none, +ERROR(duplicate_enum_element,none, "duplicate definition of enum element",()) //------------------------------------------------------------------------------ // Type Check Attributes //------------------------------------------------------------------------------ -ERROR(attr_only_only_one_decl_kind,sema_tcd,none, +ERROR(attr_only_only_one_decl_kind,none, "%0 may only be used on '%1' declarations", (DeclAttribute,StringRef)) -ERROR(override_final,sema_tcd,none, +ERROR(override_final,none, "%0 overrides a 'final' %0", (DescriptiveDeclKind)) -ERROR(member_cannot_be_final,sema_tcd,none, +ERROR(member_cannot_be_final,none, "only classes and class members may be marked with 'final'", ()) -ERROR(final_not_allowed_here,sema_tcd,none, +ERROR(final_not_allowed_here,none, "'final' may only be applied to classes, properties, methods, and " "subscripts", ()) -ERROR(final_not_on_accessors,sema_tcd,none, +ERROR(final_not_on_accessors,none, "'final' cannot be applied to accessors, it must be put on the " "%select{var|let|subscript}0", (unsigned)) -ERROR(override_noreturn_with_return,sema_tcd,none, +ERROR(override_noreturn_with_return,none, "an override of a @noreturn method should also be @noreturn", ()) -ERROR(override_rethrows_with_non_rethrows,sema_tcd,none, +ERROR(override_rethrows_with_non_rethrows,none, "override of 'rethrows' %select{method|initializer}0 should also " "be 'rethrows'", (bool)) -ERROR(rethrows_without_throwing_parameter,sema_tcd,none, +ERROR(rethrows_without_throwing_parameter,none, "'rethrows' function must take a throwing function argument", ()) -ERROR(inconsistent_attribute_override,sema_tcd,none, - "@%0 must be consistent between a method and its override", (StringRef)) -ERROR(autoclosure_function_type,attribute_parsing,none, +ERROR(autoclosure_function_type,none, "@autoclosure may only be applied to values of function type", ()) -ERROR(autoclosure_function_input_nonunit,attribute_parsing,none, +ERROR(autoclosure_function_input_nonunit,none, "autoclosure argument type must be '()'", ()) -ERROR(noescape_function_type,attribute_parsing,none, +ERROR(noescape_function_type,none, "@noescape may only be applied to parameters of function type", ()) -ERROR(noescape_implied_by_autoclosure,attribute_parsing,none, +ERROR(noescape_implied_by_autoclosure,none, "@noescape is implied by @autoclosure and should not be " "redundantly specified", ()) -ERROR(noescape_conflicts_escaping_autoclosure,attribute_parsing,none, +ERROR(noescape_conflicts_escaping_autoclosure,none, "@noescape conflicts with @autoclosure(escaping)", ()) // NSManaged attribute -ERROR(attr_NSManaged_not_instance_member,sema_tcd,none, +ERROR(attr_NSManaged_not_instance_member,none, "@NSManaged only allowed on an instance property or method", ()) -ERROR(attr_NSManaged_not_stored,sema_tcd,none, +ERROR(attr_NSManaged_not_stored,none, "@NSManaged not allowed on %select{computed|observing|addressed}0 " "properties", (unsigned)) -ERROR(attr_NSManaged_let_property,sema_tcd,none, +ERROR(attr_NSManaged_let_property,none, "@NSManaged not allowed on a 'let' property", ()) -ERROR(attr_NSManaged_initial_value,sema_tcd,none, +ERROR(attr_NSManaged_initial_value,none, "@NSManaged property cannot have an initial value", ()) -ERROR(attr_NSManaged_NSCopying,sema_tcd,none, +ERROR(attr_NSManaged_NSCopying,none, "@NSManaged property cannot also be marked @NSCopying", ()) -ERROR(attr_NSManaged_method_body,sema_tcd,none, +ERROR(attr_NSManaged_method_body,none, "@NSManaged method cannot have a body; it must be provided at runtime",()) // NSCopying attribute -ERROR(nscopying_only_on_class_properties,sema_tcd,none, +ERROR(nscopying_only_on_class_properties,none, "@NSCopying may only be used on properties in classes", ()) -ERROR(nscopying_only_mutable,sema_tcd,none, +ERROR(nscopying_only_mutable,none, "@NSCopying requires property to be mutable", ()) -ERROR(nscopying_only_stored_property,sema_tcd,none, +ERROR(nscopying_only_stored_property,none, "@NSCopying is only valid on stored properties", ()) -ERROR(nscopying_doesnt_conform,sema_tcd,none, +ERROR(nscopying_doesnt_conform,none, "@NSCopying is only valid with types that conform to" " the NSCopying protocol", ()) @@ -1528,23 +1601,23 @@ ERROR(nscopying_doesnt_conform,sema_tcd,none, #define SELECT_APPLICATION_MAIN "select{'UIApplicationMain'|'NSApplicationMain'}" #define SELECT_APPLICATION_DELEGATE "select{'UIApplicationDelegate'|'NSApplicationDelegate'}" -ERROR(attr_ApplicationMain_not_class,sema_tcd,none, +ERROR(attr_ApplicationMain_not_class,none, "%" SELECT_APPLICATION_MAIN "0 attribute may only be used on classes", (unsigned)) -ERROR(attr_ApplicationMain_not_ApplicationDelegate,sema_tcd,none, +ERROR(attr_ApplicationMain_not_ApplicationDelegate,none, "%" SELECT_APPLICATION_MAIN "0 class must conform to the %" SELECT_APPLICATION_DELEGATE "0 protocol", (unsigned)) -ERROR(attr_generic_ApplicationMain_not_supported,sema_tcd,none, +ERROR(attr_generic_ApplicationMain_not_supported,none, "generic %" SELECT_APPLICATION_MAIN "0 classes are not supported", (unsigned)) -ERROR(attr_ApplicationMain_multiple,sema_tcd,none, +ERROR(attr_ApplicationMain_multiple,none, "%" SELECT_APPLICATION_MAIN "0 attribute can only apply to one class in a module", (unsigned)) -ERROR(attr_ApplicationMain_with_script,sema_tcd,none, +ERROR(attr_ApplicationMain_with_script,none, "%" SELECT_APPLICATION_MAIN "0 attribute cannot be used in a module that contains " "top-level code", (unsigned)) -NOTE(attr_ApplicationMain_script_here,sema_tcd,none, +NOTE(attr_ApplicationMain_script_here,none, "top-level code defined in this source file", ()) @@ -1552,32 +1625,32 @@ NOTE(attr_ApplicationMain_script_here,sema_tcd,none, #undef SELECT_APPLICATION_DELEGATE // lazy -ERROR(lazy_not_on_let,sema_tcd,none, +ERROR(lazy_not_on_let,none, "'lazy' cannot be used on a let", ()) -ERROR(lazy_not_on_computed,sema_tcd,none, +ERROR(lazy_not_on_computed,none, "'lazy' may not be used on a computed property", ()) -ERROR(lazy_on_already_lazy_global,sema_tcd,none, +ERROR(lazy_on_already_lazy_global,none, "'lazy' may not be used on an already-lazy global", ()) -ERROR(lazy_not_in_protocol,sema_tcd,none, +ERROR(lazy_not_in_protocol,none, "'lazy' isn't allowed on a protocol requirement", ()) -ERROR(lazy_requires_initializer,sema_tcd,none, +ERROR(lazy_requires_initializer,none, "lazy properties must have an initializer", ()) -ERROR(lazy_requires_single_var,sema_tcd,none, +ERROR(lazy_requires_single_var,none, "'lazy' cannot destructure an initializer", ()) -ERROR(lazy_must_be_property,sema_tcd,none, +ERROR(lazy_must_be_property,none, "lazy is only valid for members of a struct or class", ()) -ERROR(lazy_not_observable,sema_tcd,none, +ERROR(lazy_not_observable,none, "lazy properties may not have observers", ()) // Debugger function attribute. -ERROR(attr_for_debugger_support_only,sema_tcd,none, +ERROR(attr_for_debugger_support_only,none, "@LLDBDebuggerSupport may only be used when debugger support is on", ()) // warn_unused_result -ERROR(attr_warn_unused_result_mutable_variable,sema_tcd,none, +ERROR(attr_warn_unused_result_mutable_variable,none, "'mutable_variant' parameter of 'warn_unused_result' attribute does not " "make sense on a %select{non-function|non-method|non-instance method|" "method of a class|mutating method}0", (unsigned)) @@ -1586,268 +1659,268 @@ ERROR(attr_warn_unused_result_mutable_variable,sema_tcd,none, // Type Check Expressions //------------------------------------------------------------------------------ -NOTE(found_candidate,sema_tce,none, +NOTE(found_candidate,none, "found this candidate", ()) -NOTE(found_candidate_type,sema_tce,none, +NOTE(found_candidate_type,none, "found candidate with type %0", (Type)) -NOTE(first_declaration,sema_tce,none, +NOTE(first_declaration,none, "first declaration", ()) -NOTE(second_declaration,sema_tce,none, +NOTE(second_declaration,none, "second declaration", ()) -ERROR(no_IntegerLiteralType_found,sema_tce,none, +ERROR(no_IntegerLiteralType_found,none, "standard library error: IntegerLiteralType not defined", ()) -ERROR(no_FloatLiteralType_found,sema_tce,none, +ERROR(no_FloatLiteralType_found,none, "standard library error: FloatLiteralType not defined", ()) -ERROR(no_StringLiteralType_found,sema_tce,none, +ERROR(no_StringLiteralType_found,none, "standard library error: StringLiteralType not defined", ()) -ERROR(no_MaxBuiltinIntegerType_found,sema_tce,none, +ERROR(no_MaxBuiltinIntegerType_found,none, "standard library error: _MaxBuiltinIntegerType is not properly defined", ()) -ERROR(no_MaxBuiltinFloatType_found,sema_tce,none, +ERROR(no_MaxBuiltinFloatType_found,none, "standard library error: _MaxBuiltinFloatType is not properly defined", ()) -ERROR(no_member_of_module,sema_tce,none, +ERROR(no_member_of_module,none, "module %0 has no member named %1", (Identifier, DeclName)) -ERROR(super_with_no_base_class,sema_tce,none, +ERROR(super_with_no_base_class,none, "'super' members cannot be referenced in a root class", ()) -ERROR(bad_init_ref_base,sema_tce, none, +ERROR(bad_init_ref_base, none, "'init' can only refer to the initializers of " "'self'%select{| or 'super'}0", (bool)) -ERROR(init_delegation_outside_initializer,sema_tce,none, +ERROR(init_delegation_outside_initializer,none, "initializer delegation can only occur within an initializer", ()) -ERROR(init_delegates_and_chains,sema_tce,none, +ERROR(init_delegates_and_chains,none, "initializer cannot both delegate ('self.init') and chain to a " "superclass initializer ('super.init')", ()) -NOTE(init_delegation_or_chain,sema_tce,none, +NOTE(init_delegation_or_chain,none, "previous %select{delegation|chaining}0 call is here", (bool)) -ERROR(delegating_convenience_super_init,sema_tce,none, +ERROR(delegating_convenience_super_init,none, "convenience initializer for %0 must delegate (with 'self.init') rather " "than chaining to a superclass initializer (with 'super.init')", (Type)) -ERROR(delegating_designated_init,sema_tce,none, +ERROR(delegating_designated_init,none, "designated initializer for %0 cannot delegate (with 'self.init'); " "did you mean this to be a convenience initializer?", (Type)) -NOTE(delegation_here,sema_tce,none, "delegation occurs here", ()) -ERROR(chain_convenience_init,sema_tce,none, +NOTE(delegation_here,none, "delegation occurs here", ()) +ERROR(chain_convenience_init,none, "must call a designated initializer of the superclass %0", (Type)) -ERROR(delegate_chain_nonoptional_to_optional,sema_tce,none, +ERROR(delegate_chain_nonoptional_to_optional,none, "a non-failable initializer cannot %select{delegate|chain}0 to " "failable initializer %1 written with 'init?'", (bool, DeclName)) -NOTE(init_force_unwrap,sema_tce,none, +NOTE(init_force_unwrap,none, "force potentially-failing result with '!'", ()) -NOTE(init_propagate_failure,sema_tce,none, +NOTE(init_propagate_failure,none, "propagate the failure with 'init?'", ()) -ERROR(delegate_chain_nonoptional_to_optional_try,sema_tce,none, +ERROR(delegate_chain_nonoptional_to_optional_try,none, "a non-failable initializer cannot use 'try?' to " "%select{delegate|chain}0 to another initializer", (bool)) -NOTE(init_delegate_force_try,sema_tce,none, +NOTE(init_delegate_force_try,none, "force potentially-failing result with 'try!'", ()) -ERROR(init_delegation_nested,sema_tce,none, +ERROR(init_delegation_nested,none, "%select{initializer delegation ('self.init')|" "initializer chaining ('super.init')}0 cannot be nested in another " "%select{expression|statement}1", (bool, bool)) -NOTE(convenience_init_here,sema_tce,none, +NOTE(convenience_init_here,none, "convenience initializer is declared here", ()) -ERROR(designated_init_in_extension,sema_tcd,none, +ERROR(designated_init_in_extension,none, "designated initializer cannot be declared in an extension of %0; " "did you mean this to be a convenience initializer?", (Type)) -ERROR(enumstruct_convenience_init,sema_tce,none, +ERROR(enumstruct_convenience_init,none, "delegating initializers in %0 are not marked with 'convenience'", (StringRef)) -ERROR(nonclass_convenience_init,sema_tce,none, +ERROR(nonclass_convenience_init,none, "convenience initializer not allowed in non-class type %0", (Type)) -ERROR(dynamic_construct_class,sema_tce,none, +ERROR(dynamic_construct_class,none, "constructing an object of class type %0 with a metatype value must use " "a 'required' initializer", (Type)) -NOTE(note_nonrequired_initializer,sema_tce,none, +NOTE(note_nonrequired_initializer,none, "selected %select{non-required|implicit}0 initializer %1", (bool, DeclName)) -ERROR(construct_protocol_value,sema_tce,none, +ERROR(construct_protocol_value,none, "value of type %0 is a protocol; it cannot be instantiated", (Type)) -ERROR(construct_protocol_by_name,sema_tce,none, +ERROR(construct_protocol_by_name,none, "protocol type %0 cannot be instantiated", (Type)) // Operators -ERROR(unknown_binop,sema_tce,none, +ERROR(unknown_binop,none, "operator is not a known binary operator", ()) -ERROR(non_assoc_adjacent,sema_tce,none, +ERROR(non_assoc_adjacent,none, "non-associative operator is adjacent to operator of same precedence", ()) -ERROR(incompatible_assoc,sema_tce,none, +ERROR(incompatible_assoc,none, "operator is adjacent to operator of same precedence" " but incompatible associativity", ()) // If you change this, also change enum TryKindForDiagnostics. #define TRY_KIND_SELECT(SUB) "%select{try|try!|try?}" #SUB -ERROR(try_rhs,sema_tce,none, +ERROR(try_rhs,none, "'" TRY_KIND_SELECT(0) "' cannot appear to the right of a " "non-assignment operator", (unsigned)) -ERROR(try_if_rhs_noncovering,sema_tce,none, +ERROR(try_if_rhs_noncovering,none, "'" TRY_KIND_SELECT(0) "' following conditional operator does not cover " "everything to its right", (unsigned)) -ERROR(try_assign_rhs_noncovering,sema_tce,none, +ERROR(try_assign_rhs_noncovering,none, "'" TRY_KIND_SELECT(0) "' following assignment operator does not cover " "everything to its right", (unsigned)) -ERROR(reference_non_inout,sema_tce,none, - "reference to %0 not used to initialize a inout parameter", (Type)) -NOTE(subscript_decl_here,sema_tca,none, +NOTE(subscript_decl_here,none, "subscript operator declared here", ()) -ERROR(condition_broken_proto,sema_tce,none, +ERROR(condition_broken_proto,none, "protocol 'BooleanType' is broken", ()) -ERROR(option_type_broken,sema_tce,none, - "type 'Optional' is broken", ()) -ERROR(broken_bool,sema_tce,none, "type 'Bool' is broken", ()) -ERROR(binding_explicit_downcast,sema_tce,none, - "operand of postfix '?' is a forced downcast to type %0; use 'as?' to " - "perform a conditional downcast", (Type)) +ERROR(broken_bool,none, "type 'Bool' is broken", ()) -WARNING(inject_forced_downcast,sema_tce,none, +WARNING(inject_forced_downcast,none, "treating a forced downcast to %0 as optional will never produce 'nil'", (Type)) -NOTE(forced_to_conditional_downcast,sema_tce,none, +NOTE(forced_to_conditional_downcast,none, "use 'as?' to perform a conditional downcast to %0", (Type)) -NOTE(silence_inject_forced_downcast,sema_tce,none, +NOTE(silence_inject_forced_downcast,none, "add parentheses around the cast to silence this warning", ()) -ERROR(conditional_downcast_foreign,sema_tce,none, +ERROR(conditional_downcast_foreign,none, "conditional downcast to CoreFoundation type %0 will always succeed", (Type)) -ERROR(optional_used_as_boolean,sema_tce,none, +ERROR(optional_used_as_boolean,none, "optional type %0 cannot be used as a boolean; " "test for '!= nil' instead", (Type)) -ERROR(optional_used_as_true_boolean,sema_tce,none, +ERROR(optional_used_as_true_boolean,none, "optional type %0 cannot be used as a boolean; " "test for '== nil' instead", (Type)) -ERROR(migrate_from_raw_to_init,sema_tce,none, +ERROR(migrate_from_raw_to_init,none, "static method 'fromRaw' has been replaced with a failable initializer " "'init(rawValue:)'", ()) -ERROR(migrate_from_allZeros,sema_tce,none, +ERROR(migrate_from_allZeros,none, "static method 'allZeros' has been replaced with the default initializer", ()) -ERROR(migrate_to_raw_to_raw_value,sema_tce,none, +ERROR(migrate_to_raw_to_raw_value,none, "method 'fromRaw' has been replaced with a property 'rawValue'", ()) -ERROR(new_array_bound_zero,sema_tce,none, - "array type cannot have zero length", ()) -ERROR(non_constant_array,type_parsing,none, - "array has non-constant size", ()) - -ERROR(interpolation_missing_proto,sema_tce,none, +ERROR(interpolation_missing_proto,none, "string interpolation requires the protocol 'StringInterpolationConvertible' to be defined", ()) -ERROR(interpolation_broken_proto,sema_tce,none, +ERROR(interpolation_broken_proto,none, "protocol 'StringInterpolationConvertible' is broken", ()) -ERROR(object_literal_broken_proto,sema_tce,none, +ERROR(object_literal_broken_proto,none, "object literal protocol is broken", ()) -ERROR(discard_expr_outside_of_assignment,sema_tce,none, +ERROR(discard_expr_outside_of_assignment,none, "'_' can only appear in a pattern or on the left side of an assignment", ()) -ERROR(inout_expr_outside_of_call,sema_tce,none, +ERROR(inout_expr_outside_of_call,none, "'&' can only appear immediately in a call argument list", ()) -ERROR(type_of_expression_is_ambiguous,sema_tce,none, + +ERROR(unresolved_member_no_inference,none, + "reference to member %0 cannot be resolved without a contextual type", + (DeclName)) +ERROR(unresolved_collection_literal,none, + "cannot infer type for empty collection literal without a " + "contextual type", ()) +ERROR(unresolved_nil_literal,none, + "'nil' requires a contextual type", ()) + +ERROR(type_of_expression_is_ambiguous,none, "type of expression is ambiguous without more context", ()) -ERROR(specific_type_of_expression_is_ambiguous,sema_tce,none, +ERROR(specific_type_of_expression_is_ambiguous,none, "expression type %0 is ambiguous without more context", (Type)) -ERROR(missing_protocol,sema_tce,none, +ERROR(missing_protocol,none, "missing protocol %0", (Identifier)) -ERROR(nil_literal_broken_proto,sema_tce,none, +ERROR(nil_literal_broken_proto,none, "protocol 'NilLiteralConvertible' is broken", ()) -ERROR(builtin_integer_literal_broken_proto,sema_tce,none, +ERROR(builtin_integer_literal_broken_proto,none, "protocol '_BuiltinIntegerLiteralConvertible' is broken", ()) -ERROR(integer_literal_broken_proto,sema_tce,none, +ERROR(integer_literal_broken_proto,none, "protocol 'IntegerLiteralConvertible' is broken", ()) -ERROR(builtin_float_literal_broken_proto,sema_tce,none, +ERROR(builtin_float_literal_broken_proto,none, "protocol '_BuiltinFloatLiteralConvertible' is broken", ()) -ERROR(float_literal_broken_proto,sema_tce,none, +ERROR(float_literal_broken_proto,none, "protocol 'FloatLiteralConvertible' is broken", ()) -ERROR(builtin_boolean_literal_broken_proto,sema_tce,none, +ERROR(builtin_boolean_literal_broken_proto,none, "protocol '_BuiltinBooleanLiteralConvertible' is broken", ()) -ERROR(boolean_literal_broken_proto,sema_tce,none, +ERROR(boolean_literal_broken_proto,none, "protocol 'BooleanLiteralConvertible' is broken", ()) -ERROR(builtin_unicode_scalar_literal_broken_proto,sema_tce,none, +ERROR(builtin_unicode_scalar_literal_broken_proto,none, "protocol '_BuiltinUnicodeScalarLiteralConvertible' is broken", ()) -ERROR(unicode_scalar_literal_broken_proto,sema_tce,none, +ERROR(unicode_scalar_literal_broken_proto,none, "protocol 'UnicodeScalarLiteralConvertible' is broken", ()) -ERROR(builtin_extended_grapheme_cluster_literal_broken_proto,sema_tce,none, +ERROR(builtin_extended_grapheme_cluster_literal_broken_proto,none, "protocol '_BuiltinExtendedGraphemeClusterLiteralConvertible' is broken", ()) -ERROR(extended_grapheme_cluster_literal_broken_proto,sema_tce,none, +ERROR(extended_grapheme_cluster_literal_broken_proto,none, "protocol 'ExtendedGraphemeClusterLiteralConvertible' is broken", ()) -ERROR(builtin_string_literal_broken_proto,sema_tce,none, +ERROR(builtin_string_literal_broken_proto,none, "protocol '_BuiltinStringLiteralConvertible' is broken", ()) -ERROR(string_literal_broken_proto,sema_tce,none, +ERROR(string_literal_broken_proto,none, "protocol 'StringLiteralConvertible' is broken", ()) -ERROR(bool_type_broken,sema_tce,none, +ERROR(bool_type_broken,none, "could not find a Bool type defined for 'is'", ()) // Array literals -ERROR(array_protocol_broken,sema_tce,none, +ERROR(array_protocol_broken,none, "ArrayLiteralConvertible protocol definition is broken", ()) -ERROR(type_is_not_array,sema_tce,none, +ERROR(type_is_not_array,none, "contextual type %0 cannot be used with array literal", (Type)) -NOTE(meant_dictionary_lit, sema_tce,none, +NOTE(meant_dictionary_lit,none, "did you mean to use a dictionary literal instead?", ()) +ERROR(should_use_empty_dictionary_literal,none, + "use [:] to get an empty dictionary literal", ()) // Dictionary literals -ERROR(dictionary_protocol_broken,sema_tce,none, +ERROR(dictionary_protocol_broken,none, "DictionaryLiteralConvertible protocol definition is broken", ()) -ERROR(type_is_not_dictionary,sema_tce,none, +ERROR(type_is_not_dictionary,none, "contextual type %0 cannot be used with dictionary literal", (Type)) // Generic specializations -ERROR(cannot_explicitly_specialize_generic_function,tce_sema,none, +ERROR(cannot_explicitly_specialize_generic_function,none, "cannot explicitly specialize a generic function", ()) -ERROR(not_a_generic_definition,tce_sema,none, +ERROR(not_a_generic_definition,none, "cannot specialize a non-generic definition", ()) -ERROR(not_a_generic_type,tce_sema,none, +ERROR(not_a_generic_type,none, "cannot specialize non-generic type %0", (Type)) -ERROR(type_parameter_count_mismatch,tce_sema,none, +ERROR(type_parameter_count_mismatch,none, "generic type %0 specialized with %select{too many|too few}3 type " "parameters (got %2, but expected %1)", (Identifier, unsigned, unsigned, bool)) -ERROR(generic_type_requires_arguments,tce_sema,none, +ERROR(generic_type_requires_arguments,none, "reference to generic type %0 requires arguments in <...>", (Type)) -NOTE(generic_type_declared_here,tce_sema,none, +NOTE(generic_type_declared_here,none, "generic type %0 declared here", (Identifier)) // Ambiguities -ERROR(ambiguous_decl_ref,tce_sema,none, +ERROR(ambiguous_decl_ref,none, "ambiguous use of %0", (DeclName)) -ERROR(ambiguous_operator_ref,tce_sema,none, +ERROR(ambiguous_operator_ref,none, "ambiguous use of operator %0", (DeclName)) // Cannot capture inout-ness of a parameter // Partial application of foreign functions not supported -ERROR(partial_application_of_function_invalid,tce_sema,none, +ERROR(partial_application_of_function_invalid,none, "partial application of %select{" "function with 'inout' parameters|" "'mutating' method|" @@ -1856,81 +1929,76 @@ ERROR(partial_application_of_function_invalid,tce_sema,none, "}0 is not allowed", (unsigned)) -ERROR(self_assignment_var,tce_sema,none, +ERROR(self_assignment_var,none, "assigning a variable to itself", ()) -ERROR(self_assignment_prop,tce_sema,none, +ERROR(self_assignment_prop,none, "assigning a property to itself", ()) -ERROR(property_use_in_closure_without_explicit_self,tce_sema,none, +ERROR(property_use_in_closure_without_explicit_self,none, "reference to property %0 in closure requires explicit 'self.' to make" " capture semantics explicit", (Identifier)) -ERROR(method_call_in_closure_without_explicit_self,tce_sema,none, +ERROR(method_call_in_closure_without_explicit_self,none, "call to method %0 in closure requires explicit 'self.' to make" " capture semantics explicit", (Identifier)) -ERROR(implicit_use_of_self_in_closure,tce_sema,none, +ERROR(implicit_use_of_self_in_closure,none, "implicit use of 'self' in closure; use 'self.' to make" " capture semantics explicit", ()) -ERROR(capture_before_declaration,tce_sema,none, +ERROR(capture_before_declaration,none, "cannot capture %0 before it is declared", (Identifier)) -ERROR(transitive_capture_before_declaration,tce_sema,none, +ERROR(transitive_capture_before_declaration,none, "cannot capture %0, which would use %1 before it is declared", (Identifier, Identifier)) -NOTE(transitive_capture_through_here,tce_sema,none, +NOTE(transitive_capture_through_here,none, "%0, declared here, captures %1", (Identifier, Identifier)) -ERROR(unsupported_local_function_reference,tce_sema,none, - "cannot reference a local function with captures from another local " - "function", ()) -ERROR(unsupported_recursive_local_function,tce_sema,none, - "local functions cannot reference themselves", ()) -WARNING(recursive_accessor_reference,tce_sema,none, +WARNING(recursive_accessor_reference,none, "attempting to %select{access|modify}1 %0 within its own " "%select{getter|setter}1", (Identifier, bool)) -NOTE(recursive_accessor_reference_silence,tce_sema,none, +NOTE(recursive_accessor_reference_silence,none, "access 'self' explicitly to silence this warning", ()) -WARNING(store_in_willset,tce_sema,none, +WARNING(store_in_willset,none, "attempting to store to property %0 within its own willSet, which is " "about to be overwritten by the new value", (Identifier)) -ERROR(value_of_module_type,tce_sema,none, +ERROR(value_of_module_type,none, "expected module member name after module name", ()) -ERROR(value_of_metatype_type,tce_sema,none, +ERROR(value_of_metatype_type,none, "expected member name or constructor call after type name", ()) -NOTE(add_parens_to_type,tce_sema,none, +NOTE(add_parens_to_type,none, "add arguments after the type to construct a value of the type", ()) -NOTE(add_self_to_type,tce_sema,none, +NOTE(add_self_to_type,none, "use '.self' to reference the type object", ()) -WARNING(warn_unqualified_access,tce_sema,none, +WARNING(warn_unqualified_access,none, "use of %0 treated as a reference to %1 in %2 %3", (Identifier, DescriptiveDeclKind, DescriptiveDeclKind, DeclName)) -NOTE(fix_unqualified_access_member,tce_sema,none, +NOTE(fix_unqualified_access_member,none, "use 'self.' to silence this warning", ()) -NOTE(fix_unqualified_access_top_level,tce_sema,none, +NOTE(fix_unqualified_access_top_level,none, "use '%0' to reference the %1", (StringRef, DescriptiveDeclKind, Identifier)) -NOTE(fix_unqualified_access_top_level_multi,tce_sema,none, +NOTE(fix_unqualified_access_top_level_multi,none, "use '%0' to reference the %1 in module %2", (StringRef, DescriptiveDeclKind, Identifier)) -ERROR(type_of_metatype,tce_sema,none, +ERROR(type_of_metatype,none, "'.dynamicType' is not allowed after a type name", ()) -ERROR(invalid_noescape_use,tce_sema,none, +ERROR(invalid_noescape_use,none, "@noescape parameter %0 may only be called", (Identifier)) -NOTE(noescape_autoclosure,tce_sema,none, +NOTE(noescape_autoclosure,none, "parameter %0 is implicitly @noescape because it was declared @autoclosure", (Identifier)) -ERROR(closure_noescape_use,tce_sema,none, +ERROR(closure_noescape_use,none, "closure use of @noescape parameter %0 may allow it to escape", (Identifier)) -ERROR(decl_closure_noescape_use,tce_sema,none, +ERROR(decl_closure_noescape_use,none, "declaration closing over @noescape parameter %0 may allow it to escape", (Identifier)) -ERROR(capture_across_type_decl,tce_sema,none, +ERROR(capture_across_type_decl,none, "%0 declaration cannot close over value %1 defined in outer scope", (DescriptiveDeclKind, Identifier)) @@ -1938,174 +2006,172 @@ ERROR(capture_across_type_decl,tce_sema,none, // Type Check Statements //------------------------------------------------------------------------------ -ERROR(jump_out_of_defer,sema_tcs,none, +ERROR(jump_out_of_defer,none, "'%0' cannot transfer control out of a defer statement", (StringRef)) -ERROR(return_invalid_outside_func,sema_tcs,none, +ERROR(return_invalid_outside_func,none, "return invalid outside of a func", ()) -ERROR(return_expr_missing,sema_tcs,none, +ERROR(return_expr_missing,none, "non-void function should return a value", ()) -ERROR(return_non_failable_init,sema_tcs,none, +ERROR(return_non_failable_init,none, "only a failable initializer can return 'nil'", ()) -NOTE(make_init_failable,sema_tcs,none, +NOTE(make_init_failable,none, "use 'init?' to make the initializer %0 failable", (DeclName)) -ERROR(return_init_non_nil,sema_tcs,none, +ERROR(return_init_non_nil,none, "'nil' is the only return value permitted in an initializer", ()) -WARNING(if_always_true,sema_tcd,none, +WARNING(if_always_true,none, "'if' condition is always true", ()) -WARNING(while_always_true,sema_tcd,none, +WARNING(while_always_true,none, "'while' condition is always true", ()) -WARNING(guard_always_succeeds,sema_tcd,none, +WARNING(guard_always_succeeds,none, "'guard' condition is always true, body is unreachable", ()) -ERROR(expression_unused_function,sema_tcs,none, +ERROR(expression_unused_function,none, "expression resolves to an unused function", ()) -ERROR(expression_unused_lvalue,sema_tcs,none, +ERROR(expression_unused_lvalue,none, "expression resolves to an unused l-value", ()) -WARNING(expression_unused_result,sema_tcs,none, +WARNING(expression_unused_result,none, "result of call to %0 is unused", (DeclName)) -WARNING(expression_unused_init_result,sema_tcs,none, +WARNING(expression_unused_init_result,none, "result of initializer is unused", ()) -WARNING(expression_unused_result_message,sema_tcs,none, +WARNING(expression_unused_result_message,none, "result of call to %0 is unused: %1", (DeclName, StringRef)) -WARNING(expression_unused_result_nonmutating,sema_tcs,none, +WARNING(expression_unused_result_nonmutating,none, "result of call to non-mutating function %0 is unused; " "use %1 to mutate in-place", (DeclName, DeclName)) -WARNING(expression_unused_optional_try,sema_tcs,none, +WARNING(expression_unused_optional_try,none, "result of 'try?' is unused", ()) -ERROR(assignment_lhs_not_lvalue,sema_tcs,none, +ERROR(assignment_lhs_not_lvalue,none, "cannot assign to immutable expression of type %0", (Type)) -ERROR(assignment_lhs_is_immutable_variable,sema_tcs,none, +ERROR(assignment_lhs_is_immutable_variable,none, "cannot assign to value: %0", (StringRef)) -ERROR(assignment_lhs_is_immutable_property,sema_tcs,none, +ERROR(assignment_lhs_is_immutable_property,none, "cannot assign to property: %0", (StringRef)) -ERROR(assignment_subscript_has_immutable_base,sema_tcs,none, +ERROR(assignment_subscript_has_immutable_base,none, "cannot assign through subscript: %0", (StringRef)) -ERROR(assignment_bang_has_immutable_subcomponent,sema_tcs,none, +ERROR(assignment_bang_has_immutable_subcomponent,none, "cannot assign through '!': %0", (StringRef)) -NOTE(change_to_mutating,sema_tcs,none, +NOTE(change_to_mutating,none, "mark %select{method|accessor}0 'mutating' to make 'self' mutable", (bool)) +// For Stmt +WARNING(deprecated_c_style_for_stmt,none, +"C-style for statement is deprecated and will be removed in a future version of Swift", ()) +NOTE(cant_fix_c_style_for_stmt,none, +"C-style for statement can't be automatically fixed to for-in, because the loop variable is modified inside the loop", ()) + // ForEach Stmt -ERROR(sequence_protocol_broken,sema_tcs,none, +ERROR(sequence_protocol_broken,none, "SequenceType protocol definition is broken", ()) -ERROR(generator_protocol_broken,sema_tcs,none, +ERROR(generator_protocol_broken,none, "GeneratorType protocol definition is broken", ()) -ERROR(label_shadowed,sema_tcs, none, +ERROR(label_shadowed, none, "label %0 cannot be reused on an inner statement", (Identifier)) -ERROR(break_outside_loop,sema_tcs,none, +ERROR(break_outside_loop,none, "'break' is only allowed inside a loop, if, do, or switch", ()) -ERROR(unlabeled_break_outside_loop,sema_tcs,none, +ERROR(unlabeled_break_outside_loop,none, "unlabeled 'break' is only allowed inside a loop or switch, a" " labeled break is required to exit an if or do", ()) -ERROR(continue_outside_loop,sema_tcs,none, +ERROR(continue_outside_loop,none, "'continue' is only allowed inside a loop", ()) -ERROR(continue_not_in_this_stmt,sema_tcs,none, +ERROR(continue_not_in_this_stmt,none, "'continue' cannot be used with %0 statements", (StringRef)) // Switch Stmt -ERROR(no_match_operator,sema_tcs,none, +ERROR(no_match_operator,none, "no binary '~=' operator available for 'switch' statement", ()) -ERROR(fallthrough_outside_switch,sema_tcs,none, +ERROR(fallthrough_outside_switch,none, "'fallthrough' is only allowed inside a switch", ()) -ERROR(fallthrough_from_last_case,sema_tcs,none, +ERROR(fallthrough_from_last_case,none, "'fallthrough' without a following 'case' or 'default' block", ()) -ERROR(fallthrough_into_case_with_var_binding,sema_tcs,none, +ERROR(fallthrough_into_case_with_var_binding,none, "'fallthrough' cannot transfer control to a case label that declares variables", ()) -ERROR(unnecessary_cast_over_optionset,sema_tcs,none, +ERROR(unnecessary_cast_over_optionset,none, "unnecessary cast over raw value of %0", (Type)) //------------------------------------------------------------------------------ // Type Check Patterns //------------------------------------------------------------------------------ -ERROR(cannot_infer_type_for_pattern,sema_tcp,none, +ERROR(cannot_infer_type_for_pattern,none, "type annotation missing in pattern", ()) -ERROR(refutable_pattern_requires_initializer,sema_tcd,none, +ERROR(refutable_pattern_requires_initializer,none, "pattern matching requires an initializer value to match against", ()) -ERROR(invalid_pattern,sema_tcd,none, +ERROR(invalid_pattern,none, "invalid pattern", ()) -WARNING(var_pattern_didnt_bind_variables, sema_tcp,none, +WARNING(var_pattern_didnt_bind_variables,none, "'%0' pattern has no effect; sub-pattern didn't bind any variables", (StringRef)) -ERROR(iflet_pattern_matching,sema_tcp,none, +ERROR(iflet_pattern_matching,none, "pattern matching in a condition requires the 'case' keyword", ()) -ERROR(iflet_implicitly_unwraps,sema_tcp,none, +ERROR(iflet_implicitly_unwraps,none, "pattern matching in a condition implicitly unwraps optionals", ()) -ERROR(type_pattern_missing_is,sema_tcp,none, +ERROR(type_pattern_missing_is,none, "'is' keyword required to pattern match against type name", ()) -ERROR(pattern_type_mismatch_context,sema_tcp,none, +ERROR(pattern_type_mismatch_context,none, "type annotation does not match contextual type %0", (Type)) -ERROR(label_single_entry_tuple,sema_tcp,none, - "label is not allowed on single element tuple pattern", ()) -NOTE(remove_parens_for_type_annotation,sema_tcp,none, - "remove the parentheses to make this a type annotation", ()) -NOTE(remove_label_for_tuple_pattern,sema_tcp,none, - "remove the label to make this a tuple pattern", ()) - -ERROR(tuple_pattern_in_non_tuple_context,sema_tcp,none, + +ERROR(tuple_pattern_in_non_tuple_context,none, "tuple pattern cannot match values of the non-tuple type %0", (Type)) -ERROR(closure_argument_list_tuple,sema_tcp,none, +ERROR(closure_argument_list_tuple,none, "contextual closure type %0 expects %1 argument%s1, " "but %2 were used in closure body", (Type, unsigned, unsigned)) -ERROR(closure_argument_list_missing,sema_tcp,none, +ERROR(closure_argument_list_missing,none, "contextual type for closure argument list expects %0 argument%s0, " "which cannot be implicitly ignored", (unsigned)) -ERROR(tuple_pattern_length_mismatch,sema_tcp,none, +ERROR(tuple_pattern_length_mismatch,none, "tuple pattern has the wrong length for tuple type %0", (Type)) -ERROR(tuple_pattern_label_mismatch,sema_tcp,none, +ERROR(tuple_pattern_label_mismatch,none, "tuple pattern element label %0 must be %1", (Identifier, Identifier)) -ERROR(enum_element_pattern_member_not_found,sema_tcp,none, +ERROR(enum_element_pattern_member_not_found,none, "enum case '%0' not found in type %1", (StringRef, Type)) -ERROR(enum_element_pattern_not_enum,sema_tcp,none, - "enum case pattern cannot match values of the non-enum type %0", (Type)) -ERROR(optional_element_pattern_not_valid_type,sema_tcp,none, +ERROR(optional_element_pattern_not_valid_type,none, "'?' pattern cannot match values of type %0", (Type)) -ERROR(condition_optional_element_pattern_not_valid_type,sema_tcp,none, +ERROR(condition_optional_element_pattern_not_valid_type,none, "initializer for conditional binding must have Optional type, not %0", (Type)) -ERROR(enum_element_pattern_not_member_of_enum,sema_tcp,none, +ERROR(enum_element_pattern_not_member_of_enum,none, "enum case '%0' is not a member of type %1", (StringRef, Type)) -ERROR(nominal_type_pattern_not_nominal_type,sema_tcp,none, +ERROR(nominal_type_pattern_not_nominal_type,none, "non-nominal type %0 cannot be used with property pattern syntax", (Type)) -ERROR(nominal_type_pattern_type_mismatch,sema_tcp,none, +ERROR(nominal_type_pattern_type_mismatch,none, "type %0 of pattern does not match deduced type %1", (Type, Type)) -ERROR(nominal_type_pattern_property_not_found,sema_tcp,none, +ERROR(nominal_type_pattern_property_not_found,none, "property '%0' not found in type %1", (StringRef, Type)) -ERROR(nominal_type_pattern_property_ambiguous,sema_tcp,none, +ERROR(nominal_type_pattern_property_ambiguous,none, "property name '%0' in type %1 is ambiguous", (StringRef, Type)) -ERROR(nominal_type_pattern_not_property,sema_tcp,none, +ERROR(nominal_type_pattern_not_property,none, "member '%0' of type %1 is not a property", (StringRef, Type)) -ERROR(nominal_type_pattern_static_property,sema_tcp,none, +ERROR(nominal_type_pattern_static_property,none, "cannot match type property '%0' of type %1 in a 'case' pattern", (StringRef, Type)) -ERROR(nominal_type_subpattern_without_property_name,pattern_parsing,none, +ERROR(nominal_type_subpattern_without_property_name,none, "subpattern of a struct or class pattern must have a keyword name", ()) -ERROR(ambiguous_enum_pattern_type,sema_tcp,none, +ERROR(ambiguous_enum_pattern_type,none, "generic enum type %0 is ambiguous without explicit generic parameters " "when matching value of type %1", (Type, Type)) -WARNING(type_inferred_to_undesirable_type,sema_tcp,none, +WARNING(type_inferred_to_undesirable_type,none, "%select{variable|constant}2 %0 inferred to have type %1, " "which may be unexpected", (Identifier, Type, bool)) -NOTE(add_explicit_type_annotation_to_silence,sema_tcp,none, +NOTE(add_explicit_type_annotation_to_silence,none, "add an explicit type annotation to silence this warning", ()) -ERROR(isa_pattern_value,sema_tcp,none, +ERROR(isa_pattern_value,none, "downcast pattern value of type %0 cannot be used", (Type)) //------------------------------------------------------------------------------ @@ -2114,190 +2180,184 @@ ERROR(isa_pattern_value,sema_tcp,none, -ERROR(try_unhandled,sema,none, +ERROR(try_unhandled,none, "errors thrown from here are not handled", ()) -ERROR(throwing_call_unhandled,sema,none, +ERROR(throwing_call_unhandled,none, "call can throw, but the error is not handled", ()) -ERROR(tryless_throwing_call_unhandled,sema,none, +ERROR(tryless_throwing_call_unhandled,none, "call can throw, but it is not marked with 'try' and " "the error is not handled", ()) -ERROR(throw_in_nonthrowing_function,sema,none, +ERROR(throw_in_nonthrowing_function,none, "error is not handled because the enclosing function " "is not declared 'throws'", ()) -ERROR(throwing_call_in_rethrows_function,sema,none, +ERROR(throwing_call_in_rethrows_function,none, "call can throw, but the error is not handled; a function declared " "'rethrows' may only throw if its parameter does", ()) -ERROR(tryless_throwing_call_in_rethrows_function,sema,none, +ERROR(tryless_throwing_call_in_rethrows_function,none, "call can throw, but it is not marked with 'try' and " "the error is not handled; a function declared " "'rethrows' may only throw if its parameter does", ()) -ERROR(throw_in_rethrows_function,sema,none, +ERROR(throw_in_rethrows_function,none, "a function declared 'rethrows' may only throw if its parameter does", ()) -NOTE(because_rethrows_argument_throws,sema,none, +NOTE(because_rethrows_argument_throws,none, "call is to 'rethrows' function, but argument function can throw", ()) -NOTE(because_rethrows_default_argument_throws,sema,none, +NOTE(because_rethrows_default_argument_throws,none, "call is to 'rethrows' function, but a defaulted argument function" " can throw", ()) -ERROR(throwing_call_in_nonthrowing_autoclosure,sema,none, +ERROR(throwing_call_in_nonthrowing_autoclosure,none, "call can throw, but it is executed in a non-throwing " "autoclosure",()) -ERROR(tryless_throwing_call_in_nonthrowing_autoclosure,sema,none, +ERROR(tryless_throwing_call_in_nonthrowing_autoclosure,none, "call can throw, but it is not marked with 'try' and " "it is executed in a non-throwing autoclosure",()) -ERROR(throw_in_nonthrowing_autoclosure,sema,none, +ERROR(throw_in_nonthrowing_autoclosure,none, "error is not handled because it is thrown in a non-throwing " "autoclosure", ()) -ERROR(try_unhandled_in_nonexhaustive_catch,sema,none, +ERROR(try_unhandled_in_nonexhaustive_catch,none, "errors thrown from here are not handled because the " "enclosing catch is not exhaustive", ()) -ERROR(throwing_call_in_nonexhaustive_catch,sema,none, +ERROR(throwing_call_in_nonexhaustive_catch,none, "call can throw, but the enclosing catch is not exhaustive", ()) -ERROR(tryless_throwing_call_in_nonexhaustive_catch,sema,none, +ERROR(tryless_throwing_call_in_nonexhaustive_catch,none, "call can throw, but it is not marked with 'try' and " "the enclosing catch is not exhaustive", ()) -ERROR(throw_in_nonexhaustive_catch,sema,none, +ERROR(throw_in_nonexhaustive_catch,none, "error is not handled because the enclosing catch is not exhaustive", ()) -ERROR(throwing_call_in_illegal_context,sema,none, +ERROR(throwing_call_in_illegal_context,none, "call can throw, but errors cannot be thrown out of %0", (StringRef)) -ERROR(throw_in_illegal_context,sema,none, +ERROR(throw_in_illegal_context,none, "errors cannot be thrown out of %0", (StringRef)) -ERROR(throwing_operator_without_try,sema,none, +ERROR(throwing_operator_without_try,none, "operator can throw but expression is not marked with 'try'", ()) -ERROR(throwing_call_without_try,sema,none, +ERROR(throwing_call_without_try,none, "call can throw but is not marked with 'try'", ()) -WARNING(no_throw_in_try,sema,none, +WARNING(no_throw_in_try,none, "no calls to throwing functions occur within 'try' expression", ()) -WARNING(no_throw_in_do_with_catch,sema,none, +WARNING(no_throw_in_do_with_catch,none, "'catch' block is unreachable because no errors are thrown in 'do' block", ()) //------------------------------------------------------------------------------ // Type Check Types //------------------------------------------------------------------------------ -ERROR(sugar_type_not_found,sema_tct,none, +ERROR(sugar_type_not_found,none, "broken standard library: cannot find " "%select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|" "ErrorType}0 type", (unsigned)) -ERROR(optional_intrinsics_not_found,sema_tct,none, +ERROR(optional_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on " "Optional", ()) -ERROR(pointer_argument_intrinsics_not_found,sema_tct,none, +ERROR(pointer_argument_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on " "UnsafeMutablePointer", ()) -ERROR(array_literal_intrinsics_not_found,sema_tct,none, +ERROR(array_literal_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on " "Array", ()) -ERROR(bool_intrinsics_not_found,sema_tct,none, +ERROR(bool_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on Bool", ()) -ERROR(self_in_nominal,sema_tct,none, +ERROR(self_in_nominal,none, "'Self' is only available in a protocol or as the result of a " "method in a class; did you mean %0?", (Identifier)) -ERROR(class_super_access,sema_tcd,none, +ERROR(class_super_access,none, "class %select{must be declared %select{private|internal|PUBLIC}2" "|cannot be declared %select{PRIVATE|internal|public}1}0 because its " "superclass is %select{private|internal|PUBLIC}2", (bool, Accessibility, Accessibility)) -ERROR(dot_protocol_on_non_existential,sema_tct,none, +ERROR(dot_protocol_on_non_existential,none, "cannot use 'Protocol' with non-protocol type %0", (Type)) -ERROR(tuple_single_element,sema_tcd,none, +ERROR(tuple_single_element,none, "cannot create a single-element tuple with an element label", ()) -ERROR(tuple_ellipsis,sema_tcd,none, +ERROR(tuple_ellipsis,none, "cannot create a variadic tuple", ()) // Ownership -ERROR(invalid_ownership_type,attribute_parsing,none, +ERROR(invalid_ownership_type,none, "'%select{strong|weak|unowned|unowned}0' may only be applied to " "class and class-bound protocol types, not %1", (/*Ownership*/unsigned, Type)) -ERROR(invalid_ownership_protocol_type,attribute_parsing,none, +ERROR(invalid_ownership_protocol_type,none, "'%select{strong|weak|unowned|unowned}0' may not be applied to " "non-class-bound protocol %1; consider adding a class bound", (/*Ownership*/unsigned, Type)) -ERROR(invalid_weak_ownership_not_optional,attribute_parsing,none, +ERROR(invalid_weak_ownership_not_optional,none, "'weak' variable should have optional type %0", (Type)) -ERROR(invalid_weak_let,attribute_parsing,none, +ERROR(invalid_weak_let,none, "'weak' must be a mutable variable, because it may change at runtime", ()) // required -ERROR(required_initializer_nonclass,attribute_parsing,none, +ERROR(required_initializer_nonclass,none, "'required' initializer in non-class type %0", (Type)) -ERROR(required_initializer_in_extension,attribute_parsing,none, +ERROR(required_initializer_in_extension,none, "'required' initializer must be declared directly in class %0" " (not in an extension)", (Type)) -ERROR(required_initializer_missing,attribute_parsing,none, +ERROR(required_initializer_missing,none, "'required' initializer %0 must be provided by subclass of %1", (DeclName, Type)) -NOTE(required_initializer_here,sema_tcd,none, +NOTE(required_initializer_here,none, "'required' initializer is declared in superclass here", ()) -ERROR(required_initializer_not_accessible,sema_tcd,none, +ERROR(required_initializer_not_accessible,none, "'required' initializer must be as accessible as its enclosing type", ()) -ERROR(required_initializer_missing_keyword,sema_tcd,none, +ERROR(required_initializer_missing_keyword,none, "'required' modifier must be present on all overrides of a required " "initializer", ()) -ERROR(required_initializer_override_wrong_keyword,sema_tcd,none, +ERROR(required_initializer_override_wrong_keyword,none, "use the 'required' modifier to override a required initializer", ()) -WARNING(required_initializer_override_keyword,sema_tcd,none, +WARNING(required_initializer_override_keyword,none, "'override' is implied when overriding a required initializer", ()) -NOTE(overridden_required_initializer_here,sema_tcd,none, +NOTE(overridden_required_initializer_here,none, "overridden required initializer is here", ()) // Functions -ERROR(attribute_requires_function_type,attribute_parsing,none, +ERROR(attribute_requires_function_type,none, "attribute only applies to syntactic function types", ()) -ERROR(first_class_generic_function,type_parsing,PointsToFirstBadToken, - "generic types cannot be used as first-class types", ()) -ERROR(objc_block_cannot_be_thin,attribute_parsing,none, +ERROR(objc_block_cannot_be_thin,none, "@objc_block function type cannot be @thin", ()) -ERROR(attribute_not_supported,attribute_parsing,none, +ERROR(attribute_not_supported,none, "this attribute is not supported", ()) -ERROR(convention_with_deprecated_representation_attribute,attribute_parsing,none, +ERROR(convention_with_deprecated_representation_attribute,none, "@convention attribute cannot be used with deprecated @%0 attribute", (StringRef)) -ERROR(unsupported_convention,type_parsing,none, +ERROR(unsupported_convention,none, "convention '%0' not supported", (StringRef)) -ERROR(unreferenced_generic_parameter,type_parsing,none, +ERROR(unreferenced_generic_parameter,none, "generic parameter '%0' is not used in function signature", (StringRef)) -WARNING(deprecated_convention_attribute,type_parsing,none, +WARNING(deprecated_convention_attribute,none, "'@%0' attribute is deprecated; '@convention(%1)' should be used " "instead", (StringRef, StringRef)) // SIL -ERROR(sil_local_storage_nested, decl_parsing,none, - "local storage types cannot be in nested positions", ()) -ERROR(opened_non_protocol, decl_parsing,none, +ERROR(opened_non_protocol,none, "@opened cannot be applied to non-protocol type %0", (Type)) -ERROR(sil_function_ellipsis,type_parsing,PointsToFirstBadToken, +ERROR(sil_function_ellipsis,PointsToFirstBadToken, "SIL function types cannot be variadic", ()) -ERROR(sil_function_label,type_parsing,PointsToFirstBadToken, +ERROR(sil_function_label,PointsToFirstBadToken, "SIL function types cannot have labeled inputs", ()) -ERROR(sil_function_repeat_convention,type_parsing,PointsToFirstBadToken, +ERROR(sil_function_repeat_convention,PointsToFirstBadToken, "repeated %select{parameter|result|callee}0 convention attribute", (unsigned)) -ERROR(sil_function_multiple_results,type_parsing,PointsToFirstBadToken, +ERROR(sil_function_multiple_results,PointsToFirstBadToken, "SIL function types cannot have multiple results", ()) -ERROR(sil_function_multiple_error_results,type_parsing,PointsToFirstBadToken, +ERROR(sil_function_multiple_error_results,PointsToFirstBadToken, "SIL function types cannot have multiple @error results", ()) -ERROR(unsupported_cc_representation_combo,type_parsing,none, - "cc unsupported with this sil representation", ()) -ERROR(unsupported_sil_convention,type_parsing,none, +ERROR(unsupported_sil_convention,none, "convention '%0' not supported in SIL", (StringRef)) -ERROR(sil_deprecated_convention_attribute,type_parsing,none, +ERROR(sil_deprecated_convention_attribute,none, "'@%0' attribute is deprecated; '@convention(%1)' must be used instead", (StringRef, StringRef)) // SIL Metatypes -ERROR(sil_metatype_without_repr,type_parsing,none, +ERROR(sil_metatype_without_repr,none, "metatypes in SIL must have @thin, @thick, or @objc_metatype attribute", ()) -ERROR(sil_metatype_multiple_reprs,type_parsing,none, +ERROR(sil_metatype_multiple_reprs,none, "metatypes in SIL can only be one of @thin, @thick, or @objc_metatype", ()) @@ -2305,192 +2365,195 @@ ERROR(sil_metatype_multiple_reprs,type_parsing,none, // @objc and @nonobjc //------------------------------------------------------------------------------ -ERROR(attr_used_without_required_module, sema_tcd, none, +ERROR(attr_used_without_required_module, none, "%0 attribute used without importing module %1", (DeclAttribute, Identifier)) -ERROR(invalid_objc_decl_context,sema_tcd,none, +ERROR(invalid_objc_decl_context,none, "@objc can only be used with members of classes, @objc protocols, and " "concrete extensions of classes", ()) -ERROR(invalid_objc_decl,sema_tcd,none, +ERROR(invalid_objc_decl,none, "only classes, protocols, methods, initializers, properties, and " "subscript declarations can be declared @objc", ()) -ERROR(invalid_objc_swift_rooted_class,sema_tcd,none, +ERROR(invalid_objc_swift_rooted_class,none, "only classes that inherit from NSObject can be declared @objc", ()) -ERROR(invalid_nonobjc_decl,sema_tcd,none, +ERROR(invalid_nonobjc_decl,none, "only methods, initializers, properties and subscript declarations can " "be declared @nonobjc", ()) -ERROR(objc_in_extension_context,sema_objc,none, +ERROR(objc_in_extension_context,none, "members of constrained extensions cannot be declared @objc", ()) -ERROR(objc_in_generic_extension,sema_objc,none, +ERROR(objc_in_generic_extension,none, "@objc is not supported within extensions of generic classes", ()) -ERROR(objc_for_generic_class,sema_objc,none, +ERROR(objc_for_generic_class,none, "generic subclasses of '@objc' classes cannot have an explicit '@objc' " "attribute because they are not directly visible from Objective-C", ()) -ERROR(objc_getter_for_nonobjc_property,sema_tcd,none, +ERROR(objc_getter_for_nonobjc_property,none, "'@objc' getter for non-'@objc' property", ()) -ERROR(objc_getter_for_nonobjc_subscript,sema_tcd,none, +ERROR(objc_getter_for_nonobjc_subscript,none, "'@objc' getter for non-'@objc' subscript", ()) -ERROR(objc_setter_for_nonobjc_property,sema_tcd,none, +ERROR(objc_setter_for_nonobjc_property,none, "'@objc' setter for non-'@objc' property", ()) -ERROR(objc_setter_for_nonobjc_subscript,sema_tcd,none, +ERROR(objc_setter_for_nonobjc_subscript,none, "'@objc' setter for non-'@objc' subscript", ()) -ERROR(objc_enum_generic,sema_tcd,none, +ERROR(objc_enum_generic,none, "'@objc' enum cannot be generic", ()) -ERROR(objc_name_req_nullary,sema_objc,none, - "'@objc' %select{class|protocol|property}0 must have a simple name", (int)) -ERROR(objc_name_enum,sema_objc,none, - "'@objc' enum cannot have a name", ()) -ERROR(objc_name_subscript,sema_objc,none, +ERROR(objc_name_req_nullary,none, + "'@objc' %select{class|protocol|enum|enum case|property}0 must have a simple name", (int)) +ERROR(objc_name_subscript,none, "'@objc' subscript cannot have a name; did you mean to put " "the name on the getter or setter?", ()) -ERROR(objc_name_func_mismatch,sema_objc,none, +ERROR(objc_name_func_mismatch,none, "'@objc' %select{initializer|method}0 name provides " "%select{one argument name|names for %1 arguments}2, but " "%select{initializer|method}0 has %select{one parameter|%3 parameters}4" "%select{| (%select{|including }4the error parameter)}5", (bool, unsigned, bool, unsigned, bool, bool)) +ERROR(objc_enum_case_req_name,none, + "attribute has no effect; cases within an '@objc' enum are already " + "exposed to Objective-C", ()) +ERROR(objc_enum_case_req_objc_enum,none, + "'@objc' enum case is not allowed outside of an '@objc' enum", ()) +ERROR(objc_enum_case_multi,none, + "'@objc' enum case declaration defines multiple enum cases with the same Objective-C name", ()) // If you change this, also change enum ObjCReason #define OBJC_ATTR_SELECT "select{marked dynamic|marked @objc|marked @IBOutlet|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override}" -ERROR(objc_invalid_on_var,sema_objc,none, +ERROR(objc_invalid_on_var,none, "property cannot be %" OBJC_ATTR_SELECT "0 " "because its type cannot be represented in Objective-C", (unsigned)) -ERROR(objc_invalid_subscript_key_type,sema_objc,none, +ERROR(objc_invalid_subscript_key_type,none, "subscript cannot be %" OBJC_ATTR_SELECT "0 because its key " "type %1 is neither an integer nor an object", (unsigned, Type)) -ERROR(objc_invalid_on_subscript,sema_objc,none, +ERROR(objc_invalid_on_subscript,none, "subscript cannot be %" OBJC_ATTR_SELECT "0 because its type " "cannot be represented in Objective-C", (unsigned)) -ERROR(objc_invalid_with_generic_params,sema_objc,none, +ERROR(objc_invalid_with_generic_params,none, "method cannot be %" OBJC_ATTR_SELECT "0 because it has generic " "parameters", (unsigned)) -ERROR(objc_convention_invalid,sema_objc,none, +ERROR(objc_convention_invalid,none, "%0 is not representable in Objective-C, so it cannot be used" " with '@convention(%1)'", (Type, StringRef)) -NOTE(not_objc_empty_protocol_composition,sema_objc,none, +NOTE(not_objc_empty_protocol_composition,none, "'protocol<>' is not considered '@objc'; use 'AnyObject' instead", ()) -NOTE(not_objc_protocol,sema_objc,none, +NOTE(not_objc_protocol,none, "protocol %0 is not '@objc'", (Type)) -NOTE(not_objc_empty_tuple,sema_objc,none, +NOTE(not_objc_empty_tuple,none, "empty tuple type cannot be represented in Objective-C", ()) -NOTE(not_objc_tuple,sema_objc,none, +NOTE(not_objc_tuple,none, "tuples cannot be represented in Objective-C", ()) -NOTE(not_objc_swift_class,sema_objc,none, +NOTE(not_objc_swift_class,none, "classes not annotated with @objc cannot be represented " "in Objective-C", ()) -NOTE(not_objc_swift_struct,sema_objc,none, +NOTE(not_objc_swift_struct,none, "Swift structs cannot be represented in Objective-C", ()) -NOTE(not_objc_swift_enum,sema_objc,none, +NOTE(not_objc_swift_enum,none, "non-'@objc' enums cannot be represented in Objective-C", ()) -NOTE(not_objc_generic_type_param,sema_objc,none, +NOTE(not_objc_generic_type_param,none, "generic type parameters cannot be represented in Objective-C", ()) -NOTE(not_objc_function_type_param,sema_objc,none, +NOTE(not_objc_function_type_param,none, "function types cannot be represented in Objective-C unless their " "parameters and returns can be", ()) -NOTE(not_objc_function_type_throwing,sema_objc,none, +NOTE(not_objc_function_type_throwing,none, "throwing function types cannot be represented in Objective-C", ()) -NOTE(objc_inferring_on_objc_protocol_member,sema_objc,none, +NOTE(objc_inferring_on_objc_protocol_member,none, "inferring '@objc' because the declaration is a member of " "an '@objc' protocol", ()) -NOTE(objc_overriding_objc_decl,sema_objc,none, +NOTE(objc_overriding_objc_decl,none, "overriding '@objc' %select{property|subscript|initializer|method}0 %1 " "here", (unsigned, DeclName)) -ERROR(objc_invalid_on_func_curried,sema_objc,none, +ERROR(objc_invalid_on_func_curried,none, "method cannot be %" OBJC_ATTR_SELECT "0 because curried functions " "cannot be represented in Objective-C", (unsigned)) -ERROR(objc_observing_accessor,sema_objc, none, +ERROR(objc_observing_accessor, none, "observing accessors are not allowed to be marked @objc", ()) -ERROR(objc_invalid_on_func_variadic,sema_objc,none, +ERROR(objc_invalid_on_func_variadic,none, "method cannot be %" OBJC_ATTR_SELECT "0 because it has a variadic " "parameter", (unsigned)) -ERROR(objc_invalid_on_func_param_type,sema_objc,none, +ERROR(objc_invalid_on_func_param_type,none, "method cannot be %" OBJC_ATTR_SELECT "1 because the type of the " "parameter %0 cannot be represented in Objective-C", (unsigned, unsigned)) -ERROR(objc_invalid_on_func_single_param_type,sema_objc,none, +ERROR(objc_invalid_on_func_single_param_type,none, "method cannot be %" OBJC_ATTR_SELECT "0 because the type of the " "parameter cannot be represented in Objective-C", (unsigned)) -ERROR(objc_invalid_on_func_result_type,sema_objc,none, +ERROR(objc_invalid_on_func_result_type,none, "method cannot be %" OBJC_ATTR_SELECT "0 because its result type " "cannot be represented in Objective-C", (unsigned)) -ERROR(objc_invalid_on_foreign_class,sema_objc,none, +ERROR(objc_invalid_on_foreign_class,none, "method cannot be %" OBJC_ATTR_SELECT "0 because Core Foundation " "types are not classes in Objective-C", (unsigned)) -ERROR(objc_invalid_on_throwing_optional_result,sema_objc,none, +ERROR(objc_invalid_on_throwing_optional_result,none, "throwing method cannot be %" OBJC_ATTR_SELECT "0 because " "it returns a value of optional type %1; 'nil' indicates failure to " "Objective-C", (unsigned, Type)) -ERROR(objc_invalid_on_throwing_result,sema_objc,none, +ERROR(objc_invalid_on_throwing_result,none, "throwing method cannot be %" OBJC_ATTR_SELECT "0 because " "it returns a value of type %1; return 'Void' or a type that bridges " "to an Objective-C class", (unsigned, Type)) -ERROR(objc_invalid_on_failing_init,sema_objc,none, +ERROR(objc_invalid_on_failing_init,none, "a failable and throwing initializer cannot be " "%" OBJC_ATTR_SELECT "0 because 'nil' indicates failure to Objective-C", (unsigned)) -ERROR(objc_override_method_selector_mismatch,sema_objc,none, +ERROR(objc_override_method_selector_mismatch,none, "Objective-C method has a different selector from the " "method it overrides (%0 vs. %1)", (ObjCSelector, ObjCSelector)) -ERROR(objc_override_property_name_mismatch,sema_objc,none, +ERROR(objc_override_property_name_mismatch,none, "Objective-C property has a different name from the " "property it overrides (%0 vs. %1)", (Identifier, Identifier)) -ERROR(broken_bridged_to_objc_protocol,sema_tcd,none, +ERROR(broken_bridged_to_objc_protocol,none, "_BridgedToObjectiveC protocol is broken", ()) -ERROR(type_not_bridged,sema_objc,none, - "%0 is not bridged to Objective-C", (Type)) -ERROR(missing_bridging_function,sema_objc,Fatal, +ERROR(missing_bridging_function,Fatal, "missing '%select{_forceBridgeFromObjectiveC|" "_conditionallyBridgeFromObjectiveC}0'", (bool)) -ERROR(missing_nserror_bridging_function,sema_objc,none, +ERROR(missing_nserror_bridging_function,none, "missing _bridgeNSError", ()) #define OBJC_DIAG_SELECT "%select{initializer %1|implicit initializer %1|deinitializer|implicit deinitializer|method %1|getter for %1|subscript getter|setter for %1|subscript setter}0" #define OBJC_DIAG_SELECT_2 "%select{initializer %3|implicit initializer %3|deinitializer|implicit deinitializer|method %3|getter for %3|subscript getter|setter for %3|subscript setter}2" -ERROR(objc_redecl,sema_objc,none, +ERROR(objc_redecl,none, OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with " OBJC_DIAG_SELECT_2 " with the same Objective-C selector", (unsigned, DeclName, unsigned, DeclName, ObjCSelector)) -NOTE(objc_declared_here,sema_objc,none, +NOTE(objc_declared_here,none, OBJC_DIAG_SELECT " declared here", (unsigned, DeclName)) -ERROR(objc_redecl_same,sema_objc,none, +ERROR(objc_redecl_same,none, OBJC_DIAG_SELECT " with Objective-C selector %2 conflicts with " "previous declaration with the same Objective-C selector", (unsigned, DeclName, ObjCSelector)) -ERROR(objc_override_other,sema_objc,none, +ERROR(objc_override_other,none, OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with " OBJC_DIAG_SELECT_2 " from superclass %5 with the same Objective-C " "selector", (unsigned, DeclName, unsigned, DeclName, ObjCSelector, Type)) -ERROR(objc_class_method_not_permitted,sema_objc,none, +ERROR(objc_class_method_not_permitted,none, OBJC_DIAG_SELECT " defines Objective-C class method %2, which is " "not permitted by Swift", (unsigned, DeclName, ObjCSelector)) -NOTE(objc_witness_selector_mismatch,sema_objc,none, +NOTE(objc_witness_selector_mismatch,none, "Objective-C method %2 provided by " OBJC_DIAG_SELECT " does not match the requirement's selector (%3)", (unsigned, DeclName, ObjCSelector, ObjCSelector)) -ERROR(objc_optional_requirement_conflict,sema_objc,none, +ERROR(objc_optional_requirement_conflict,none, "Objective-C method %4 provided by " OBJC_DIAG_SELECT " conflicts with optional requirement " OBJC_DIAG_SELECT_2 " in protocol %5", (unsigned, DeclName, unsigned, DeclName, ObjCSelector, DeclName)) -ERROR(nonobjc_not_allowed,sema_objc,none, +ERROR(nonobjc_not_allowed,none, "declaration is %" OBJC_ATTR_SELECT "0, and cannot be marked @nonobjc", (unsigned)) @@ -2502,9 +2565,9 @@ ERROR(nonobjc_not_allowed,sema_objc,none, // dynamic //------------------------------------------------------------------------------ -ERROR(dynamic_not_in_class,sema_dynamic,none, +ERROR(dynamic_not_in_class,none, "only members of classes may be dynamic", ()) -ERROR(dynamic_with_final,sema_dynamic,none, +ERROR(dynamic_with_final,none, "a declaration cannot be both 'final' and 'dynamic'", ()) @@ -2512,154 +2575,154 @@ ERROR(dynamic_with_final,sema_dynamic,none, // @available //------------------------------------------------------------------------------ -ERROR(availability_decl_unavailable, sema_avail, none, +ERROR(availability_decl_unavailable, none, "%0 is unavailable", (DeclName)) -ERROR(availability_decl_unavailable_rename, sema_avail, none, +ERROR(availability_decl_unavailable_rename, none, "%0 has been renamed to '%1'", (DeclName, StringRef)) -ERROR(availability_decl_unavailable_rename_msg, sema_avail, none, +ERROR(availability_decl_unavailable_rename_msg, none, "%0 has been renamed to '%1': %2", (DeclName, StringRef, StringRef)) -ERROR(availability_decl_unavailable_msg, sema_avail, none, +ERROR(availability_decl_unavailable_msg, none, "%0 is unavailable: %1", (DeclName, StringRef)) -ERROR(availability_decl_unavailable_in_swift, sema_avail, none, +ERROR(availability_decl_unavailable_in_swift, none, "%0 is unavailable in Swift", (DeclName)) -ERROR(availability_decl_unavailable_in_swift_msg, sema_avail, none, +ERROR(availability_decl_unavailable_in_swift_msg, none, "%0 is unavailable in Swift: %1", (DeclName, StringRef)) -NOTE(availability_marked_unavailable, sema_avail, none, +NOTE(availability_marked_unavailable, none, "%0 has been explicitly marked unavailable here", (DeclName)) -NOTE(availability_obsoleted, sema_avail, none, +NOTE(availability_obsoleted, none, "%0 was obsoleted in %1 %2", (DeclName, StringRef, clang::VersionTuple)) -WARNING(availability_deprecated, sema_avail, none, +WARNING(availability_deprecated, none, "%0 %select{is|%select{is|was}3}1 deprecated" "%select{| %select{on|in}3 %2%select{| %4}3}1", (DeclName, bool, StringRef, bool, clang::VersionTuple)) -WARNING(availability_deprecated_msg, sema_avail, none, +WARNING(availability_deprecated_msg, none, "%0 %select{is|%select{is|was}3}1 deprecated" "%select{| %select{on|in}3 %2%select{| %4}3}1: %5", (DeclName, bool, StringRef, bool, clang::VersionTuple, StringRef)) -WARNING(availability_deprecated_rename, sema_avail, none, +WARNING(availability_deprecated_rename, none, "%0 %select{is|%select{is|was}3}1 deprecated" "%select{| %select{on|in}3 %2%select{| %4}3}1: renamed to '%5'", (DeclName, bool, StringRef, bool, clang::VersionTuple, StringRef)) -NOTE(note_deprecated_rename, sema_avail, none, +NOTE(note_deprecated_rename, none, "use '%0' instead", (StringRef)) -ERROR(availability_decl_more_than_enclosing, sema_avail, none, +ERROR(availability_decl_more_than_enclosing, none, "declaration cannot be more available than enclosing scope", ()) -NOTE(availability_decl_more_than_enclosing_enclosing_here, sema_avail, none, +NOTE(availability_decl_more_than_enclosing_enclosing_here, none, "enclosing scope here", ()) -ERROR(availability_decl_only_version_newer, sema_avail, none, +ERROR(availability_decl_only_version_newer, none, "%0 is only available on %1 %2 or newer", (DeclName, StringRef, clang::VersionTuple)) -NOTE(availability_guard_with_version_check, sema_avail, none, +NOTE(availability_guard_with_version_check, none, "add 'if #available' version check", ()) -NOTE(availability_add_attribute, sema_avail, none, +NOTE(availability_add_attribute, none, "add @available attribute to enclosing %0", (DescriptiveDeclKind)) -ERROR(availability_accessor_only_version_newer, sema_avail, none, +ERROR(availability_accessor_only_version_newer, none, "%select{getter|setter}0 for %1 is only available on %2 %3" " or newer", (/*AccessorKind*/unsigned, DeclName, StringRef, clang::VersionTuple)) -ERROR(availability_inout_accessor_only_version_newer, sema_avail, none, +ERROR(availability_inout_accessor_only_version_newer, none, "cannot pass as inout because %select{getter|setter}0 for %1 is only " "available on %2 %3 or newer", (/*AccessorKind*/unsigned, DeclName, StringRef, clang::VersionTuple)) -ERROR(availability_query_required_for_platform, sema_avail, none, +ERROR(availability_query_required_for_platform, none, "condition required for target platform '%0'", (StringRef)) -WARNING(availability_query_useless_min_deployment, sema_avail, none, +WARNING(availability_query_useless_min_deployment, none, "unnecessary check for '%0'; minimum deployment target ensures guard " "will always be true", (StringRef)) -WARNING(availability_query_useless_enclosing_scope, sema_avail, none, +WARNING(availability_query_useless_enclosing_scope, none, "unnecessary check for '%0'; enclosing scope ensures guard " "will always be true", (StringRef)) -NOTE(availability_query_useless_enclosing_scope_here, sema_avail, none, +NOTE(availability_query_useless_enclosing_scope_here, none, "enclosing scope here", ()) -ERROR(availability_global_script_no_potential, sema_avail, +ERROR(availability_global_script_no_potential, none, "global variable cannot be marked potentially " "unavailable with '@available' in script mode", ()) -ERROR(availability_stored_property_no_potential, sema_avail, +ERROR(availability_stored_property_no_potential, none, "stored properties cannot be marked potentially unavailable with " "'@available'", ()) -ERROR(availability_protocol_requires_version, sema_avail, +ERROR(availability_protocol_requires_version, none, "protocol %0 requires %1 to be available on %2 %3 and newer", (DeclName, DeclName, StringRef, clang::VersionTuple)) -NOTE(availability_protocol_requirement_here, sema_avail, none, +NOTE(availability_protocol_requirement_here, none, "protocol requirement here", ()) -NOTE(availability_conformance_introduced_here, sema_avail, none, +NOTE(availability_conformance_introduced_here, none, "conformance introduced here", ()) //------------------------------------------------------------------------------ // Variable usage diagnostics //------------------------------------------------------------------------------ -WARNING(pbd_never_used_stmtcond, sema_varusage, none, +WARNING(pbd_never_used_stmtcond, none, "value %0 was defined but never used; consider replacing " "with boolean test", (Identifier)) -WARNING(pbd_never_used, sema_varusage, none, +WARNING(pbd_never_used, none, "initialization of %select{variable|immutable value}1 %0 was never used" "; consider replacing with assignment to '_' or removing it", (Identifier, unsigned)) -WARNING(capture_never_used, sema_varusage, none, +WARNING(capture_never_used, none, "capture %0 was never used", (Identifier)) -WARNING(variable_never_used, sema_varusage, none, +WARNING(variable_never_used, none, "%select{variable|immutable value}1 %0 was never used; " "consider replacing with '_' or removing it", (Identifier, unsigned)) -WARNING(variable_never_mutated, sema_varusage, none, +WARNING(variable_never_mutated, none, "%select{variable|parameter}1 %0 was never mutated; " "consider changing to 'let' constant", (Identifier, unsigned)) -WARNING(variable_never_read, sema_varusage, none, +WARNING(variable_never_read, none, "%select{variable|parameter}1 %0 was written to, but never read", (Identifier, unsigned)) //------------------------------------------------------------------------------ // Naming convention diagnostics //------------------------------------------------------------------------------ -WARNING(omit_needless_words, sema_tcd, none, +WARNING(omit_needless_words, none, "%0 could be named %1 [-Womit-needless-words]", (DeclName, DeclName)) -WARNING(extraneous_default_args_in_call, sema_tcd, none, +WARNING(extraneous_default_args_in_call, none, "call to %0 has extraneous arguments that could use defaults", (DeclName)) //------------------------------------------------------------------------------ // Circular reference diagnostics //------------------------------------------------------------------------------ -ERROR(circular_reference, sema_tcd, none, +ERROR(circular_reference, none, "circular reference", ()) -NOTE(circular_reference_through, sema_tcd, none, +NOTE(circular_reference_through, none, "through reference here", ()) #ifndef DIAG_NO_UNDEF diff --git a/include/swift/AST/DiagnosticsSema.h b/include/swift/AST/DiagnosticsSema.h index 1177807691734..d2cac6e713308 100644 --- a/include/swift/AST/DiagnosticsSema.h +++ b/include/swift/AST/DiagnosticsSema.h @@ -1,8 +1,8 @@ -//===- DiagnosticsSema.h - Diagnostic Definitions ---------------*- C++ -*-===// +//===--- DiagnosticsSema.h - Diagnostic Definitions -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { namespace diag { - /// Describes the kind of requirement in a protocl. + /// Describes the kind of requirement in a protocol. enum class RequirementKind : uint8_t { Constructor, Func, @@ -32,7 +32,7 @@ namespace swift { }; // Declare common diagnostics objects with their appropriate types. -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ extern detail::DiagWithArguments::type ID; #include "DiagnosticsSema.def" } diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 4bc2a2f06980c..c7b0bfee6cf82 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,15 +19,10 @@ #include "swift/AST/CaptureInfo.h" #include "swift/AST/ConcreteDeclRef.h" -#include "swift/AST/DeclContext.h" -#include "swift/AST/Identifier.h" -#include "swift/AST/Substitution.h" +#include "swift/AST/DeclNameLoc.h" +#include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/Availability.h" -#include "swift/Basic/SourceLoc.h" -#include "swift/Config.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" namespace llvm { struct fltSemantics; @@ -49,11 +44,11 @@ namespace swift { class Initializer; class VarDecl; class OpaqueValueExpr; - class ProtocolConformance; class FuncDecl; class ConstructorDecl; class TypeDecl; class PatternBindingDecl; + class ParameterList; enum class ExprKind : uint8_t { #define EXPR(Id, Parent) Id, @@ -758,7 +753,7 @@ class InterpolatedStringLiteralExpr : public LiteralExpr { return Segments.front()->getStartLoc(); } SourceLoc getEndLoc() const { - return Segments.front()->getEndLoc(); + return Segments.back()->getEndLoc(); } static bool classof(const Expr *E) { @@ -899,14 +894,14 @@ class DeclRefExpr : public Expr { /// \brief The declaration pointer or SpecializeInfo pointer if it was /// explicitly specialized with <...>. llvm::PointerUnion DOrSpecialized; - SourceLoc Loc; + DeclNameLoc Loc; SpecializeInfo *getSpecInfo() const { return DOrSpecialized.dyn_cast(); } public: - DeclRefExpr(ConcreteDeclRef D, SourceLoc Loc, bool Implicit, + DeclRefExpr(ConcreteDeclRef D, DeclNameLoc Loc, bool Implicit, AccessSemantics semantics = AccessSemantics::Ordinary, Type Ty = Type()) : Expr(ExprKind::DeclRef, Implicit, Ty), DOrSpecialized(D), Loc(Loc) { @@ -949,8 +944,10 @@ class DeclRefExpr : public Expr { return Spec->GenericArgs; return ArrayRef(); } - SourceRange getSourceRange() const { return Loc; } - + SourceRange getSourceRange() const { return Loc.getSourceRange(); } + SourceLoc getLoc() const { return Loc.getBaseNameLoc(); } + DeclNameLoc getNameLoc() const { return Loc; } + static bool classof(const Expr *E) { return E->getKind() == ExprKind::DeclRef; } @@ -987,6 +984,10 @@ class TypeExpr : public Expr { // Create a TypeExpr with location information. TypeExpr(TypeLoc Ty); + // The type of a TypeExpr is always a metatype type. Return the instance + // type, ErrorType if an error, or null if not set yet. + Type getInstanceType() const; + // Create an implicit TypeExpr, which has no location information. static TypeExpr *createImplicit(Type Ty, ASTContext &C) { return new (C) TypeExpr(Ty); @@ -999,7 +1000,8 @@ class TypeExpr : public Expr { /// Return a TypeExpr for a TypeDecl and the specified location. - static TypeExpr *createForDecl(SourceLoc Loc, TypeDecl *D); + static TypeExpr *createForDecl(SourceLoc Loc, TypeDecl *D, + bool isImplicit); static TypeExpr *createForSpecializedDecl(SourceLoc Loc, TypeDecl *D, ArrayRef args, SourceRange angleLocs); @@ -1026,10 +1028,10 @@ class TypeExpr : public Expr { /// constructor' entry point referenced by a 'new' expression. class OtherConstructorDeclRefExpr : public Expr { ConcreteDeclRef Ctor; - SourceLoc Loc; + DeclNameLoc Loc; public: - OtherConstructorDeclRefExpr(ConcreteDeclRef Ctor, SourceLoc Loc, + OtherConstructorDeclRefExpr(ConcreteDeclRef Ctor, DeclNameLoc Loc, bool Implicit, Type Ty = {}) : Expr(ExprKind::OtherConstructorDeclRef, Implicit, Ty), Ctor(Ctor), Loc(Loc) @@ -1038,42 +1040,15 @@ class OtherConstructorDeclRefExpr : public Expr { ConstructorDecl *getDecl() const; ConcreteDeclRef getDeclRef() const { return Ctor; } - SourceLoc getConstructorLoc() const { return Loc; } - SourceRange getSourceRange() const { return Loc; } + SourceLoc getLoc() const { return Loc.getBaseNameLoc(); } + DeclNameLoc getConstructorLoc() const { return Loc; } + SourceRange getSourceRange() const { return Loc.getSourceRange(); } static bool classof(const Expr *E) { return E->getKind() == ExprKind::OtherConstructorDeclRef; } }; -/// An unresolved reference to a constructor member of a value. Resolves to a -/// DotSyntaxCall involving the value and the resolved constructor. -class UnresolvedConstructorExpr : public Expr { - Expr *SubExpr; - SourceLoc DotLoc; - SourceLoc ConstructorLoc; -public: - UnresolvedConstructorExpr(Expr *SubExpr, SourceLoc DotLoc, - SourceLoc ConstructorLoc, bool Implicit) - : Expr(ExprKind::UnresolvedConstructor, Implicit), - SubExpr(SubExpr), DotLoc(DotLoc), ConstructorLoc(ConstructorLoc) - {} - - Expr *getSubExpr() const { return SubExpr; } - void setSubExpr(Expr *e) { SubExpr = e; } - - SourceLoc getLoc() const { return ConstructorLoc; } - SourceLoc getConstructorLoc() const { return ConstructorLoc; } - SourceLoc getDotLoc() const { return DotLoc; } - - SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); } - SourceLoc getEndLoc() const { return ConstructorLoc; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UnresolvedConstructor; - } -}; - /// OverloadSetRefExpr - A reference to an overloaded set of values with a /// single name. /// @@ -1108,18 +1083,19 @@ class OverloadSetRefExpr : public Expr { /// OverloadedDeclRefExpr - A reference to an overloaded name that should /// eventually be resolved (by overload resolution) to a value reference. class OverloadedDeclRefExpr : public OverloadSetRefExpr { - SourceLoc Loc; + DeclNameLoc Loc; bool IsSpecialized = false; bool IsPotentiallyDelayedGlobalOperator = false; public: - OverloadedDeclRefExpr(ArrayRef Decls, SourceLoc Loc, + OverloadedDeclRefExpr(ArrayRef Decls, DeclNameLoc Loc, bool Implicit, Type Ty = Type()) : OverloadSetRefExpr(ExprKind::OverloadedDeclRef, Decls, Implicit, Ty), Loc(Loc) { } - SourceLoc getLoc() const { return Loc; } - SourceRange getSourceRange() const { return Loc; } + DeclNameLoc getNameLoc() const { return Loc; } + SourceLoc getLoc() const { return Loc.getBaseNameLoc(); } + SourceRange getSourceRange() const { return Loc.getSourceRange(); } void setSpecialized(bool specialized) { IsSpecialized = specialized; } @@ -1145,11 +1121,11 @@ class OverloadedDeclRefExpr : public OverloadSetRefExpr { class OverloadedMemberRefExpr : public OverloadSetRefExpr { Expr *SubExpr; SourceLoc DotLoc; - SourceLoc MemberLoc; + DeclNameLoc MemberLoc; public: OverloadedMemberRefExpr(Expr *SubExpr, SourceLoc DotLoc, - ArrayRef Decls, SourceLoc MemberLoc, + ArrayRef Decls, DeclNameLoc MemberLoc, bool Implicit, Type Ty = Type(), AccessSemantics semantics = AccessSemantics::Ordinary) : OverloadSetRefExpr(ExprKind::OverloadedMemberRef, Decls, Implicit, Ty), @@ -1158,15 +1134,16 @@ class OverloadedMemberRefExpr : public OverloadSetRefExpr { } SourceLoc getDotLoc() const { return DotLoc; } - SourceLoc getMemberLoc() const { return MemberLoc; } + DeclNameLoc getMemberLoc() const { return MemberLoc; } Expr *getBase() const { return SubExpr; } void setBase(Expr *E) { SubExpr = E; } - SourceLoc getLoc() const { return MemberLoc; } + SourceLoc getLoc() const { return MemberLoc.getBaseNameLoc(); } SourceLoc getStartLoc() const { - return DotLoc.isValid()? SubExpr->getStartLoc() : MemberLoc; + return DotLoc.isValid()? SubExpr->getStartLoc() + : MemberLoc.getBaseNameLoc(); } - SourceLoc getEndLoc() const { return MemberLoc; } + SourceLoc getEndLoc() const { return MemberLoc.getSourceRange().End; } AccessSemantics getAccessSemantics() const { return AccessSemantics(OverloadedMemberRefExprBits.Semantics); @@ -1176,26 +1153,26 @@ class OverloadedMemberRefExpr : public OverloadSetRefExpr { return E->getKind() == ExprKind::OverloadedMemberRef; } }; - + /// UnresolvedDeclRefExpr - This represents use of an undeclared identifier, /// which may ultimately be a use of something that hasn't been defined yet, it /// may be a use of something that got imported (which will be resolved during /// sema), or may just be a use of an unknown identifier. /// class UnresolvedDeclRefExpr : public Expr { - Identifier Name; - SourceLoc Loc; + DeclName Name; + DeclNameLoc Loc; DeclRefKind RefKind; bool IsSpecialized = false; public: - UnresolvedDeclRefExpr(Identifier name, DeclRefKind refKind, SourceLoc loc) + UnresolvedDeclRefExpr(DeclName name, DeclRefKind refKind, DeclNameLoc loc) : Expr(ExprKind::UnresolvedDeclRef, /*Implicit=*/loc.isInvalid()), Name(name), Loc(loc), RefKind(refKind) { } - bool hasName() const { return !Name.empty(); } - Identifier getName() const { return Name; } + bool hasName() const { return static_cast(Name); } + DeclName getName() const { return Name; } DeclRefKind getRefKind() const { return RefKind; } void setSpecialized(bool specialized) { IsSpecialized = specialized; } @@ -1204,7 +1181,9 @@ class UnresolvedDeclRefExpr : public Expr { /// specialized by <...>. bool isSpecialized() const { return IsSpecialized; } - SourceRange getSourceRange() const { return Loc; } + DeclNameLoc getNameLoc() const { return Loc; } + + SourceRange getSourceRange() const { return Loc.getSourceRange(); } static bool classof(const Expr *E) { return E->getKind() == ExprKind::UnresolvedDeclRef; @@ -1221,15 +1200,15 @@ class MemberRefExpr : public Expr { Expr *Base; ConcreteDeclRef Member; SourceLoc DotLoc; - SourceRange NameRange; + DeclNameLoc NameLoc; public: MemberRefExpr(Expr *base, SourceLoc dotLoc, ConcreteDeclRef member, - SourceRange nameRange, bool Implicit, + DeclNameLoc loc, bool Implicit, AccessSemantics semantics = AccessSemantics::Ordinary); Expr *getBase() const { return Base; } ConcreteDeclRef getMember() const { return Member; } - SourceLoc getNameLoc() const { return NameRange.Start; } + DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getDotLoc() const { return DotLoc; } void setBase(Expr *E) { Base = E; } @@ -1248,17 +1227,17 @@ class MemberRefExpr : public Expr { /// property. void setIsSuper(bool isSuper) { MemberRefExprBits.IsSuper = isSuper; } - SourceLoc getLoc() const { return NameRange.Start; } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } SourceLoc getStartLoc() const { SourceLoc BaseStartLoc = Base->getStartLoc(); - if (BaseStartLoc.isInvalid() || NameRange.End.isInvalid()) { - return NameRange.Start; + if (BaseStartLoc.isInvalid() || NameLoc.isInvalid()) { + return NameLoc.getBaseNameLoc(); } else { return BaseStartLoc; } } SourceLoc getEndLoc() const { - return NameRange.End; + return NameLoc.getSourceRange().End; } static bool classof(const Expr *E) { @@ -1299,12 +1278,12 @@ class DynamicMemberRefExpr : public DynamicLookupExpr { Expr *Base; ConcreteDeclRef Member; SourceLoc DotLoc; - SourceLoc NameLoc; + DeclNameLoc NameLoc; public: DynamicMemberRefExpr(Expr *base, SourceLoc dotLoc, ConcreteDeclRef member, - SourceLoc nameLoc) + DeclNameLoc nameLoc) : DynamicLookupExpr(ExprKind::DynamicMemberRef), Base(base), Member(member), DotLoc(dotLoc), NameLoc(nameLoc) { } @@ -1319,22 +1298,22 @@ class DynamicMemberRefExpr : public DynamicLookupExpr { ConcreteDeclRef getMember() const { return Member; } /// Retrieve the location of the member name. - SourceLoc getNameLoc() const { return NameLoc; } + DeclNameLoc getNameLoc() const { return NameLoc; } /// Retrieve the location of the '.'. SourceLoc getDotLoc() const { return DotLoc; } - SourceLoc getLoc() const { return NameLoc; } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } SourceLoc getStartLoc() const { SourceLoc BaseStartLoc = Base->getStartLoc(); if (BaseStartLoc.isInvalid() || NameLoc.isInvalid()) { - return NameLoc; + return NameLoc.getBaseNameLoc(); } else { return BaseStartLoc; } } - SourceLoc getEndLoc() const { return NameLoc; } + SourceLoc getEndLoc() const { return NameLoc.getSourceRange().End; } static bool classof(const Expr *E) { return E->getKind() == ExprKind::DynamicMemberRef; @@ -1401,28 +1380,28 @@ class DynamicSubscriptExpr : public DynamicLookupExpr { /// bar.foo. These always have unresolved type. class UnresolvedMemberExpr : public Expr { SourceLoc DotLoc; - SourceLoc NameLoc; - Identifier Name; + DeclNameLoc NameLoc; + DeclName Name; Expr *Argument; public: - UnresolvedMemberExpr(SourceLoc dotLoc, SourceLoc nameLoc, - Identifier name, Expr *argument) + UnresolvedMemberExpr(SourceLoc dotLoc, DeclNameLoc nameLoc, + DeclName name, Expr *argument) : Expr(ExprKind::UnresolvedMember, /*Implicit=*/false), DotLoc(dotLoc), NameLoc(nameLoc), Name(name), Argument(argument) { } - Identifier getName() const { return Name; } - SourceLoc getNameLoc() const { return NameLoc; } + DeclName getName() const { return Name; } + DeclNameLoc getNameLoc() const { return NameLoc; } SourceLoc getDotLoc() const { return DotLoc; } Expr *getArgument() const { return Argument; } void setArgument(Expr *argument) { Argument = argument; } - SourceLoc getLoc() const { return NameLoc; } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } SourceLoc getStartLoc() const { return DotLoc; } SourceLoc getEndLoc() const { - return (Argument ? Argument->getEndLoc() : NameLoc); + return (Argument ? Argument->getEndLoc() : NameLoc.getSourceRange().End); } static bool classof(const Expr *E) { @@ -1898,91 +1877,35 @@ class SubscriptExpr : public Expr { class UnresolvedDotExpr : public Expr { Expr *SubExpr; SourceLoc DotLoc; - SourceLoc NameLoc; - Identifier Name; + DeclNameLoc NameLoc; + DeclName Name; public: - UnresolvedDotExpr(Expr *subexpr, SourceLoc dotloc, Identifier name, - SourceLoc nameloc, bool Implicit) + UnresolvedDotExpr(Expr *subexpr, SourceLoc dotloc, DeclName name, + DeclNameLoc nameloc, bool Implicit) : Expr(ExprKind::UnresolvedDot, Implicit), SubExpr(subexpr), DotLoc(dotloc), NameLoc(nameloc), Name(name) {} - SourceLoc getLoc() const { return NameLoc; } + SourceLoc getLoc() const { return NameLoc.getBaseNameLoc(); } SourceLoc getStartLoc() const { - return (DotLoc.isInvalid() ? NameLoc : SubExpr->getStartLoc()); + return (DotLoc.isInvalid() ? NameLoc.getSourceRange().End + : SubExpr->getStartLoc()); + } + SourceLoc getEndLoc() const { + return NameLoc.getSourceRange().End ; } - SourceLoc getEndLoc() const { return NameLoc; } SourceLoc getDotLoc() const { return DotLoc; } Expr *getBase() const { return SubExpr; } void setBase(Expr *e) { SubExpr = e; } - Identifier getName() const { return Name; } - SourceLoc getNameLoc() const { return NameLoc; } + DeclName getName() const { return Name; } + DeclNameLoc getNameLoc() const { return NameLoc; } static bool classof(const Expr *E) { return E->getKind() == ExprKind::UnresolvedDot; } }; - -/// A selector-style member access (foo.bar:bas:) on an expression with -/// unresolved type. -class UnresolvedSelectorExpr : public Expr { -public: - // A selector component. - struct ComponentLoc { - SourceLoc NameLoc; - SourceLoc ColonLoc; - }; - -private: - Expr *SubExpr; - SourceLoc DotLoc; - DeclName Name; - - MutableArrayRef getComponentsBuf() { - return {reinterpret_cast(this+1), - Name.getArgumentNames().size() + 1}; - } - - UnresolvedSelectorExpr(Expr *subExpr, SourceLoc dotLoc, - DeclName name, - ArrayRef components); - -public: - static UnresolvedSelectorExpr *create(ASTContext &C, - Expr *subExpr, - SourceLoc dotLoc, - DeclName name, - ArrayRef components); - - ArrayRef getComponentLocs() const { - return {reinterpret_cast(this+1), - Name.getArgumentNames().size() + 1}; - } - - SourceLoc getLoc() const { - return getComponentLocs().front().NameLoc; - } - - SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); } - SourceLoc getEndLoc() const { return getComponentLocs().back().ColonLoc; } - - SourceLoc getDotLoc() const { return DotLoc; } - Expr *getBase() const { return SubExpr; } - void setBase(Expr *e) { SubExpr = e; } - - SourceRange getNameRange() const { - return {getComponentLocs().front().NameLoc, - getComponentLocs().back().ColonLoc}; - } - - DeclName getName() const { return Name; } - - static bool classof(const Expr *E) { - return E->getKind() == ExprKind::UnresolvedSelector; - } -}; /// TupleElementExpr - Refer to an element of a tuple, /// e.g. "(1,field:2).field". @@ -2561,11 +2484,11 @@ class CollectionUpcastConversionExpr : public ImplicitConversionExpr { /// "Appropriate kind" means e.g. a concrete/existential metatype if the /// result is an existential metatype. class ErasureExpr : public ImplicitConversionExpr { - ArrayRef Conformances; + ArrayRef Conformances; public: ErasureExpr(Expr *subExpr, Type type, - ArrayRef conformances) + ArrayRef conformances) : ImplicitConversionExpr(ExprKind::Erasure, subExpr, type), Conformances(conformances) {} @@ -2579,7 +2502,7 @@ class ErasureExpr : public ImplicitConversionExpr { /// to the corresponding protocol is trivial (because the source /// type is either an archetype or an existential type that conforms to /// that corresponding protocol). - ArrayRef getConformances() const { + ArrayRef getConformances() const { return Conformances; } @@ -2775,14 +2698,14 @@ class AbstractClosureExpr : public Expr, public DeclContext { CaptureInfo Captures; /// \brief The set of parameters. - Pattern *ParamPattern; + ParameterList *parameterList; public: AbstractClosureExpr(ExprKind Kind, Type FnType, bool Implicit, unsigned Discriminator, DeclContext *Parent) : Expr(Kind, Implicit, FnType), DeclContext(DeclContextKind::AbstractClosureExpr, Parent), - ParamPattern(nullptr) { + parameterList(nullptr) { AbstractClosureExprBits.Discriminator = Discriminator; } @@ -2790,9 +2713,9 @@ class AbstractClosureExpr : public Expr, public DeclContext { const CaptureInfo &getCaptureInfo() const { return Captures; } /// \brief Retrieve the parameters of this closure. - Pattern *getParams() { return ParamPattern; } - const Pattern *getParams() const { return ParamPattern; } - void setParams(Pattern *P); + ParameterList *getParameters() { return parameterList; } + const ParameterList *getParameters() const { return parameterList; } + void setParameterList(ParameterList *P); // Expose this to users. using DeclContext::setParent; @@ -2825,11 +2748,12 @@ class AbstractClosureExpr : public Expr, public DeclContext { decltype(AbstractClosureExprBits)::InvalidDiscriminator }; - ArrayRef getParamPatterns() { - return ParamPattern ? ParamPattern : ArrayRef (); + ArrayRef getParameterLists() { + return parameterList ? parameterList : ArrayRef(); } - ArrayRef getParamPatterns() const { - return ParamPattern ? ParamPattern : ArrayRef (); + + ArrayRef getParameterLists() const { + return parameterList ? parameterList : ArrayRef(); } unsigned getNaturalArgumentCount() const { return 1; } @@ -2921,7 +2845,7 @@ class ClosureExpr : public AbstractClosureExpr { llvm::PointerIntPair Body; public: - ClosureExpr(Pattern *params, SourceLoc throwsLoc, SourceLoc arrowLoc, + ClosureExpr(ParameterList *params, SourceLoc throwsLoc, SourceLoc arrowLoc, SourceLoc inLoc, TypeLoc explicitResultType, unsigned discriminator, DeclContext *parent) : AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false, @@ -2929,7 +2853,7 @@ class ClosureExpr : public AbstractClosureExpr { ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc), ExplicitResultType(explicitResultType), Body(nullptr) { - setParams(params); + setParameterList(params); ClosureExprBits.HasAnonymousClosureVars = false; ClosureExprBits.IsVoidConversionClosure = false; } @@ -3048,7 +2972,7 @@ class ClosureExpr : public AbstractClosureExpr { /// \brief This is a closure of the contained subexpression that is formed -/// when an scalar expression is converted to @autoclosure function type. +/// when a scalar expression is converted to @autoclosure function type. /// For example: /// \code /// @autoclosure var x : () -> Int = 4 @@ -3094,7 +3018,7 @@ class AutoClosureExpr : public AbstractClosureExpr { /// DynamicTypeExpr - "base.dynamicType" - Produces a metatype value. /// -/// The metatype value can comes from a evaluating an expression and then +/// The metatype value can comes from evaluating an expression and then /// getting its metatype. class DynamicTypeExpr : public Expr { Expr *Base; @@ -3771,6 +3695,44 @@ class EditorPlaceholderExpr : public Expr { void setSemanticExpr(Expr *SE) { SemanticExpr = SE; } }; +/// Produces the Objective-C selector of the referenced method. +/// +/// \code +/// #selector(UIView.insertSubview(_:aboveSubview:)) +/// \endcode +class ObjCSelectorExpr : public Expr { + SourceLoc KeywordLoc; + SourceLoc LParenLoc; + Expr *SubExpr; + SourceLoc RParenLoc; + AbstractFunctionDecl *Method = nullptr; + +public: + ObjCSelectorExpr(SourceLoc keywordLoc, SourceLoc lParenLoc, + Expr *subExpr, SourceLoc rParenLoc) + : Expr(ExprKind::ObjCSelector, /*Implicit=*/false), + KeywordLoc(keywordLoc), LParenLoc(lParenLoc), SubExpr(subExpr), + RParenLoc(rParenLoc) { } + + Expr *getSubExpr() const { return SubExpr; } + void setSubExpr(Expr *expr) { SubExpr = expr; } + + /// Retrieve the Objective-C method to which this expression refers. + AbstractFunctionDecl *getMethod() const { return Method; } + + /// Set the Objective-C method to which this expression refers. + void setMethod(AbstractFunctionDecl *method) { Method = method; } + + SourceLoc getLoc() const { return KeywordLoc; } + SourceRange getSourceRange() const { + return SourceRange(KeywordLoc, RParenLoc); + } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::ObjCSelector; + } +}; + #undef SWIFT_FORWARD_SOURCE_LOCS_TO } // end namespace swift diff --git a/include/swift/AST/ExprHandle.h b/include/swift/AST/ExprHandle.h index 3b3a1d7aa3aad..6c4b8930d25a6 100644 --- a/include/swift/AST/ExprHandle.h +++ b/include/swift/AST/ExprHandle.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,7 +26,7 @@ namespace swift { /// ExprHandle - Provides an indirection for expressions, so both a type and a /// pattern can point at the same expression during type-checking. -class ExprHandle { +class alignas(8) ExprHandle { /// \brief The expression along with a bit saying whether this expression /// was already type-checked (or not). llvm::PointerIntPair EAndChecked; diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index a76815e53a44b..66387b964003b 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -64,7 +64,6 @@ EXPR(DeclRef, Expr) EXPR(SuperRef, Expr) EXPR(Type, Expr) EXPR(OtherConstructorDeclRef, Expr) -UNCHECKED_EXPR(UnresolvedConstructor, Expr) EXPR(DotSyntaxBaseIgnored, Expr) ABSTRACT_EXPR(OverloadSetRef, Expr) UNCHECKED_EXPR(OverloadedDeclRef, OverloadSetRefExpr) @@ -79,7 +78,6 @@ ABSTRACT_EXPR(DynamicLookup, Expr) UNCHECKED_EXPR(UnresolvedSpecialize, Expr) UNCHECKED_EXPR(UnresolvedMember, Expr) UNCHECKED_EXPR(UnresolvedDot, Expr) -UNCHECKED_EXPR(UnresolvedSelector, Expr) UNCHECKED_EXPR(Sequence, Expr) ABSTRACT_EXPR(Identity, Expr) EXPR(Paren, IdentityExpr) @@ -157,6 +155,7 @@ EXPR(DefaultValue, Expr) EXPR(CodeCompletion, Expr) UNCHECKED_EXPR(UnresolvedPattern, Expr) EXPR(EditorPlaceholder, Expr) +EXPR(ObjCSelector, Expr) #undef EXPR_RANGE #undef UNCHECKED_EXPR diff --git a/include/swift/AST/ForeignErrorConvention.h b/include/swift/AST/ForeignErrorConvention.h index f50ad66b78015..c9023bc4f0137 100644 --- a/include/swift/AST/ForeignErrorConvention.h +++ b/include/swift/AST/ForeignErrorConvention.h @@ -1,8 +1,8 @@ -//===--- ForeignErrorConvention.h - Error conventions ----------*- C++ -*-===// +//===--- ForeignErrorConvention.h - Error conventions -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index 4ba3fbd3a3a9f..6505f9c70de26 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -101,7 +101,7 @@ class GenericSignature : public llvm::FoldingSetNode { NumGenericParams }; } - /// Retrieve a mutable verison of the requirements. + /// Retrieve a mutable version of the requirements. MutableArrayRef getRequirementsBuffer() { void *genericParams = getGenericParamsBuffer().end(); return { reinterpret_cast(genericParams), diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 2a8b536bcb861..2a6691ad2a9fb 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -126,8 +126,15 @@ class IRGenOptions { /// Whether we should embed the bitcode file. IRGenEmbedMode EmbedMode : 2; - /// For resilient access to super's members for testing. - unsigned ForceResilientSuperDispatch: 1; + /// Add names to LLVM values. + unsigned HasValueNamesSetting : 1; + unsigned ValueNames : 1; + + /// Only strip the field names section from nominal type field metadata. + unsigned StripFieldNames : 1; + + /// Strip all nominal type field metadata. + unsigned StripFieldMetadata : 1; /// List of backend command-line options for -embed-bitcode. std::vector CmdArgs; @@ -139,9 +146,10 @@ class IRGenOptions { DisableFPElim(true), Playground(false), EmitStackPromotionChecks(false), GenerateProfile(false), EmbedMode(IRGenEmbedMode::None), - ForceResilientSuperDispatch(false) + HasValueNamesSetting(false), ValueNames(false), + StripFieldNames(false), StripFieldMetadata(false) {} - + /// Gets the name of the specified output filename. /// If multiple files are specified, the last one is returned. StringRef getSingleOutputFilename() const { diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 7cdc01d263ed1..c6a7631e27555 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,12 +18,8 @@ #define SWIFT_AST_IDENTIFIER_H #include "swift/Basic/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/StringRef.h" -#include namespace llvm { class raw_ostream; @@ -31,6 +27,7 @@ namespace llvm { namespace swift { class ASTContext; + class ParameterList; /// DeclRefKind - The kind of reference to an identifier. enum class DeclRefKind { @@ -109,9 +106,6 @@ class Identifier { /// isOperatorContinuationCodePoint - Return true if the specified code point /// is a valid operator code point. static bool isOperatorContinuationCodePoint(uint32_t C) { - // '.' is a special case. It can only appear in '..'. - if (C == '.') - return false; if (isOperatorStartCodePoint(C)) return true; @@ -124,8 +118,12 @@ class Identifier { || (C >= 0xE0100 && C <= 0xE01EF); } + static bool isEditorPlaceholder(StringRef name) { + return name.startswith("<#"); + } + bool isEditorPlaceholder() const { - return !empty() && Pointer[0] == '<' && Pointer[1] == '#'; + return !empty() && isEditorPlaceholder(str()); } void *getAsOpaquePointer() const { return (void *)Pointer; } @@ -246,6 +244,9 @@ class DeclName { : SimpleOrCompound(decltype(SimpleOrCompound)::getFromOpaqueValue(Opaque)) {} + void initialize(ASTContext &C, Identifier baseName, + ArrayRef argumentNames); + public: /// Build a null name. DeclName() : SimpleOrCompound(IdentifierAndCompound()) {} @@ -256,9 +257,15 @@ class DeclName { /// Build a compound value name given a base name and a set of argument names. DeclName(ASTContext &C, Identifier baseName, - ArrayRef argumentNames); + ArrayRef argumentNames) { + initialize(C, baseName, argumentNames); + } + + /// Build a compound value name given a base name and a set of argument names + /// extracted from a parameter list. + DeclName(ASTContext &C, Identifier baseName, ParameterList *paramList); - /// Retrive the 'base' name, i.e., the name that follows the introducer, + /// Retrieve the 'base' name, i.e., the name that follows the introducer, /// such as the 'foo' in 'func foo(x:Int, y:Int)' or the 'bar' in /// 'var bar: Int'. Identifier getBaseName() const { @@ -374,6 +381,14 @@ class DeclName { void *getOpaqueValue() const { return SimpleOrCompound.getOpaqueValue(); } static DeclName getFromOpaqueValue(void *p) { return DeclName(p); } + /// Print the representation of this declaration name to the given + /// stream. + /// + /// \param skipEmptyArgumentNames When true, don't print the argument labels + /// if they are all empty. + llvm::raw_ostream &print(llvm::raw_ostream &os, + bool skipEmptyArgumentNames = false) const; + /// Print a "pretty" representation of this declaration name to the given /// stream. /// diff --git a/include/swift/AST/Initializer.h b/include/swift/AST/Initializer.h index 29039412b36b6..f757c9525743f 100644 --- a/include/swift/AST/Initializer.h +++ b/include/swift/AST/Initializer.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/KnownDecls.def b/include/swift/AST/KnownDecls.def index a8483d202d7ce..524d0f1478ba4 100644 --- a/include/swift/AST/KnownDecls.def +++ b/include/swift/AST/KnownDecls.def @@ -1,8 +1,8 @@ -//===-- KnownDecl.def - Compiler declaration metaprogramming ----*- C++ -*-===// +//===--- KnownDecls.def - Compiler declaration metaprogramming --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/KnownFoundationEntities.def b/include/swift/AST/KnownFoundationEntities.def new file mode 100644 index 0000000000000..c5f72d04fae98 --- /dev/null +++ b/include/swift/AST/KnownFoundationEntities.def @@ -0,0 +1,38 @@ +//===--- KnownFoundationEntities.def - Objective-C Foundation ---*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines macros used for macro-metaprogramming with +// compiler-known entities in the Objective-C Foundation module (and +// the ObjectiveC module it depends on). +// +//===----------------------------------------------------------------------===// +#ifndef FOUNDATION_ENTITY +# error define FOUNDATION_ENTITY(Name) +#endif + +FOUNDATION_ENTITY(NSArray) +FOUNDATION_ENTITY(NSCopying) +FOUNDATION_ENTITY(NSDictionary) +FOUNDATION_ENTITY(NSError) +FOUNDATION_ENTITY(NSErrorPointer) +FOUNDATION_ENTITY(NSInteger) +FOUNDATION_ENTITY(NSNumber) +FOUNDATION_ENTITY(NSObject) +FOUNDATION_ENTITY(NSRange) +FOUNDATION_ENTITY(NSSet) +FOUNDATION_ENTITY(NSString) +FOUNDATION_ENTITY(NSStringEncoding) +FOUNDATION_ENTITY(NSUInteger) +FOUNDATION_ENTITY(NSURL) +FOUNDATION_ENTITY(NSZone) + +#undef FOUNDATION_ENTITY diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 341249c1d6f88..419c3582016ef 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -24,6 +24,7 @@ IDENTIFIER(alloc) IDENTIFIER(allocWithZone) +IDENTIFIER(allZeros) IDENTIFIER(atIndexedSubscript) IDENTIFIER_(bridgeToObjectiveC) IDENTIFIER_WITH_NAME(code_, "_code") @@ -42,9 +43,7 @@ IDENTIFIER(hashValue) IDENTIFIER(init) IDENTIFIER(load) IDENTIFIER(next) -IDENTIFIER(NSError) IDENTIFIER_(NSErrorDomain) -IDENTIFIER(NSObject) IDENTIFIER(objectAtIndexedSubscript) IDENTIFIER(objectForKeyedSubscript) IDENTIFIER(ObjectiveC) @@ -52,6 +51,7 @@ IDENTIFIER_(OptionalNilComparisonType) IDENTIFIER(Protocol) IDENTIFIER(rawValue) IDENTIFIER(RawValue) +IDENTIFIER(Selector) IDENTIFIER(self) IDENTIFIER(Self) IDENTIFIER(setObject) diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index 1669808d3bd86..615f9d6bd4c65 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -1,8 +1,8 @@ -//===-- KnownProtocols.def - Compiler protocol metaprogramming --*- C++ -*-===// +//===--- KnownProtocols.def - Compiler protocol metaprogramming -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/KnownProtocols.h b/include/swift/AST/KnownProtocols.h index a2554fcebf1df..18cd1cb85b0a7 100644 --- a/include/swift/AST/KnownProtocols.h +++ b/include/swift/AST/KnownProtocols.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index 3320491f108fa..42ac0d8cc8821 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -129,12 +129,8 @@ class alignas(void*) LazyMemberLoader { /// Populates the given vector with all member decls for \p D. /// /// The implementation should add the members to D. - /// - /// \param[out] hasMissingRequiredMembers If present, set to true if any - /// members failed to import and were non-optional protocol requirements. virtual void - loadAllMembers(Decl *D, uint64_t contextData, - bool *hasMissingRequiredMembers = nullptr) { + loadAllMembers(Decl *D, uint64_t contextData) { llvm_unreachable("unimplemented"); } diff --git a/include/swift/AST/LinkLibrary.h b/include/swift/AST/LinkLibrary.h index df359296a9441..62724a8dd3f1c 100644 --- a/include/swift/AST/LinkLibrary.h +++ b/include/swift/AST/LinkLibrary.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Mangle.h b/include/swift/AST/Mangle.h index 35e01c711bb72..ad2868d83fa3a 100644 --- a/include/swift/AST/Mangle.h +++ b/include/swift/AST/Mangle.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,7 +17,6 @@ #include "swift/AST/Types.h" #include "swift/AST/Decl.h" #include "swift/AST/GenericSignature.h" -#include "swift/AST/ResilienceExpansion.h" namespace swift { @@ -34,17 +33,19 @@ enum class OperatorFixity { Postfix }; -/// Defined in include/swift/SIL/Mangle.h -class SpecializationManglerBase; -/// A class for mangling declarations. +/// A class for mangling declarations. The Mangler accumulates name fragments +/// with the mangleXXX methods, and the final string is constructed with the +/// `finalize` method, after which the Mangler should not be used. class Mangler { struct ArchetypeInfo { unsigned Depth; unsigned Index; }; - raw_ostream &Buffer; + llvm::SmallVector Storage; + llvm::raw_svector_ostream Buffer; + llvm::DenseMap Substitutions; llvm::DenseMap Archetypes; CanGenericSignature CurGenericSignature; @@ -56,8 +57,6 @@ class Mangler { /// If enabled, non-ASCII names are encoded in modified Punycode. bool UsePunycode; - friend class SpecializationManglerBase; - public: enum BindGenerics : unsigned { /// We don't intend to mangle any sort of type within this context @@ -88,49 +87,48 @@ class Mangler { ~ContextStack() { M.ArchetypesDepth = OldDepth; } }; + /// Finish the mangling of the symbol and return the mangled name. + std::string finalize(); + + /// Finish the mangling of the symbol and write the mangled name into + /// \p stream. + void finalize(llvm::raw_ostream &stream); + void setModuleContext(ModuleDecl *M) { Mod = M; } /// \param DWARFMangling - use the 'Qq' mangling format for /// archetypes and the 'a' mangling for alias types. /// \param usePunycode - emit modified Punycode instead of UTF-8. - Mangler(raw_ostream &buffer, bool DWARFMangling = false, + Mangler(bool DWARFMangling = false, bool usePunycode = true) - : Buffer(buffer), DWARFMangling(DWARFMangling), UsePunycode(usePunycode) {} + : Buffer(Storage), DWARFMangling(DWARFMangling), UsePunycode(usePunycode) {} void mangleContextOf(const ValueDecl *decl, BindGenerics shouldBind); void mangleContext(const DeclContext *ctx, BindGenerics shouldBind); void mangleModule(const ModuleDecl *module); void mangleDeclName(const ValueDecl *decl); - void mangleDeclType(const ValueDecl *decl, ResilienceExpansion expansion, - unsigned uncurryingLevel); + void mangleDeclType(const ValueDecl *decl, unsigned uncurryingLevel); - void mangleEntity(const ValueDecl *decl, ResilienceExpansion expansion, - unsigned uncurryingLevel); + void mangleEntity(const ValueDecl *decl, unsigned uncurryingLevel); void mangleConstructorEntity(const ConstructorDecl *ctor, bool isAllocating, - ResilienceExpansion kind, unsigned uncurryingLevel); void mangleDestructorEntity(const DestructorDecl *decl, bool isDeallocating); void mangleIVarInitDestroyEntity(const ClassDecl *decl, bool isDestroyer); void mangleAccessorEntity(AccessorKind kind, AddressorKind addressorKind, - const AbstractStorageDecl *decl, - ResilienceExpansion expansion); + const AbstractStorageDecl *decl); void mangleAddressorEntity(const ValueDecl *decl); void mangleGlobalGetterEntity(ValueDecl *decl); void mangleDefaultArgumentEntity(const DeclContext *ctx, unsigned index); void mangleInitializerEntity(const VarDecl *var); void mangleClosureEntity(const SerializedAbstractClosureExpr *closure, - ResilienceExpansion explosion, unsigned uncurryingLevel); void mangleClosureEntity(const AbstractClosureExpr *closure, - ResilienceExpansion explosion, unsigned uncurryingLevel); void mangleNominalType(const NominalTypeDecl *decl, - ResilienceExpansion expansion, BindGenerics shouldBind, CanGenericSignature extGenericSig = nullptr, const GenericParamList *extGenericParams = nullptr); void mangleProtocolDecl(const ProtocolDecl *protocol); - void mangleType(Type type, ResilienceExpansion expansion, - unsigned uncurryingLevel); + void mangleType(Type type, unsigned uncurryingLevel); void mangleDirectness(bool isIndirect); void mangleProtocolName(const ProtocolDecl *protocol); void mangleProtocolConformance(const ProtocolConformance *conformance); @@ -140,14 +138,30 @@ class Mangler { void mangleDeclTypeForDebugger(const ValueDecl *decl); void mangleTypeForDebugger(Type decl, const DeclContext *DC); - void mangleGenericSignature(const GenericSignature *sig, - ResilienceExpansion expansion); + void mangleGenericSignature(const GenericSignature *sig); void mangleFieldOffsetFull(const ValueDecl *decl, bool isIndirect); void mangleTypeMetadataFull(CanType ty, bool isPattern); void mangleTypeFullMetadataFull(CanType ty); void mangleGlobalVariableFull(const VarDecl *decl); - + + /// Adds the string \p S into the mangled name. + void append(StringRef S); + + /// Adds the char \p C into the mangled name. + void append(char C); + + /// Add the already mangled symbol \p Name as an identifier. (using the + /// length prefix). + void mangleIdentifierSymbol(StringRef Name); + + /// Add the already mangled symbol \p Name. This gives the mangler the + /// opportunity to decode \p Name before adding it to the mangled name. + void appendSymbol(StringRef Name); + + /// Mangle the integer \p Nat into the name. + void mangleNatural(const APInt &Nat); + /// Mangles globalinit_token and globalinit_func, which are used to /// initialize global variables. /// \param decl The global variable or one of the global variables of a @@ -162,8 +176,7 @@ class Mangler { bool isOperator=false); void resetArchetypesDepth() { ArchetypesDepth = 0; } private: - void mangleFunctionType(AnyFunctionType *fn, ResilienceExpansion expansion, - unsigned uncurryingLevel); + void mangleFunctionType(AnyFunctionType *fn, unsigned uncurryingLevel); void mangleProtocolList(ArrayRef protocols); void mangleProtocolList(ArrayRef protocols); void mangleIdentifier(Identifier ident, @@ -181,13 +194,12 @@ class Mangler { assert(DWARFMangling && "sugared types are only legal when mangling for the debugger"); auto *BlandTy = cast(type.getPointer())->getSinglyDesugaredType(); - mangleType(BlandTy, ResilienceExpansion::Minimal, 0); + mangleType(BlandTy, 0); } void mangleGenericSignatureParts(ArrayRef params, unsigned initialParamDepth, - ArrayRef requirements, - ResilienceExpansion expansion); + ArrayRef requirements); Type getDeclTypeForMangling(const ValueDecl *decl, ArrayRef &genericParams, unsigned &initialParamIndex, @@ -197,8 +209,7 @@ class Mangler { void mangleGenericParamIndex(GenericTypeParamType *paramTy); void mangleAssociatedTypeName(DependentMemberType *dmt, bool canAbbreviate); - void mangleConstrainedType(CanType type, - ResilienceExpansion expansion); + void mangleConstrainedType(CanType type); CanGenericSignature getCanonicalSignatureOrNull(GenericSignature *sig, ModuleDecl &M); }; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 5069e1e4cb08a..d7a80db592f7c 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -267,13 +267,14 @@ class ModuleDecl : public TypeDecl, public DeclContext { /// \see EntryPointInfoTy EntryPointInfoTy EntryPointInfo; - enum class Flags { - TestingEnabled = 1 << 0, - FailedToLoad = 1 << 1 - }; + struct { + unsigned TestingEnabled : 1; + unsigned FailedToLoad : 1; + unsigned ResilienceEnabled : 1; + } Flags; /// The magic __dso_handle variable. - llvm::PointerIntPair> DSOHandleAndFlags; + VarDecl *DSOHandle; ModuleDecl(Identifier name, ASTContext &ctx); @@ -315,18 +316,28 @@ class ModuleDecl : public TypeDecl, public DeclContext { /// Returns true if this module was or is being compiled for testing. bool isTestingEnabled() const { - return DSOHandleAndFlags.getInt().contains(Flags::TestingEnabled); + return Flags.TestingEnabled; } void setTestingEnabled(bool enabled = true) { - DSOHandleAndFlags.setInt(DSOHandleAndFlags.getInt()|Flags::TestingEnabled); + Flags.TestingEnabled = enabled; } /// Returns true if there was an error trying to load this module. bool failedToLoad() const { - return DSOHandleAndFlags.getInt().contains(Flags::FailedToLoad); + return Flags.FailedToLoad; } void setFailedToLoad(bool failed = true) { - DSOHandleAndFlags.setInt(DSOHandleAndFlags.getInt() | Flags::FailedToLoad); + Flags.FailedToLoad = failed; + } + + /// Returns true if this module is compiled for resilience enabled, + /// meaning the module is expected to evolve without recompiling + /// clients that link against it. + bool isResilienceEnabled() const { + return Flags.ResilienceEnabled; + } + void setResilienceEnabled(bool enabled = true) { + Flags.ResilienceEnabled = enabled; } /// Look up a (possibly overloaded) value set at top-level scope @@ -409,6 +420,11 @@ class ModuleDecl : public TypeDecl, public DeclContext { DeclContext *container, DeclName name, Identifier privateDiscriminator) const; + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const; + /// \sa getImportedModules enum class ImportFilter { All, @@ -572,7 +588,7 @@ class ModuleDecl : public TypeDecl, public DeclContext { public: // Only allow allocation of Modules using the allocator in ASTContext // or by doing a placement new. - void *operator new(size_t Bytes, ASTContext &C, + void *operator new(size_t Bytes, const ASTContext &C, unsigned Alignment = alignof(ModuleDecl)); }; @@ -639,6 +655,11 @@ class FileUnit : public DeclContext { DeclName name, SmallVectorImpl &results) const {} + /// Find all Objective-C methods with the given selector. + virtual void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const = 0; + /// Returns the comment attached to the given declaration. /// /// This function is an implementation detail for comment serialization. @@ -804,6 +825,10 @@ class DerivedFileUnit final : public FileUnit { void getTopLevelDecls(SmallVectorImpl &results) const override; + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override { llvm_unreachable("no private decls in the derived file unit"); @@ -903,6 +928,11 @@ class SourceFile final : public FileUnit { /// complete, we diagnose. std::map AttrsRequiringFoundation; + /// A mapping from Objective-C selectors to the methods that have + /// those selectors. + llvm::DenseMap> + ObjCMethods; + template using OperatorMap = llvm::DenseMap>; @@ -959,6 +989,10 @@ class SourceFile final : public FileUnit { lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, SmallVectorImpl &results) const override; + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + virtual void getTopLevelDecls(SmallVectorImpl &results) const override; virtual void @@ -1120,6 +1154,11 @@ class BuiltinUnit final : public FileUnit { NLKind lookupKind, SmallVectorImpl &result) const override; + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override { llvm_unreachable("no private values in the Builtin module"); diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index ae3e62490c95f..05bf1b247fa66 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -1,8 +1,8 @@ -//===--- ModuleLoader.h - Module Loader Interface ----------- -*- C++ -*- -===// +//===--- ModuleLoader.h - Module Loader Interface ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -95,7 +95,7 @@ class ModuleLoader { virtual void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { } - /// \brief Load the methods within the given class that that produce + /// \brief Load the methods within the given class that produce /// Objective-C class or instance methods with the given selector. /// /// \param classDecl The class in which we are searching for @objc methods. @@ -109,7 +109,7 @@ class ModuleLoader { /// /// \param previousGeneration The previous generation with which this /// callback was invoked. The list of methods will already contain all of - /// the results from generations up and and including \c previousGeneration. + /// the results from generations up and including \c previousGeneration. /// /// \param methods The list of @objc methods in this class that have this /// selector and are instance/class methods as requested. This list will be diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index b1fdf59244411..97b94ab03d4c2 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -140,7 +140,7 @@ enum class DeclVisibilityKind { MemberOfOutsideNominal, /// Declaration is visible at the top level because it is declared in this - /// module or in a imported module. + /// module or in an imported module. VisibleAtTopLevel, /// Declaration was found via \c AnyObject or \c AnyObject.Type. diff --git a/include/swift/AST/Ownership.h b/include/swift/AST/Ownership.h index b329a324201d4..44b976c12d1f3 100644 --- a/include/swift/AST/Ownership.h +++ b/include/swift/AST/Ownership.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,12 +19,14 @@ #ifndef SWIFT_OWNERSHIP_H #define SWIFT_OWNERSHIP_H +#include + namespace swift { /// Different kinds of reference ownership supported by Swift. // This enum is used in diagnostics. If you add a case here, the diagnostics // must be updated as well. -enum class Ownership { +enum class Ownership : uint8_t { /// \brief a strong reference (the default semantics) Strong, diff --git a/include/swift/AST/ParameterList.h b/include/swift/AST/ParameterList.h new file mode 100644 index 0000000000000..d228151b05a9e --- /dev/null +++ b/include/swift/AST/ParameterList.h @@ -0,0 +1,153 @@ +//===--- ParameterList.h - Functions & closures parameter lists -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the ParameterList class and support logic. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_PARAMETERLIST_H +#define SWIFT_AST_PARAMETERLIST_H + +#include "swift/AST/Decl.h" +#include "swift/Basic/OptionSet.h" + +namespace swift { + +/// This describes a list of parameters. Each parameter descriptor is tail +/// allocated onto this list. +class alignas(alignof(ParamDecl*)) ParameterList { + void *operator new(size_t Bytes) throw() = delete; + void operator delete(void *Data) throw() = delete; + void *operator new(size_t Bytes, void *Mem) throw() = delete; + void *operator new(size_t Bytes, ASTContext &C, + unsigned Alignment = 8); + + SourceLoc LParenLoc, RParenLoc; + size_t numParameters; + + ParameterList(SourceLoc LParenLoc, size_t numParameters, SourceLoc RParenLoc) + : LParenLoc(LParenLoc), RParenLoc(RParenLoc), numParameters(numParameters){} + void operator=(const ParameterList&) = delete; +public: + /// Create a parameter list with the specified parameters. + static ParameterList *create(const ASTContext &C, SourceLoc LParenLoc, + ArrayRef params, + SourceLoc RParenLoc); + + /// Create a parameter list with the specified parameters, with no location + /// info for the parens. + static ParameterList *create(const ASTContext &C, + ArrayRef params) { + return create(C, SourceLoc(), params, SourceLoc()); + } + + /// Create an empty parameter list. + static ParameterList *createEmpty(const ASTContext &C, + SourceLoc LParenLoc = SourceLoc(), + SourceLoc RParenLoc = SourceLoc()) { + return create(C, LParenLoc, {}, RParenLoc); + } + + /// Create a parameter list for a single parameter lacking location info. + static ParameterList *createWithoutLoc(ParamDecl *decl) { + return create(decl->getASTContext(), decl); + } + + /// Create an implicit 'self' decl for a method in the specified decl context. + /// If 'static' is true, then this is self for a static method in the type. + /// + /// Note that this decl is created, but it is returned with an incorrect + /// DeclContext that needs to be set correctly. This is automatically handled + /// when a function is created with this as part of its argument list. + /// + static ParameterList *createSelf(SourceLoc loc, DeclContext *DC, + bool isStaticMethod = false, + bool isInOut = false); + + SourceLoc getLParenLoc() const { return LParenLoc; } + SourceLoc getRParenLoc() const { return RParenLoc; } + + typedef MutableArrayRef::iterator iterator; + typedef ArrayRef::iterator const_iterator; + iterator begin() { return getArray().begin(); } + iterator end() { return getArray().end(); } + const_iterator begin() const { return getArray().begin(); } + const_iterator end() const { return getArray().end(); } + + MutableArrayRef getArray() { + auto Ptr = reinterpret_cast(this + 1); + return { Ptr, numParameters }; + } + ArrayRef getArray() const { + auto Ptr = reinterpret_cast(this + 1); + return { Ptr, numParameters }; + } + + size_t size() const { + return numParameters; + } + + const ParamDecl *get(unsigned i) const { + return getArray()[i]; + } + + ParamDecl *&get(unsigned i) { + return getArray()[i]; + } + + const ParamDecl *operator[](unsigned i) const { return get(i); } + ParamDecl *&operator[](unsigned i) { return get(i); } + + /// Change the DeclContext of any contained parameters to the specified + /// DeclContext. + void setDeclContextOfParamDecls(DeclContext *DC); + + + /// Flags used to indicate how ParameterList cloning should operate. + enum CloneFlags { + /// The cloned ParamDecls should be marked implicit. + Implicit = 0x01, + /// The cloned pattern is for an inherited constructor; mark default + /// arguments as inherited, and mark unnamed arguments as named. + Inherited = 0x02 + }; + + /// Make a duplicate copy of this parameter list. This allocates copies of + /// the ParamDecls, so they can be reparented into a new DeclContext. + ParameterList *clone(const ASTContext &C, + OptionSet options = None) const; + + /// Return a TupleType or ParenType for this parameter list. This returns a + /// null type if one of the ParamDecls does not have a type set for it yet. + Type getType(const ASTContext &C) const; + + /// Return the full function type for a set of curried parameter lists that + /// returns the specified result type. This returns a null type if one of the + /// ParamDecls does not have a type set for it yet. + /// + static Type getFullType(Type resultType, ArrayRef PL); + + + /// Return the full source range of this parameter. + SourceRange getSourceRange() const; + SourceLoc getStartLoc() const { return getSourceRange().Start; } + SourceLoc getEndLoc() const { return getSourceRange().End; } + + void dump() const; + void dump(raw_ostream &OS, unsigned Indent = 0) const; + + // void print(raw_ostream &OS) const; +}; + +} // end namespace swift. + +#endif diff --git a/include/swift/AST/Pattern.h b/include/swift/AST/Pattern.h index 393b8154936d2..e30f875d20be5 100644 --- a/include/swift/AST/Pattern.h +++ b/include/swift/AST/Pattern.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,7 +20,6 @@ #include "swift/Basic/SourceLoc.h" #include "swift/Basic/type_traits.h" #include "swift/AST/Decl.h" -#include "swift/AST/DefaultArgumentKind.h" #include "swift/AST/Expr.h" #include "swift/Basic/LLVM.h" #include "swift/AST/Type.h" @@ -30,7 +29,6 @@ namespace swift { class ASTContext; - class ExprHandle; /// PatternKind - The classification of different kinds of /// value-matching pattern. @@ -120,11 +118,6 @@ class alignas(8) Pattern { /// identifier if the pattern does not bind a name directly. Identifier getBoundName() const; - /// Returns the name directly bound by this pattern within the body of - /// a function, or the null identifier if the pattern does not bind a name - /// directly. - Identifier getBodyName() const; - /// If this pattern binds a single variable without any /// destructuring or conditionalizing, return that variable. VarDecl *getSingleVar() const; @@ -169,54 +162,12 @@ class alignas(8) Pattern { VD->setParentPatternStmt(S); }); } - - /// Return the number of "top-level" variables in the given pattern, - /// which looks into one level of tuple pattern to determine the # - /// of variables. If the pattern is not a tuple, the result is one. - unsigned numTopLevelVariables() const; - - /// \brief Build an implicit 'self' parameter for the specified DeclContext. - static Pattern *buildImplicitSelfParameter(SourceLoc Loc, - TypeLoc TyLoc, - DeclContext *CurDeclContext); - - /// \brief Build an implicit let parameter pattern for the specified - /// DeclContext. - static Pattern *buildImplicitLetParameter(SourceLoc loc, StringRef name, - TypeLoc TyLoc, - DeclContext *CurDeclContext); - - /// Flags used to indicate how pattern cloning should operate. - enum CloneFlags { - /// The cloned pattern should be implicit. - Implicit = 0x01, - /// The cloned pattern is for an inherited constructor; mark default - /// arguments as inherited, and mark unnamed arguments as named. - Inherited = 0x02, - /// Whether the named patterns produced from a cloned 'any' pattern is - /// are 'var'. - IsVar = 0x04 - }; - - Pattern *clone(ASTContext &context, - OptionSet options = None) const; - - /// Given that this is a function-parameter pattern, clone it in a - /// way that permits makeForwardingReference to be called on the - /// result. - Pattern *cloneForwardable(ASTContext &context, DeclContext *DC, - OptionSet options = None) const; - /// Form an un-typechecked reference to the variables bound by this - /// pattern in a manner which perfectly forwards the values. Not - /// all patterns can be forwarded. - Expr *buildForwardingRefExpr(ASTContext &context) const; - static bool classof(const Pattern *P) { return true; } //*** Allocation Routines ************************************************/ - void *operator new(size_t bytes, ASTContext &C); + void *operator new(size_t bytes, const ASTContext &C); // Make placement new and vanilla new/delete illegal for Patterns. void *operator new(size_t bytes) = delete; @@ -271,23 +222,14 @@ class ParenPattern : public Pattern { class TuplePatternElt { Identifier Label; SourceLoc LabelLoc; - llvm::PointerIntPair ThePatternAndEllipsis; - SourceLoc EllipsisLoc; - ExprHandle *Init; - DefaultArgumentKind DefArgKind; + Pattern *ThePattern; public: TuplePatternElt() = default; - explicit TuplePatternElt(Pattern *P) - : ThePatternAndEllipsis(P, false), Init(nullptr), DefArgKind(DefaultArgumentKind::None) {} + explicit TuplePatternElt(Pattern *P) : ThePattern(P) {} - TuplePatternElt(Identifier Label, SourceLoc LabelLoc, - Pattern *p, bool hasEllipsis, - SourceLoc ellipsisLoc = SourceLoc(), - ExprHandle *init = nullptr, - DefaultArgumentKind defArgKind = DefaultArgumentKind::None) - : Label(Label), LabelLoc(LabelLoc), ThePatternAndEllipsis(p, hasEllipsis), - EllipsisLoc(ellipsisLoc), Init(init), DefArgKind(defArgKind) {} + TuplePatternElt(Identifier Label, SourceLoc LabelLoc, Pattern *p) + : Label(Label), LabelLoc(LabelLoc), ThePattern(p) {} Identifier getLabel() const { return Label; } SourceLoc getLabelLoc() const { return LabelLoc; } @@ -296,20 +238,12 @@ class TuplePatternElt { LabelLoc = Loc; } - Pattern *getPattern() { return ThePatternAndEllipsis.getPointer(); } + Pattern *getPattern() { return ThePattern; } const Pattern *getPattern() const { - return ThePatternAndEllipsis.getPointer(); + return ThePattern; } - void setPattern(Pattern *p) { ThePatternAndEllipsis.setPointer(p); } - - bool hasEllipsis() const { return ThePatternAndEllipsis.getInt(); } - SourceLoc getEllipsisLoc() const { return EllipsisLoc; } - - ExprHandle *getInit() const { return Init; } - - DefaultArgumentKind getDefaultArgKind() const { return DefArgKind; } - void setDefaultArgKind(DefaultArgumentKind DAK) { DefArgKind = DAK; } + void setPattern(Pattern *p) { ThePattern = p; } }; /// A pattern consisting of a tuple of patterns. @@ -366,9 +300,6 @@ class TuplePattern : public Pattern { SourceLoc getRParenLoc() const { return RPLoc; } SourceRange getSourceRange() const; - bool hasAnyEllipsis() const; - SourceLoc getAnyEllipsisLoc() const; - static bool classof(const Pattern *P) { return P->getKind() == PatternKind::Tuple; } @@ -387,7 +318,6 @@ class NamedPattern : public Pattern { VarDecl *getDecl() const { return Var; } Identifier getBoundName() const; - Identifier getBodyName() const; StringRef getNameStr() const { return Var->getNameStr(); } SourceLoc getLoc() const { return Var->getLoc(); } diff --git a/include/swift/AST/PatternNodes.def b/include/swift/AST/PatternNodes.def index a35385bdd17d6..40dc5926a8f59 100644 --- a/include/swift/AST/PatternNodes.def +++ b/include/swift/AST/PatternNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/PlatformKind.h b/include/swift/AST/PlatformKind.h index 4ac2580ac3aca..3da2fe800b45b 100644 --- a/include/swift/AST/PlatformKind.h +++ b/include/swift/AST/PlatformKind.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -32,7 +32,7 @@ enum class PlatformKind { #include "swift/AST/PlatformKinds.def" }; -/// Returns the short string representating the platform, suitable for +/// Returns the short string representing the platform, suitable for /// use in availability specifications (e.g., "OSX"). StringRef platformString(PlatformKind platform); @@ -40,7 +40,7 @@ StringRef platformString(PlatformKind platform); /// or None if such a platform kind does not exist. Optional platformFromString(StringRef Name); -/// Returns a human-readiable version of the platform name as a string, suitable +/// Returns a human-readable version of the platform name as a string, suitable /// for emission in diagnostics (e.g., "OS X"). StringRef prettyPlatformString(PlatformKind platform); diff --git a/include/swift/AST/PlatformKinds.def b/include/swift/AST/PlatformKinds.def index 0a97d241d8907..3325258e5fd16 100644 --- a/include/swift/AST/PlatformKinds.def +++ b/include/swift/AST/PlatformKinds.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index cfd634202664f..1456a773965c2 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -1,8 +1,8 @@ -//===- PrettyStackTrace.h - Crash trace information -------------*- C++ -*-===// +//===--- PrettyStackTrace.h - Crash trace information -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 22fe00cb924d8..4806fad4eea7c 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -229,6 +229,7 @@ struct PrintOptions { result.ExcludeAttrList.push_back(DAK_Exported); result.ExcludeAttrList.push_back(DAK_Inline); result.ExcludeAttrList.push_back(DAK_Rethrows); + result.ExcludeAttrList.push_back(DAK_Swift3Migration); result.PrintOverrideKeyword = false; result.AccessibilityFilter = Accessibility::Public; result.PrintIfConfig = false; @@ -247,7 +248,7 @@ struct PrintOptions { static PrintOptions printTypeInterface(Type T, DeclContext *DC); - /// Retrive the print options that are suitable to print the testable interface. + /// Retrieve the print options that are suitable to print the testable interface. static PrintOptions printTestableInterface() { PrintOptions result = printInterface(); result.AccessibilityFilter = Accessibility::Internal; @@ -270,6 +271,7 @@ struct PrintOptions { result.PrintAccessibility = false; result.SkipUnavailable = false; result.ExcludeAttrList.push_back(DAK_Available); + result.ExcludeAttrList.push_back(DAK_Swift3Migration); result.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::BothAlways; result.PrintDocumentationComments = false; @@ -312,6 +314,7 @@ struct PrintOptions { PO.PrintFunctionRepresentationAttrs = false; PO.PrintDocumentationComments = false; PO.ExcludeAttrList.push_back(DAK_Available); + PO.ExcludeAttrList.push_back(DAK_Swift3Migration); PO.SkipPrivateStdlibDecls = true; return PO; } diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index c60c6d74e93a6..e8891fdeb7a9a 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,6 +18,7 @@ #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/Decl.h" +#include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/Substitution.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" @@ -35,6 +36,7 @@ class GenericParamList; class NormalProtocolConformance; class ProtocolConformance; class ModuleDecl; +class SubstitutionIterator; enum class AllocationArena; /// \brief Type substitution mapping from substitutable types to their @@ -87,7 +89,7 @@ enum class ProtocolConformanceState { /// /// ProtocolConformance is an abstract base class, implemented by subclasses /// for the various kinds of conformance (normal, specialized, inherited). -class ProtocolConformance { +class alignas(1 << DeclAlignInBits) ProtocolConformance { /// The kind of protocol conformance. ProtocolConformanceKind Kind; @@ -187,7 +189,9 @@ class ProtocolConformance { /// protocol conformance. /// /// The function object should accept a \c ValueDecl* for the requirement - /// followed by the \c ConcreteDeclRef for the witness. + /// followed by the \c ConcreteDeclRef for the witness. Note that a generic + /// witness will only be specialized if the conformance came from the current + /// file. template void forEachValueWitness(LazyResolver *resolver, F f) const { const ProtocolDecl *protocol = getProtocol(); @@ -252,7 +256,7 @@ class ProtocolConformance { return mem; } - /// Print a parsable and human-readable description of the identifying + /// Print a parseable and human-readable description of the identifying /// information of the protocol conformance. void printName(raw_ostream &os, const PrintOptions &PO = PrintOptions()) const; @@ -376,6 +380,9 @@ class NormalProtocolConformance : public ProtocolConformance, TypeDecl *typeDecl) const; /// Retrieve the value witness corresponding to the given requirement. + /// + /// Note that a generic witness will only be specialized if the conformance + /// came from the current file. ConcreteDeclRef getWitness(ValueDecl *requirement, LazyResolver *resolver) const; @@ -496,6 +503,8 @@ class SpecializedProtocolConformance : public ProtocolConformance, return GenericSubstitutions; } + SubstitutionIterator getGenericSubstitutionIterator() const; + /// Get the protocol being conformed to. ProtocolDecl *getProtocol() const { return GenericConformance->getProtocol(); diff --git a/include/swift/AST/ProtocolConformanceRef.h b/include/swift/AST/ProtocolConformanceRef.h new file mode 100644 index 0000000000000..4549642624e64 --- /dev/null +++ b/include/swift/AST/ProtocolConformanceRef.h @@ -0,0 +1,98 @@ +//===--- ProtocolConformanceRef.h - AST Protocol Conformance ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the ProtocolConformanceRef type. +// +//===----------------------------------------------------------------------===// +#ifndef SWIFT_AST_PROTOCOLCONFORMANCEREF_H +#define SWIFT_AST_PROTOCOLCONFORMANCEREF_H + +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/PointerUnion.h" +#include "swift/AST/TypeAlignments.h" + +namespace swift { + +/// A ProtocolConformanceRef is a handle to a protocol conformance which +/// may be either concrete or abstract. +/// +/// A concrete conformance is derived from a specific protocol conformance +/// declaration. +/// +/// An abstract conformance is derived from context: the conforming type +/// is either existential or opaque (i.e. an archetype), and while the +/// type-checker promises that the conformance exists, it is not known +/// statically which concrete conformance it refers to. +/// +/// ProtocolConformanceRef allows the efficient recovery of the protocol +/// even when the conformance is abstract. +class ProtocolConformanceRef { + using UnionType = llvm::PointerUnion; + UnionType Union; + + explicit ProtocolConformanceRef(UnionType value) : Union(value) { + assert(value && "cannot construct ProtocolConformanceRef with null"); + } +public: + /// Create an abstract protocol conformance reference. + explicit ProtocolConformanceRef(ProtocolDecl *proto) : Union(proto) { + assert(proto != nullptr && + "cannot construct ProtocolConformanceRef with null"); + } + + /// Create a concrete protocol conformance reference. + explicit ProtocolConformanceRef(ProtocolConformance *conf) : Union(conf) { + assert(conf != nullptr && + "cannot construct ProtocolConformanceRef with null"); + } + + /// Create either a concrete or an abstract protocol conformance reference, + /// depending on whether ProtocolConformance is null. + explicit ProtocolConformanceRef(ProtocolDecl *protocol, + ProtocolConformance *conf); + + bool isConcrete() const { return Union.is(); } + ProtocolConformance *getConcrete() const { + return Union.get(); + } + + bool isAbstract() const { return Union.is(); } + ProtocolDecl *getAbstract() const { + return Union.get(); + } + + using OpaqueValue = void*; + OpaqueValue getOpaqueValue() const { return Union.getOpaqueValue(); } + static ProtocolConformanceRef getFromOpaqueValue(OpaqueValue value) { + return ProtocolConformanceRef(UnionType::getFromOpaqueValue(value)); + } + + /// Return the protocol requirement. + ProtocolDecl *getRequirement() const; + + void dump() const; + + bool operator==(ProtocolConformanceRef other) const { + return Union == other.Union; + } + bool operator!=(ProtocolConformanceRef other) const { + return Union != other.Union; + } + + friend llvm::hash_code hash_value(ProtocolConformanceRef conformance) { + return llvm::hash_value(conformance.Union.getOpaqueValue()); + } +}; + +} // end namespace swift + +#endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCEREF_H diff --git a/include/swift/AST/RawComment.h b/include/swift/AST/RawComment.h index 3b83baef652cd..bf7be32bc82ed 100644 --- a/include/swift/AST/RawComment.h +++ b/include/swift/AST/RawComment.h @@ -1,8 +1,8 @@ -//===--- RawComment.h - Extraction of raw comments ------------------------===// +//===--- RawComment.h - Extraction of raw comments --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/ReferencedNameTracker.h b/include/swift/AST/ReferencedNameTracker.h index a1738c6b58871..7864ae1f86486 100644 --- a/include/swift/AST/ReferencedNameTracker.h +++ b/include/swift/AST/ReferencedNameTracker.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Requirement.h b/include/swift/AST/Requirement.h index 41d8a057fda71..e4135267a474c 100644 --- a/include/swift/AST/Requirement.h +++ b/include/swift/AST/Requirement.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,6 +28,10 @@ enum class RequirementKind : unsigned int { /// A conformance requirement T : P, where T is a type that depends /// on a generic parameter and P is a protocol to which T must conform. Conformance, + /// A superclass requirement T : C, where T is a type that depends + /// on a generic parameter and C is a concrete class type which T must + /// equal or be a subclass of. + Superclass, /// A same-type requirement T == U, where T and U are types that shall be /// equivalent. SameType, diff --git a/include/swift/AST/ResilienceExpansion.h b/include/swift/AST/ResilienceExpansion.h index f861539a8fd38..a8059e86b0827 100644 --- a/include/swift/AST/ResilienceExpansion.h +++ b/include/swift/AST/ResilienceExpansion.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 235ff2284c281..df6811cc56cd4 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -51,7 +51,7 @@ class SILOptions { OptimizeUnchecked }; - /// Controls how perform SIL linking. + /// Controls how to perform SIL linking. LinkingMode LinkMode = LinkNormal; /// Remove all runtime assertions during optimizations. @@ -97,9 +97,10 @@ class SILOptions { /// Should we use a pass pipeline passed in via a json file? Null by default. StringRef ExternalPassPipelineFilename; - - /// Use super_method for native super method calls instead of function_ref. - bool UseNativeSuperMethod = false; + + /// Emit captures and function contexts using +0 caller-guaranteed ARC + /// conventions. + bool EnableGuaranteedClosureContexts = false; }; } // end namespace swift diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index 8f558dfbfdf48..e767946540c08 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index f6c50aef97a65..206b184ee7e79 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -217,7 +217,7 @@ class DeferStmt : public Stmt { Expr *getCallExpr() const { return callExpr; } void setCallExpr(Expr *E) { callExpr = E; } - /// Dig the original users's body of the defer out for AST fidelity. + /// Dig the original user's body of the defer out for AST fidelity. BraceStmt *getBodyAsWritten() const; static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Defer; } @@ -800,6 +800,9 @@ class ForStmt : public LabeledStmt { SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(ForLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } + + SourceLoc getFirstSemicolonLoc() const { return Semi1Loc; } + SourceLoc getSecondSemicolonLoc() const { return Semi2Loc; } NullablePtr getInitializer() const { return Initializer; } void setInitializer(Expr *V) { Initializer = V; } diff --git a/include/swift/AST/StmtNodes.def b/include/swift/AST/StmtNodes.def index 87b8f9a2b0aa1..38676dcbd5903 100644 --- a/include/swift/AST/StmtNodes.def +++ b/include/swift/AST/StmtNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/SubstTypeVisitor.h b/include/swift/AST/SubstTypeVisitor.h index 2abe6583a1d74..012dead8867c2 100644 --- a/include/swift/AST/SubstTypeVisitor.h +++ b/include/swift/AST/SubstTypeVisitor.h @@ -1,8 +1,8 @@ -//===-- SubstTypeVisitor.h - Visitor for substituted types ------*- C++ -*-===// +//===--- SubstTypeVisitor.h - Visitor for substituted types -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/Substitution.h b/include/swift/AST/Substitution.h index f6754e520f759..a209b3a18977d 100644 --- a/include/swift/AST/Substitution.h +++ b/include/swift/AST/Substitution.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,54 +26,31 @@ namespace llvm { namespace swift { class ArchetypeType; - class ProtocolConformance; + class ProtocolConformanceRef; /// DenseMap type used internally by Substitution::subst to track conformances /// applied to archetypes. using ArchetypeConformanceMap - = llvm::DenseMap>; - + = llvm::DenseMap>; + /// Substitution - A substitution into a generic specialization. class Substitution { - ArchetypeType * Archetype = nullptr; Type Replacement; - ArrayRef Conformance; + ArrayRef Conformance; public: - /// FIXME: An archetype that looks like the archetype or dependent generic - /// parameter type that should be substituted by this substitution, but - /// which is not guaranteed to map to any particular context. All that is - /// guaranteed: - /// - /// - Archetype will conform to the same protocols as the substituted - /// type. - /// - Archetype will appear at the same point in the generic parameter - /// hierarchy as the substituted type; that is, if the substituted type - /// is a generic parameter, it will be a primary archetype, or if the - /// substituted type is a dependent member type, it will be a nested - /// archetype with the same name path--if T0.Foo.Bar is being substituted, - /// this will be some archetype X.Foo.Bar. - /// - If the substituted type represents a Self or associated type of a - /// protocol requirement, this Archetype will be that archetype from the - /// protocol context. - /// - /// You really shouldn't use the value of this field for anything new. - ArchetypeType *getArchetype() const { return Archetype; } - /// The replacement type. Type getReplacement() const { return Replacement; } /// The protocol conformances for the replacement. These appear in the same /// order as Archetype->getConformsTo() for the substituted archetype. - const ArrayRef getConformances() const { + const ArrayRef getConformances() const { return Conformance; } Substitution() {} - Substitution(ArchetypeType *Archetype, - Type Replacement, - ArrayRef Conformance); + Substitution(Type Replacement, ArrayRef Conformance); bool operator!=(const Substitution &other) const { return !(*this == other); } bool operator==(const Substitution &other) const; @@ -96,6 +73,60 @@ class Substitution { ArchetypeConformanceMap &conformanceMap) const; }; +/// An iterator over a list of archetypes and the substitutions +/// applied to them. +class SubstitutionIterator { + // TODO: this should use dependent types when getConformsTo() becomes + // efficient there. + ArrayRef Archetypes; + ArrayRef Subs; + +public: + SubstitutionIterator() = default; + explicit SubstitutionIterator(GenericParamList *params, + ArrayRef subs); + + struct iterator { + ArchetypeType * const *NextArch = nullptr; + const Substitution *NextSub = nullptr; + + iterator() = default; + iterator(ArchetypeType * const *nextArch, const Substitution *nextSub) + : NextArch(nextArch), NextSub(nextSub) {} + + iterator &operator++() { + ++NextArch; + ++NextSub; + return *this; + } + + iterator operator++(int) { + iterator copy = *this; + ++*this; + return copy; + } + + std::pair operator*() const { + return { *NextArch, *NextSub }; + } + + bool operator==(const iterator &other) const { + assert((NextSub == other.NextSub) == (NextArch == other.NextArch)); + return NextSub == other.NextSub; + } + bool operator!=(const iterator &other) const { + return !(*this == other); + } + }; + + ArrayRef getSubstitutions() const { return Subs; } + + bool empty() const { return Archetypes.empty(); } + + iterator begin() const { return { Archetypes.begin(), Subs.begin() }; } + iterator end() const { return { Archetypes.end(), Subs.end() }; } +}; + void dump(const ArrayRef &subs); } // end namespace swift diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 8548667d4bfb8..f8093ac08bf99 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -434,7 +434,7 @@ namespace llvm { template<> struct DenseMapInfo : public DenseMapInfo { static swift::CanType getEmptyKey() { - return swift::CanType(0); + return swift::CanType(nullptr); } static swift::CanType getTombstoneKey() { return swift::CanType(llvm::DenseMapInfo class PointerLikeTypeTraits \ LLVM_DECLARE_TYPE_ALIGNMENT(swift::Decl, swift::DeclAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::AbstractStorageDecl, swift::DeclAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::OperatorDecl, swift::DeclAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolDecl, swift::DeclAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolConformance, swift::DeclAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::DeclContext, swift::DeclContextAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeBase, swift::TypeAlignInBits) LLVM_DECLARE_TYPE_ALIGNMENT(swift::ArchetypeType, swift::TypeAlignInBits) diff --git a/include/swift/AST/TypeCheckerDebugConsumer.h b/include/swift/AST/TypeCheckerDebugConsumer.h index b6133e4378af5..00a5d9ec2663b 100644 --- a/include/swift/AST/TypeCheckerDebugConsumer.h +++ b/include/swift/AST/TypeCheckerDebugConsumer.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeLoc.h b/include/swift/AST/TypeLoc.h index 8f2f7ef40f49e..a76585e453633 100644 --- a/include/swift/AST/TypeLoc.h +++ b/include/swift/AST/TypeLoc.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeMatcher.h b/include/swift/AST/TypeMatcher.h index 70461e6dbf6db..1cf6c940f176d 100644 --- a/include/swift/AST/TypeMatcher.h +++ b/include/swift/AST/TypeMatcher.h @@ -1,8 +1,8 @@ -//===-- TypeMatcher.h - Recursive Type Matcher------- -----------*- C++ -*-===// +//===--- TypeMatcher.h - Recursive Type Matcher -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeMemberVisitor.h b/include/swift/AST/TypeMemberVisitor.h index d6afd46a89bd3..6af30cfc3d8d9 100644 --- a/include/swift/AST/TypeMemberVisitor.h +++ b/include/swift/AST/TypeMemberVisitor.h @@ -1,8 +1,8 @@ -//===-- TypeMemberVisitor.h - ASTVisitor specialization ---------*- C++ -*-===// +//===--- TypeMemberVisitor.h - ASTVisitor specialization --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index ebfffbf3baaa6..f9093ca449938 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeRefinementContext.h b/include/swift/AST/TypeRefinementContext.h index 14186ca77dd07..63844e750f10e 100644 --- a/include/swift/AST/TypeRefinementContext.h +++ b/include/swift/AST/TypeRefinementContext.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 4f5d3678d0c32..1478ba255199e 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -85,7 +85,7 @@ class alignas(8) TypeRepr { //*** Allocation Routines ************************************************/ - void *operator new(size_t bytes, ASTContext &C, + void *operator new(size_t bytes, const ASTContext &C, unsigned Alignment = alignof(TypeRepr)); // Make placement new and vanilla new/delete illegal for TypeReprs. @@ -98,7 +98,7 @@ class alignas(8) TypeRepr { void dump() const; /// Clone the given type representation. - TypeRepr *clone(ASTContext &ctx) const; + TypeRepr *clone(const ASTContext &ctx) const; /// Visit the top-level types in the given type representation, /// which includes the types referenced by \c IdentTypeReprs either @@ -392,44 +392,24 @@ class FunctionTypeRepr : public TypeRepr { /// [Foo] /// \endcode class ArrayTypeRepr : public TypeRepr { - // FIXME: Tail allocation. Use bits to determine whether Base/Size are - // available. TypeRepr *Base; - llvm::PointerIntPair SizeAndOldSyntax; SourceRange Brackets; public: - ArrayTypeRepr(TypeRepr *Base, ExprHandle *Size, SourceRange Brackets, - bool OldSyntax) - : TypeRepr(TypeReprKind::Array), Base(Base), - SizeAndOldSyntax(Size, OldSyntax), Brackets(Brackets) { } + ArrayTypeRepr(TypeRepr *Base, SourceRange Brackets) + : TypeRepr(TypeReprKind::Array), Base(Base), Brackets(Brackets) { } TypeRepr *getBase() const { return Base; } - ExprHandle *getSize() const { return SizeAndOldSyntax.getPointer(); } SourceRange getBrackets() const { return Brackets; } - bool usesOldSyntax() const { return SizeAndOldSyntax.getInt(); } - static bool classof(const TypeRepr *T) { return T->getKind() == TypeReprKind::Array; } static bool classof(const ArrayTypeRepr *T) { return true; } private: - SourceLoc getStartLocImpl() const { - if (usesOldSyntax()) - return Base->getStartLoc(); - - return Brackets.Start; - } - SourceLoc getEndLocImpl() const { - // This test is necessary because the type Int[4][2] is represented as - // ArrayTypeRepr(ArrayTypeRepr(Int, 2), 4), so the range needs to cover both - // sets of brackets. - if (usesOldSyntax() && isa(Base)) - return Base->getEndLoc(); - return Brackets.End; - } + SourceLoc getStartLocImpl() const { return Brackets.Start; } + SourceLoc getEndLocImpl() const { return Brackets.End; } void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const; friend class TypeRepr; }; @@ -781,10 +761,8 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::ProtocolComposition: case TypeReprKind::Tuple: case TypeReprKind::Fixed: - return true; - case TypeReprKind::Array: - return !cast(this)->usesOldSyntax(); + return true; } llvm_unreachable("bad TypeRepr kind"); } diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index 1ec3f7879fe30..50404fd9d9d94 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeVisitor.h b/include/swift/AST/TypeVisitor.h index 15be7dc39b574..81f89c3b90639 100644 --- a/include/swift/AST/TypeVisitor.h +++ b/include/swift/AST/TypeVisitor.h @@ -1,8 +1,8 @@ -//===-- TypeVisitor.h - Type Visitor ----------------------------*- C++ -*-===// +//===--- TypeVisitor.h - Type Visitor ---------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/AST/TypeWalker.h b/include/swift/AST/TypeWalker.h index 1a3d4042babff..7b079c01e604f 100644 --- a/include/swift/AST/TypeWalker.h +++ b/include/swift/AST/TypeWalker.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,11 +26,11 @@ class TypeWalker { Stop }; - /// This method is called when first visiting an type before walking into its + /// This method is called when first visiting a type before walking into its /// children. virtual Action walkToTypePre(Type ty) { return Action::Continue; } - /// This method is called after visiting an type's children. + /// This method is called after visiting a type's children. virtual Action walkToTypePost(Type ty) { return Action::Continue; } /// Controls whether the original type of a SubstitutedType is visited. diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index caa2896fa6d7f..8b181b29f3cc0 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -425,7 +425,7 @@ class alignas(1 << TypeAlignInBits) TypeBase { return getRecursiveProperties().hasOpenedExistential(); } - /// Determine whether the type involves the given opend existential + /// Determine whether the type involves the given opened existential /// archetype. bool hasOpenedExistential(ArchetypeType *opened); @@ -672,10 +672,6 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// the result would be the (parenthesized) type ((int, int)). Type getUnlabeledType(ASTContext &Context); - /// Relabel the elements of the given type with the given new - /// (top-level) labels. - Type getRelabeledType(ASTContext &Context, ArrayRef labels); - /// \brief Retrieve the type without any default arguments. Type getWithoutDefaultArgs(const ASTContext &Context); @@ -839,17 +835,6 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// Retrieve the type declaration directly referenced by this type, if any. TypeDecl *getDirectlyReferencedTypeDecl() const; - /// Retrieve the default argument string that would be inferred for this type, - /// assuming that we know it is inferred. - /// - /// This routine pre-supposes that we know that the given type is the type of - /// a parameter that has a default, and all we need to figure out is which - /// default argument should be print. - /// - /// FIXME: This should go away when/if inferred default arguments become - /// "real". - StringRef getInferredDefaultArgString(); - private: // Make vanilla new/delete illegal for Types. void *operator new(size_t Bytes) throw() = delete; @@ -1257,9 +1242,11 @@ class TupleTypeElt { /// is variadic. llvm::PointerIntPair NameAndVariadic; - /// \brief This is the type of the field, which is mandatory, along with the - /// kind of default argument. - llvm::PointerIntPair TyAndDefaultArg; + /// \brief This is the type of the field. + Type ElementType; + + /// The default argument, + DefaultArgumentKind DefaultArg; friend class TupleType; @@ -1273,12 +1260,12 @@ class TupleTypeElt { /*implicit*/ TupleTypeElt(TypeBase *Ty) : NameAndVariadic(Identifier(), false), - TyAndDefaultArg(Ty, DefaultArgumentKind::None) { } + ElementType(Ty), DefaultArg(DefaultArgumentKind::None) { } bool hasName() const { return !NameAndVariadic.getPointer().empty(); } Identifier getName() const { return NameAndVariadic.getPointer(); } - Type getType() const { return TyAndDefaultArg.getPointer(); } + Type getType() const { return ElementType.getPointer(); } /// Determine whether this field is variadic. bool isVararg() const { @@ -1286,9 +1273,7 @@ class TupleTypeElt { } /// Retrieve the kind of default argument available on this field. - DefaultArgumentKind getDefaultArgKind() const { - return TyAndDefaultArg.getInt(); - } + DefaultArgumentKind getDefaultArgKind() const { return DefaultArg; } /// Whether we have a default argument. bool hasDefaultArg() const { @@ -1308,11 +1293,6 @@ class TupleTypeElt { TupleTypeElt getWithType(Type T) const { return TupleTypeElt(T, getName(), getDefaultArgKind(), isVararg()); } - - /// Determine whether this tuple element has an initializer. - bool hasInit() const { - return getDefaultArgKind() != DefaultArgumentKind::None; - } }; inline Type getTupleEltType(const TupleTypeElt &elt) { @@ -1358,7 +1338,7 @@ class TupleType : public TypeBase, public llvm::FoldingSetNode { return TupleEltTypeArrayRef(getElements()); } - /// getNamedElementId - If this tuple has a element with the specified name, + /// getNamedElementId - If this tuple has an element with the specified name, /// return the element index, otherwise return -1. int getNamedElementId(Identifier I) const; @@ -1944,7 +1924,7 @@ class ModuleType : public TypeBase { // Implement isa/cast/dyncast/etc. static bool classof(const TypeBase *T) { - return T->getKind() == TypeKind::Module; + return T->getKind() == TypeKind::Module; } private: @@ -2575,6 +2555,42 @@ inline bool isConsumedParameter(ParameterConvention conv) { llvm_unreachable("bad convention kind"); } +enum class InoutAliasingAssumption { + /// Assume that an inout indirect parameter may alias other objects. + /// This is the safe assumption an optimizations should make if it may break + /// memory safety in case the inout aliasing rule is violation. + Aliasing, + + /// Assume that an inout indirect parameter cannot alias other objects. + /// Optimizations should only use this if they can guarantee that they will + /// not break memory safety even if the inout aliasing rule is violated. + NotAliasing +}; + +/// Returns true if \p conv is a not-aliasing indirect parameter. +/// The \p isInoutAliasing specifies what to assume about the inout convention. +/// See InoutAliasingAssumption. +inline bool isNotAliasedIndirectParameter(ParameterConvention conv, + InoutAliasingAssumption isInoutAliasing) { + switch (conv) { + case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_Out: + case ParameterConvention::Indirect_In_Guaranteed: + return true; + + case ParameterConvention::Indirect_Inout: + return isInoutAliasing == InoutAliasingAssumption::NotAliasing; + + case ParameterConvention::Indirect_InoutAliasable: + case ParameterConvention::Direct_Unowned: + case ParameterConvention::Direct_Guaranteed: + case ParameterConvention::Direct_Owned: + case ParameterConvention::Direct_Deallocating: + return false; + } + llvm_unreachable("covered switch isn't covered?!"); +} + /// Returns true if conv is a guaranteed parameter. This may look unnecessary /// but this will allow code to generalize to handle Indirect_Guaranteed /// parameters when they are added. @@ -4100,12 +4116,7 @@ class TypeVariableType : public TypeBase { class Implementation; public: - - /// \brief Printing substitutions for type variables may result in recursive - /// references to the type variable itself. This flag is used to short-circuit - /// such operations. - bool isPrinting = false; - + /// \brief Create a new type variable whose implementation is constructed /// with the given arguments. template @@ -4339,7 +4350,7 @@ inline TupleTypeElt::TupleTypeElt(Type ty, DefaultArgumentKind defArg, bool isVariadic) : NameAndVariadic(name, isVariadic), - TyAndDefaultArg(ty.getPointer(), defArg) + ElementType(ty), DefaultArg(defArg) { assert(!isVariadic || isa(ty.getPointer()) || diff --git a/include/swift/AST/USRGeneration.h b/include/swift/AST/USRGeneration.h index 5eed154d0477b..808f50e71d7f8 100644 --- a/include/swift/AST/USRGeneration.h +++ b/include/swift/AST/USRGeneration.h @@ -1,8 +1,8 @@ -//===--- USRGeneration.h - Routines for USR generation --------------------===// +//===--- USRGeneration.h - Routines for USR generation ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/ASTSectionImporter/ASTSectionImporter.h b/include/swift/ASTSectionImporter/ASTSectionImporter.h index 5cf16e56e2016..2820bb86494d7 100644 --- a/include/swift/ASTSectionImporter/ASTSectionImporter.h +++ b/include/swift/ASTSectionImporter/ASTSectionImporter.h @@ -1,8 +1,8 @@ -//===--- ASTSectionImporter.cpp - Import AST Section Modules ---*- C++ -*--===// +//===--- ASTSectionImporter.h - Import AST Section Modules ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,7 @@ namespace swift { class SerializedModuleLoader; - /// \brief Povided a memory buffer with an entire Mach-O __apple_ast + /// \brief Provided a memory buffer with an entire Mach-O __apple_ast /// section, this function makes memory buffer copies of all swift /// modules found in it and registers them using /// registerMemoryBuffer() so they can be found by loadModule(). The diff --git a/include/swift/Basic/Algorithm.h b/include/swift/Basic/Algorithm.h index a1134e802d7fa..c2cef45aff32a 100644 --- a/include/swift/Basic/Algorithm.h +++ b/include/swift/Basic/Algorithm.h @@ -1,8 +1,8 @@ -//===--- Algorithm.h - -------------------------------------------*- C++ -*-==// +//===--- Algorithm.h - ------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/ArrayRefView.h b/include/swift/Basic/ArrayRefView.h index 6cddda4f9296e..f9181db6dc334 100644 --- a/include/swift/Basic/ArrayRefView.h +++ b/include/swift/Basic/ArrayRefView.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/AssertImplements.h b/include/swift/Basic/AssertImplements.h index 81894acb6ae5e..d4aa08b42ded1 100644 --- a/include/swift/Basic/AssertImplements.h +++ b/include/swift/Basic/AssertImplements.h @@ -1,8 +1,8 @@ -//===- AssertImplements.h - Assert that a class overrides a function ------===// +//===--- AssertImplements.h - Assert that a class overrides a function ----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/BlotMapVector.h b/include/swift/Basic/BlotMapVector.h index 645c2ee1da441..a80be3093cfd6 100644 --- a/include/swift/Basic/BlotMapVector.h +++ b/include/swift/Basic/BlotMapVector.h @@ -1,8 +1,8 @@ -//===- BlotMapVector.h - Map vector with "blot" operation -----*- C++ -*--===// +//===--- BlotMapVector.h - Map vector with "blot" operation ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/BlotSetVector.h b/include/swift/Basic/BlotSetVector.h index 92ca3dfd4ad53..9cd5f806bc60c 100644 --- a/include/swift/Basic/BlotSetVector.h +++ b/include/swift/Basic/BlotSetVector.h @@ -1,8 +1,8 @@ -//===--- BlotSetVector.h --------------------------------------------------===// +//===--- BlotSetVector.h ----------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -99,7 +99,7 @@ class BlotSetVector { /// V1. void replace(const ValueT &V1, const ValueT &V2) { auto Iter1 = Map.find(V1); - assert(Iter1 != Map.end() && "Can not replace value that is not in set"); + assert(Iter1 != Map.end() && "Cannot replace value that is not in set"); unsigned V1Index = Iter1->second; Map.erase(V1); diff --git a/include/swift/Basic/Cache.h b/include/swift/Basic/Cache.h index e3dfc995723d0..bcfd357e1eb2d 100644 --- a/include/swift/Basic/Cache.h +++ b/include/swift/Basic/Cache.h @@ -1,8 +1,8 @@ -//===--- Cache.h - Caching mechanism interface -------------------*- C++ -*-==// +//===--- Cache.h - Caching mechanism interface ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/ClusteredBitVector.h b/include/swift/Basic/ClusteredBitVector.h index dcc5cfa31868a..99114d9c3e172 100644 --- a/include/swift/Basic/ClusteredBitVector.h +++ b/include/swift/Basic/ClusteredBitVector.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Defer.h b/include/swift/Basic/Defer.h index 367b624a16d20..95e46e7cb2064 100644 --- a/include/swift/Basic/Defer.h +++ b/include/swift/Basic/Defer.h @@ -1,8 +1,8 @@ -//===- Defer.h - 'defer' helper macro ---------------------------*- C++ -*-===// +//===--- Defer.h - 'defer' helper macro -------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // -// This filed defines a 'defer' macro for performing a cleanup on any exit out +// This file defines a 'defer' macro for performing a cleanup on any exit out // of a scope. // //===----------------------------------------------------------------------===// diff --git a/include/swift/Basic/Demangle.h b/include/swift/Basic/Demangle.h index 41bc7fa47392a..c9d1807a98de2 100644 --- a/include/swift/Basic/Demangle.h +++ b/include/swift/Basic/Demangle.h @@ -1,8 +1,8 @@ -//===--- Demangle.h - Interface to Swift symbol demangling -------*- C++ -*-==// +//===--- Demangle.h - Interface to Swift symbol demangling ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -90,7 +90,7 @@ enum class FunctionSigSpecializationParamKind : unsigned { /// The pass that caused the specialization to occur. We use this to make sure /// that two passes that generate similar changes do not yield the same -/// mangling. This currently can not happen, so this is just a safety measure +/// mangling. This currently cannot happen, so this is just a safety measure /// that creates separate name spaces. enum class SpecializationPass : uint8_t { AllocBoxToStack, @@ -102,7 +102,7 @@ enum class SpecializationPass : uint8_t { }; static inline char encodeSpecializationPass(SpecializationPass Pass) { - return char(uint8_t(Pass)) + 48; + return char(uint8_t(Pass)) + '0'; } enum class ValueWitnessKind { diff --git a/include/swift/Basic/DemangleNodes.def b/include/swift/Basic/DemangleNodes.def index 58e5c5752d4d0..0c05714bfda3b 100644 --- a/include/swift/Basic/DemangleNodes.def +++ b/include/swift/Basic/DemangleNodes.def @@ -1,8 +1,8 @@ -//===-- DemangleNodes.def - Demangling Tree Metaprogramming -----*- C++ -*-===// +//===--- DemangleNodes.def - Demangling Tree Metaprogramming ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,6 +30,8 @@ NODE(ArchetypeRef) NODE(ArgumentTuple) NODE(AssociatedType) NODE(AssociatedTypeRef) +NODE(AssociatedTypeMetadataAccessor) +NODE(AssociatedTypeWitnessTableAccessor) NODE(AutoClosureType) NODE(BoundGenericClass) NODE(BoundGenericEnum) @@ -49,8 +51,6 @@ NODE(DependentGenericSameTypeRequirement) NODE(DependentGenericType) NODE(DependentMemberType) NODE(DependentGenericParamType) -NODE(DependentProtocolWitnessTableGenerator) -NODE(DependentProtocolWitnessTableTemplate) CONTEXT_NODE(Destructor) CONTEXT_NODE(DidSet) NODE(Directness) @@ -71,6 +71,8 @@ NODE(FunctionSignatureSpecializationParamKind) NODE(FunctionSignatureSpecializationParamPayload) NODE(FunctionType) NODE(Generics) +NODE(GenericProtocolWitnessTable) +NODE(GenericProtocolWitnessTableInstantiationFunction) NODE(GenericSpecialization) NODE(GenericSpecializationParam) NODE(GenericType) @@ -128,6 +130,7 @@ NODE(QualifiedArchetype) NODE(ReabstractionThunk) NODE(ReabstractionThunkHelper) NODE(ReturnType) +NODE(SILBoxType) NODE(SelfTypeRef) CONTEXT_NODE(Setter) NODE(SpecializationPassID) diff --git a/include/swift/Basic/DemangleWrappers.h b/include/swift/Basic/DemangleWrappers.h index 080320d2c2467..07d121994f6bd 100644 --- a/include/swift/Basic/DemangleWrappers.h +++ b/include/swift/Basic/DemangleWrappers.h @@ -1,8 +1,8 @@ -//===--- DemangleWrappers.h --------------------------------------*- C++ -*-==// +//===--- DemangleWrappers.h -------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/DiagnosticConsumer.h b/include/swift/Basic/DiagnosticConsumer.h index 7a1860ea136b1..87f8db009a483 100644 --- a/include/swift/Basic/DiagnosticConsumer.h +++ b/include/swift/Basic/DiagnosticConsumer.h @@ -1,8 +1,8 @@ -//===- DiagnosticConsumer.h - Diagnostic Consumer Interface -----*- C++ -*-===// +//===--- DiagnosticConsumer.h - Diagnostic Consumer Interface ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,12 +19,8 @@ #ifndef SWIFT_BASIC_DIAGNOSTIC_CONSUMER_H #define SWIFT_BASIC_DIAGNOSTIC_CONSUMER_H -#include "swift/Basic/LLVM.h" #include "swift/Basic/SourceLoc.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/SourceMgr.h" -#include namespace swift { class SourceManager; @@ -32,7 +28,7 @@ namespace swift { /// \brief Describes the kind of diagnostic. /// -enum class DiagnosticKind { +enum class DiagnosticKind : uint8_t { Error, Warning, Note diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h index 20b232faf913e..19ac63bf7ea7e 100644 --- a/include/swift/Basic/DiagnosticOptions.h +++ b/include/swift/Basic/DiagnosticOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -35,6 +35,12 @@ class DiagnosticOptions { /// When emitting fixits as code edits, apply all fixits from diagnostics /// without any filtering. bool FixitCodeForAllDiagnostics = false; + + /// Suppress all warnings + bool SuppressWarnings = false; + + /// Treat all warnings as errors + bool WarningsAsErrors = false; }; } diff --git a/include/swift/Basic/DiverseList.h b/include/swift/Basic/DiverseList.h index eeb7b0183ffed..8a2169e35001c 100644 --- a/include/swift/Basic/DiverseList.h +++ b/include/swift/Basic/DiverseList.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/DiverseStack.h b/include/swift/Basic/DiverseStack.h index 3d8ebb9321efc..01351273cee65 100644 --- a/include/swift/Basic/DiverseStack.h +++ b/include/swift/Basic/DiverseStack.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Dwarf.h b/include/swift/Basic/Dwarf.h index cceb2088e9391..c568990d3e8a0 100644 --- a/include/swift/Basic/Dwarf.h +++ b/include/swift/Basic/Dwarf.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/EditorPlaceholder.h b/include/swift/Basic/EditorPlaceholder.h index ea28420b5706c..c9734fcf0c778 100644 --- a/include/swift/Basic/EditorPlaceholder.h +++ b/include/swift/Basic/EditorPlaceholder.h @@ -1,8 +1,8 @@ -//===--- EditorPlaceholder.h - Handling for editor placeholders -----------===// +//===--- EditorPlaceholder.h - Handling for editor placeholders -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/EncodedSequence.h b/include/swift/Basic/EncodedSequence.h index b4c0a8d099211..c0a8bfc342e14 100644 --- a/include/swift/Basic/EncodedSequence.h +++ b/include/swift/Basic/EncodedSequence.h @@ -1,8 +1,8 @@ -//===--- EncodedSequence.h - A byte-encoded sequence -----------*- C++ -*-===// +//===--- EncodedSequence.h - A byte-encoded sequence ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Fallthrough.h b/include/swift/Basic/Fallthrough.h index 0e28731c6c0a6..c697722545fc9 100644 --- a/include/swift/Basic/Fallthrough.h +++ b/include/swift/Basic/Fallthrough.h @@ -1,8 +1,8 @@ -//===- Fallthrough.h - switch fallthrough annotation macro ------*- C++ -*-===// +//===--- Fallthrough.h - switch fallthrough annotation macro ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // -// This filed defines a SWIFT_FALLTHROUGH macro to annotate intentional +// This file defines a SWIFT_FALLTHROUGH macro to annotate intentional // fallthrough between switch cases. For compilers that support the // "clang::fallthrough" attribute, it expands to an empty statement with the // attribute applied; otherwise, it expands to just an empty statement. diff --git a/include/swift/Basic/FileSystem.h b/include/swift/Basic/FileSystem.h index 59d99df55c928..749818329f166 100644 --- a/include/swift/Basic/FileSystem.h +++ b/include/swift/Basic/FileSystem.h @@ -1,8 +1,8 @@ -//===--- FileSystem.cpp - Extra helpers for manipulating files --*- C++ -*-===// +//===--- FileSystem.h - Extra helpers for manipulating files ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/FlaggedPointer.h b/include/swift/Basic/FlaggedPointer.h index b70fb8c93d4be..c6d2c349a0b35 100644 --- a/include/swift/Basic/FlaggedPointer.h +++ b/include/swift/Basic/FlaggedPointer.h @@ -1,8 +1,8 @@ -//===- FlaggedPointer.h - Explicit pointer tagging container ----*- C++ -*-===// +//===--- FlaggedPointer.h - Explicit pointer tagging container --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/JSONSerialization.h b/include/swift/Basic/JSONSerialization.h index 00946e705ff0a..478ecdf6111e5 100644 --- a/include/swift/Basic/JSONSerialization.h +++ b/include/swift/Basic/JSONSerialization.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -398,7 +398,7 @@ class Output { template void processKeyWithDefault(const char *Key, Optional &Val, const Optional &DefaultValue, bool Required) { - assert(DefaultValue.hasValue() == false && + assert(!DefaultValue.hasValue() && "Optional shouldn't have a value!"); void *SaveInfo; bool UseDefault; @@ -425,8 +425,7 @@ class Output { SaveInfo) ) { jsonize(*this, Val, Required); this->postflightKey(SaveInfo); - } - else { + } else { if ( UseDefault ) Val = DefaultValue; } @@ -614,7 +613,7 @@ operator<<(Output &yout, T &map) { return yout; } -// Define non-member operator<< so that Output can stream out a array. +// Define non-member operator<< so that Output can stream out an array. template inline typename diff --git a/include/swift/Basic/LLVM.h b/include/swift/Basic/LLVM.h index 6537f52ad0037..2bfb5b33755b0 100644 --- a/include/swift/Basic/LLVM.h +++ b/include/swift/Basic/LLVM.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/LLVMInitialize.h b/include/swift/Basic/LLVMInitialize.h index 53365f86f5e60..8394b3d557073 100644 --- a/include/swift/Basic/LLVMInitialize.h +++ b/include/swift/Basic/LLVMInitialize.h @@ -1,8 +1,8 @@ -//===--- LLVMInitialize.h -------------------------------------------------===// +//===--- LLVMInitialize.h ---------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index d7bdd65dea672..d8d50174f9dcc 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -41,10 +41,6 @@ namespace swift { /// Language features /// - /// \brief If true, all types are treated as resilient unless declared - /// @_fixed_layout. - bool EnableResilience = false; - /// \brief Disable API availability checking. bool DisableAvailabilityChecking = false; @@ -74,12 +70,6 @@ namespace swift { // FIXME: This should probably be limited to the particular SourceFile. bool Playground = false; - /// Whether to delay adding enum protocol conformances during code - /// completion. This isn't completely correct with multiple files but is - /// currently necessary to get reasonable performance. - // FIXME: remove this when rdar://20047340 is fixed. - bool EnableCodeCompletionDelayedEnumConformanceHack = false; - /// \brief Keep comments during lexing and attach them to declarations. bool AttachCommentsToDecls = false; @@ -130,7 +120,7 @@ namespace swift { /// This is for testing purposes. std::string DebugForbidTypecheckPrefix; - /// Number of paralellel processes performing AST verification. + /// Number of parallel processes performing AST verification. unsigned ASTVerifierProcessCount = 1U; /// ID of the current process for the purposes of AST verification. @@ -150,10 +140,19 @@ namespace swift { /// Should we check the target OSs of serialized modules to see that they're /// new enough? bool EnableTargetOSChecking = true; - - /// Don't mangle the Self type as part of declaration manglings. - bool DisableSelfTypeMangling = true; - + + /// Whether we're omitting needless words when importing Objective-C APIs. + /// + /// The vast majority of the logic for omitting needless words is + /// centralized in the Clang importer. However, there are a few + /// places elsewhere in the compiler that specifically reference + /// Objective-C entities whose names are affected by + /// omit-needless-words. + bool OmitNeedlessWords = false; + + /// Enable the Swift 3 migration via Fix-Its. + bool Swift3Migration = false; + /// Sets the target we are building for and updates configuration options /// to match. /// diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 95c3e5c7ad0a3..75a9e8643ca02 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -1,8 +1,8 @@ -//===--- Lazy.h - A lazily-initialized object -----------------------------===// +//===--- Lazy.h - A lazily-initialized object -------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Malloc.h b/include/swift/Basic/Malloc.h index 2ac42e6ef5a79..1f11c133251a0 100644 --- a/include/swift/Basic/Malloc.h +++ b/include/swift/Basic/Malloc.h @@ -1,8 +1,8 @@ -//===- Malloc.h - Aligned malloc interface ----------------------*- C++ -*-===// +//===--- Malloc.h - Aligned malloc interface --------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/NullablePtr.h b/include/swift/Basic/NullablePtr.h index c39071dc35ac6..8f827a4625f72 100644 --- a/include/swift/Basic/NullablePtr.h +++ b/include/swift/Basic/NullablePtr.h @@ -1,8 +1,8 @@ -//===- NullablePtr.h - A pointer that allows null ---------------*- C++ -*-===// +//===--- NullablePtr.h - A pointer that allows null -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/OptionSet.h b/include/swift/Basic/OptionSet.h index 977527e9b19c6..c2763fdf7b600 100644 --- a/include/swift/Basic/OptionSet.h +++ b/include/swift/Basic/OptionSet.h @@ -1,8 +1,8 @@ -//===-- OptionSet.h - Sets of boolean options -------------------*- C++ -*-===// +//===--- OptionSet.h - Sets of boolean options ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/OptionalEnum.h b/include/swift/Basic/OptionalEnum.h index cfcd34e9b4e90..3d594ab4d998e 100644 --- a/include/swift/Basic/OptionalEnum.h +++ b/include/swift/Basic/OptionalEnum.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Platform.h b/include/swift/Basic/Platform.h index c60444a42ebfe..4b151a7dbc4a4 100644 --- a/include/swift/Basic/Platform.h +++ b/include/swift/Basic/Platform.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/PointerIntEnum.h b/include/swift/Basic/PointerIntEnum.h new file mode 100644 index 0000000000000..ce8471cc070b6 --- /dev/null +++ b/include/swift/Basic/PointerIntEnum.h @@ -0,0 +1,225 @@ +//===--- PointerIntEnum.h ---------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include +#include +#include +#include +#include +#include + +namespace swift { + +/// A tiny meta function to compute the log2 of a compile time constant. +/// +/// *NOTE* This will be in an updated version of LLVM so this should be removed +/// at that point in time. +template +struct ConstantLog2 + : std::integral_constant::value + 1> {}; +template <> struct ConstantLog2<1> : std::integral_constant {}; + +/// A meta function for computing at compile time cleanly the value for an index +/// kind's value without using cpp macros. +template +struct PointerIntEnumIndexKindValue + : std::integral_constant::value)) | + unsigned(EnumTy::FirstIndexKind)> {}; + +/// A pointer sized ADT that is able to compactly represent a Swift like enum +/// that can contain both Integer and Pointer payloads. It attempts to optimize +/// for the case of being able to represent as many pointer cases as possible +/// while allowing for indices to be stored as well. Without any loss of +/// generality assume that T* is our stored pointer. Then this is done as +/// follows: +/// +/// 1. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are not all +/// set to 1 represent an enum with a pointer case. This means that one can have +/// at most ((1 << num_tagged_bits(T*)) - 2) enum cases associated with +/// pointers. +/// +/// 2. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are all set +/// is either an invalid PointerIntEnum or an index. +/// +/// 3. A PointerIntEnum with all bits set is an invalid PointerIntEnum. +/// +/// 4. A PointerIntEnum for which bits [0, (num_tagged_bits(T*)-1)] are all set +/// but for which the upper bits are not all set is an index enum. The case bits +/// for the index PointerIntEnum are stored in bits [num_tagged_bits(T*), +/// num_tagged_bits(T*) + num_index_case_bits]. Then the actual index is stored +/// in the remaining top bits. For the case in which this is used in swift +/// currently, we use 3 index bits meaning that on a 32 bit system we have 26 +/// bits for representing indices meaning we can represent indices up to +/// 67_108_862. Any index larger than that will result in an invalid +/// PointerIntEnum. On 64 bit we have many more bits than that. +/// +/// By using this representation, we can make PointerIntEnum a true value type +/// that is trivially constructible and destructible without needing to malloc +/// memory. +/// +/// In order for all of this to work, the user of this needs to construct an +/// enum with the appropriate case structure that allows the data structure to +/// determine what cases are pointer and which are indices. For instance the one +/// used by Projection in swift is: +/// +/// enum class NewProjectionKind : unsigned { +/// // PointerProjectionKinds +/// Upcast = 0, +/// RefCast = 1, +/// BitwiseCast = 2, +/// FirstPointerKind = Upcast, +/// LastPointerKind = BitwiseCast, +/// +/// +/// // This needs to be set to ((1 << num_tagged_bits(T*)) - 1). It +/// // represents the first NonPointerKind. +/// FirstIndexKind = 7, +/// +/// // Index Projection Kinds +/// Struct = PointerIntEnumIndexKindValue<0, EnumTy>::value, +/// Tuple = PointerIntEnumIndexKindValue<1, EnumTy>::value, +/// Index = PointerIntEnumIndexKindValue<2, EnumTy>::value, +/// Class = PointerIntEnumIndexKindValue<3, EnumTy>::value, +/// Enum = PointerIntEnumIndexKindValue<4, EnumTy>::value, +/// LastIndexKind = Enum, +/// }; +/// +template > +class PointerIntEnum { + + // Make sure that the enum fits our requirements. + static_assert(unsigned(EnumTy::FirstIndexKind) == + ((1U << NumPointerKindBits) - 1U), + "Invalid Enum"); + static_assert(unsigned(EnumTy::FirstIndexKind) <= + unsigned(EnumTy::LastIndexKind), + "Invalid Enum"); + static_assert(unsigned(EnumTy::FirstPointerKind) <= + unsigned(EnumTy::LastPointerKind), + "Invalid Enum"); + static_assert(unsigned(EnumTy::LastPointerKind) < + unsigned(EnumTy::FirstIndexKind), + "Invalid Enum"); + + /// The offset in bits where an index would be stored. + static constexpr unsigned IndexShiftOffset = + NumIndexKindBits + NumPointerKindBits; + + /// The number of bits in a PointerIntEnum that can be used to store indices. + static constexpr unsigned NumIndexBits = + sizeof(uintptr_t) * CHAR_BIT - IndexShiftOffset; + + /// The maximum index that can be stored for an index PointerIntEnum case. + static constexpr uintptr_t MaxIndex = (uintptr_t(1) << NumIndexBits) - 2; + + /// The bit representation of an Invalid PointerIntEnum's storage. + static constexpr uintptr_t InvalidStorage = uintptr_t(0) - 1; + + /// The pointer sized type used for the actual storage. + uintptr_t Storage; + +public: + PointerIntEnum() : Storage(InvalidStorage) {} + + /// Initialize this PointerIntEnum with the kind \p Kind and the Pointer \p + /// Ptr. + PointerIntEnum(EnumTy Kind, uintptr_t NewIndex) { + // If we can not represent this index, make the PointerIntEnum invalid. + if (NewIndex > MaxIndex) { + Storage = InvalidStorage; + return; + } + + Storage = uintptr_t(Kind) | (NewIndex << IndexShiftOffset); + } + + /// Initialize this PointerIntEnum with the kind \p Kind and the Pointer \p + /// Ptr. + PointerIntEnum(EnumTy Kind, PointerTy Ptr) { + void *VoidPtr = PtrTraits::getAsVoidPointer(Ptr); + + // Make sure the pointer is at least aligned to NumPointerKindBits. + assert((uintptr_t(VoidPtr) & ((1 << NumPointerKindBits) - 1)) == 0); + // Make sure that Kind is a PointerKind. + assert(unsigned(Kind) >= unsigned(EnumTy::FirstPointerKind)); + assert(unsigned(Kind) <= unsigned(EnumTy::LastPointerKind)); + + Storage = uintptr_t(VoidPtr) | uintptr_t(Kind); + } + + PointerIntEnum(PointerIntEnum &&P) = default; + PointerIntEnum(const PointerIntEnum &P) = default; + ~PointerIntEnum() = default; + PointerIntEnum &operator=(const PointerIntEnum &P) = default; + PointerIntEnum &operator=(PointerIntEnum &&P) = default; + + bool isValid() const { return Storage != InvalidStorage; } + + bool operator==(const PointerIntEnum &Other) const { + // Just compare the raw storage. + return Other.Storage == Storage; + } + + bool operator!=(const PointerIntEnum &Other) const { + return !(*this == Other); + } + + /// \returns the kind of the enum if the enum is valid. Returns None if the + /// enum is invalid. + Optional getKind() const { + if (!isValid()) + return None; + + // Check if the bottom pointer bits are all not set. If that is true then we + // know that we have a pointer kind. + unsigned PointerBits = Storage & uintptr_t(EnumTy::FirstIndexKind); + if (PointerBits != unsigned(EnumTy::FirstIndexKind)) { + return EnumTy(PointerBits); + } + + // Otherwise, we have an index kind. Just mask off the actual index bits and + // return the kind. + unsigned Mask = (1 << IndexShiftOffset) - 1; + unsigned MaskedStorage = Storage & Mask; + return EnumTy(MaskedStorage); + } + + /// \returns the index stored in the enum if the enum has an index + /// payload. Asserts if the PointerIntEnum is invalid or has a pointer + /// payload. + uintptr_t getIndex() const { + assert(isValid()); + assert(unsigned(*getKind()) >= unsigned(EnumTy::FirstIndexKind)); + return Storage >> IndexShiftOffset; + } + + /// \returns the pointer stored in the enum if the enum has a pointer + /// payload. Asserts if the PointerIntEnum is invalid or has an index payload. + PointerTy getPointer() const { + assert(isValid()); + assert(unsigned(*getKind()) <= unsigned(EnumTy::LastPointerKind)); + uintptr_t Value = Storage & ~(uintptr_t(EnumTy::FirstIndexKind)); + return PtrTraits::getFromVoidPointer((void *)(Value)); + } + + /// Return the raw storage of the type. Used for testing purposes. + uintptr_t getStorage() const { return Storage; } +}; + +} // end swift namespace diff --git a/include/swift/Basic/PrefixMap.h b/include/swift/Basic/PrefixMap.h index 47e1a55100f73..7841f7267e0f0 100644 --- a/include/swift/Basic/PrefixMap.h +++ b/include/swift/Basic/PrefixMap.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/PrettyStackTrace.h b/include/swift/Basic/PrettyStackTrace.h index 536dc3abae0de..7d94fde0f5306 100644 --- a/include/swift/Basic/PrettyStackTrace.h +++ b/include/swift/Basic/PrettyStackTrace.h @@ -1,8 +1,8 @@ -//===--- PrettyStackTrace.h - Generic stack-trace prettifiers ----*- C++ -*-==// +//===--- PrettyStackTrace.h - Generic stack-trace prettifiers ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/PrimitiveParsing.h b/include/swift/Basic/PrimitiveParsing.h index 90ea9719b5465..bff1e59153e07 100644 --- a/include/swift/Basic/PrimitiveParsing.h +++ b/include/swift/Basic/PrimitiveParsing.h @@ -1,8 +1,8 @@ -//===--- PrimitiveParsing.h - Primitive parsing routines ------------------===// +//===--- PrimitiveParsing.h - Primitive parsing routines --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Program.h b/include/swift/Basic/Program.h index 3d98377e32289..061639afc602c 100644 --- a/include/swift/Basic/Program.h +++ b/include/swift/Basic/Program.h @@ -1,8 +1,8 @@ -//===- swift/Basic/Program.h ------------------------------------*- C++ -*-===// +//===--- Program.h ----------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Punycode.h b/include/swift/Basic/Punycode.h index 3fbfcb09475ca..de7974160aadf 100644 --- a/include/swift/Basic/Punycode.h +++ b/include/swift/Basic/Punycode.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/QuotedString.h b/include/swift/Basic/QuotedString.h index 5fffc896da3c2..cee2a416b6d60 100644 --- a/include/swift/Basic/QuotedString.h +++ b/include/swift/Basic/QuotedString.h @@ -1,8 +1,8 @@ -//===- QuotedString.h - Print a string in double-quotes ---------*- C++ -*-===// +//===--- QuotedString.h - Print a string in double-quotes -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Range.h b/include/swift/Basic/Range.h index 8aaf8a1601802..f27fc738e0428 100644 --- a/include/swift/Basic/Range.h +++ b/include/swift/Basic/Range.h @@ -1,8 +1,8 @@ -//===- Range.h - Classes for conveniently working with ranges ---*- C++ -*-===// +//===--- Range.h - Classes for conveniently working with ranges -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -292,6 +292,11 @@ none_of(Range R, Predicate P) { return std::none_of(R.begin(), R.end(), P); } +template +inline unsigned count_if(Range R, Predicate P) { + return std::count_if(R.begin(), R.end(), P); +} + } // namespace swift #endif diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h index 188ddf26d9505..13e23efdf6555 100644 --- a/include/swift/Basic/RelativePointer.h +++ b/include/swift/Basic/RelativePointer.h @@ -1,8 +1,8 @@ -//===-- RelativePointer.h - Relative Pointer Support ------------*- C++ -*-===// +//===--- RelativePointer.h - Relative Pointer Support -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,16 +23,41 @@ namespace swift { +namespace detail { + +/// Apply a relative offset to a base pointer. The offset is applied to the base +/// pointer using sign-extended, wrapping arithmetic. +template +static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) { + static_assert(std::is_integral::value && + std::is_signed::value, + "offset type should be signed integer"); + + auto base = reinterpret_cast(basePtr); + // We want to do wrapping arithmetic, but with a sign-extended + // offset. To do this in C, we need to do signed promotion to get + // the sign extension, but we need to perform arithmetic on unsigned values, + // since signed overflow is undefined behavior. + auto extendOffset = (uintptr_t)(intptr_t)offset; + return base + extendOffset; +} + +} // namespace detail + /// A relative reference to an object stored in memory. The reference may be /// direct or indirect, and uses the low bit of the (assumed at least /// 2-byte-aligned) pointer to differentiate. -template +template class RelativeIndirectablePointer { private: + static_assert(std::is_integral::value && + std::is_signed::value, + "offset type should be signed integer"); + /// The relative offset of the pointer's memory from the `this` pointer. /// If the low bit is clear, this is a direct reference; otherwise, it is /// an indirect reference. - int32_t RelativeOffset; + Offset RelativeOffsetPlusIndirect; /// RelativePointers should appear in statically-generated metadata. They /// shouldn't be constructed or copied. @@ -44,21 +69,25 @@ class RelativeIndirectablePointer { RelativeIndirectablePointer &operator=(const RelativeIndirectablePointer &) = delete; +public: const ValueTy *get() const & { - // The pointer is offset relative to `this`. - auto base = reinterpret_cast(this); - intptr_t address = base + (RelativeOffset & ~1); + // Check for null. + if (Nullable && RelativeOffsetPlusIndirect == 0) + return nullptr; + + Offset offsetPlusIndirect = RelativeOffsetPlusIndirect; + uintptr_t address = detail::applyRelativeOffset(this, + offsetPlusIndirect & ~1); // If the low bit is set, then this is an indirect address. Otherwise, // it's direct. - if (RelativeOffset & 1) { + if (offsetPlusIndirect & 1) { return *reinterpret_cast(address); } else { return reinterpret_cast(address); } } - -public: + operator const ValueTy* () const & { return get(); } @@ -75,11 +104,11 @@ class RelativeIndirectablePointer { /// A relative reference to a function, intended to reference private metadata /// functions for the current executable or dynamic library image from /// position-independent constant data. -template +template class RelativeDirectPointerImpl { private: /// The relative offset of the function's entry point from *this. - int32_t RelativeOffset; + Offset RelativeOffset; /// RelativePointers should appear in statically-generated metadata. They /// shouldn't be constructed or copied. @@ -96,21 +125,30 @@ class RelativeDirectPointerImpl { using PointerTy = T*; PointerTy get() const & { - // The function entry point is addressed relative to `this`. - auto base = reinterpret_cast(this); - intptr_t absolute = base + RelativeOffset; + // Check for null. + if (Nullable && RelativeOffset == 0) + return nullptr; + + // The value is addressed relative to `this`. + uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset); return reinterpret_cast(absolute); } + /// A zero relative offset encodes a null reference. + bool isNull() const & { + return RelativeOffset == 0; + } }; /// A direct relative reference to an object. -template +template class RelativeDirectPointer : - private RelativeDirectPointerImpl + private RelativeDirectPointerImpl { - using super = RelativeDirectPointerImpl; + using super = RelativeDirectPointerImpl; public: + using super::get; + operator typename super::PointerTy() const & { return this->get(); } @@ -122,16 +160,20 @@ class RelativeDirectPointer : const typename super::ValueTy *operator->() const & { return this->get(); } + + using super::isNull; }; /// A specialization of RelativeDirectPointer for function pointers, /// allowing for calls. -template -class RelativeDirectPointer : - private RelativeDirectPointerImpl +template +class RelativeDirectPointer : + private RelativeDirectPointerImpl { - using super = RelativeDirectPointerImpl; + using super = RelativeDirectPointerImpl; public: + using super::get; + operator typename super::PointerTy() const & { return this->get(); } @@ -139,6 +181,47 @@ class RelativeDirectPointer : RetTy operator()(ArgTy...arg) { return this->get()(std::forward(arg)...); } + + using super::isNull; +}; + +/// A direct relative reference to an aligned object, with an additional +/// tiny integer value crammed into its low bits. +template +class RelativeDirectPointerIntPair { + Offset RelativeOffsetPlusInt; + + /// RelativePointers should appear in statically-generated metadata. They + /// shouldn't be constructed or copied. + RelativeDirectPointerIntPair() = delete; + RelativeDirectPointerIntPair(RelativeDirectPointerIntPair &&) = delete; + RelativeDirectPointerIntPair(const RelativeDirectPointerIntPair &) = delete; + RelativeDirectPointerIntPair &operator=(RelativeDirectPointerIntPair &&) + = delete; + RelativeDirectPointerIntPair &operator=(const RelativeDirectPointerIntPair&) + = delete; + + static Offset getMask() { + static_assert(alignof(PointeeTy) >= alignof(Offset), + "pointee alignment must be at least as strict as offset type"); + + return alignof(Offset) - 1; + } + +public: + using ValueTy = PointeeTy; + using PointerTy = PointeeTy*; + + PointerTy getPointer() const & { + // The value is addressed relative to `this`. + uintptr_t absolute = detail::applyRelativeOffset(this, + RelativeOffsetPlusInt & ~getMask()); + return reinterpret_cast(absolute); + } + + IntTy getInt() const & { + return IntTy(RelativeOffsetPlusInt & getMask()); + } }; } diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h index 41d3703e946f2..b50af049727cc 100644 --- a/include/swift/Basic/STLExtras.h +++ b/include/swift/Basic/STLExtras.h @@ -1,8 +1,8 @@ -//===- STLExtras.h - additions to the STL -----------------------*- C++ -*-===// +//===--- STLExtras.h - additions to the STL ---------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -352,7 +352,7 @@ makeTransformRange(Range range, Operation op) { } /// An iterator that filters and transforms the results of an -/// underlying forward iterator based on an transformation from the underlying +/// underlying forward iterator based on a transformation from the underlying /// value type to an optional result type. /// /// \tparam Iterator the underlying iterator. @@ -451,9 +451,9 @@ makeOptionalTransformIterator(Iterator current, Iterator end, } /// A range filtered and transformed by the optional transform. -template +template class OptionalTransformRange { - typedef typename Range::iterator Iterator; Iterator First, Last; OptionalTransform Op; diff --git a/include/swift/Basic/SourceLoc.h b/include/swift/Basic/SourceLoc.h index 050033a0c64fc..debb69396b544 100644 --- a/include/swift/Basic/SourceLoc.h +++ b/include/swift/Basic/SourceLoc.h @@ -1,8 +1,8 @@ -//===- SourceLoc.h - Source Locations and Ranges ----------------*- C++ -*-===// +//===--- SourceLoc.h - Source Locations and Ranges --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 5ffbe7ab861a5..61ef42d40eb09 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/StringExtras.h b/include/swift/Basic/StringExtras.h index 7d297ce92a0f0..b6da9d6d8e2a2 100644 --- a/include/swift/Basic/StringExtras.h +++ b/include/swift/Basic/StringExtras.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,6 +28,11 @@ #include namespace swift { + /// Determine whether the given string can be an argument label. + /// + /// \seealso Token::canBeArgumentLabel() + bool canBeArgumentLabel(StringRef identifier); + /// Describes the kind of preposition a word is. enum PrepositionKind { PK_None = 0, @@ -44,7 +49,6 @@ namespace swift { Unknown, Preposition, Verb, - AuxiliaryVerb, Gerund, }; @@ -281,6 +285,10 @@ enum class NameRole { /// The base name of a function or method. BaseName, + /// The base name of a method where the omission type name is the + /// 'self' type. + BaseNameSelf, + /// The first parameter of a function or method. FirstParameter, diff --git a/include/swift/Basic/SuccessorMap.h b/include/swift/Basic/SuccessorMap.h index 7cace7ae8e73f..bc186756de561 100644 --- a/include/swift/Basic/SuccessorMap.h +++ b/include/swift/Basic/SuccessorMap.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -233,7 +233,7 @@ class SuccessorMap { return foundUpperBound; }; - // A heler to finish the operation, given that 'cur' is an upper bound. + // A helper to finish the operation, given that 'cur' is an upper bound. auto finishWithUpperBound = [&] { assert(cur->Left == nullptr); return reassemble(true); diff --git a/include/swift/Basic/TaskQueue.h b/include/swift/Basic/TaskQueue.h index 2f0a8d2adde2f..27e9e6e2c597e 100644 --- a/include/swift/Basic/TaskQueue.h +++ b/include/swift/Basic/TaskQueue.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/ThreadSafeRefCounted.h b/include/swift/Basic/ThreadSafeRefCounted.h index 8bdc3d964e644..f519f7eb60883 100644 --- a/include/swift/Basic/ThreadSafeRefCounted.h +++ b/include/swift/Basic/ThreadSafeRefCounted.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Timer.h b/include/swift/Basic/Timer.h new file mode 100644 index 0000000000000..b3efe2f7c4cad --- /dev/null +++ b/include/swift/Basic/Timer.h @@ -0,0 +1,50 @@ +//===--- Timer.h - Shared timers for compilation phases ---------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_TIMER_H +#define SWIFT_BASIC_TIMER_H + +#include "swift/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Timer.h" + +namespace swift { + /// A convenience class for declaring a timer that's part of the Swift + /// compilation timers group. + class SharedTimer { + enum class State { + Initial, + Skipped, + Enabled + }; + static State CompilationTimersEnabled; + + Optional Timer; + + public: + explicit SharedTimer(StringRef name) { + if (CompilationTimersEnabled == State::Enabled) + Timer.emplace(name, StringRef("Swift compilation")); + else + CompilationTimersEnabled = State::Skipped; + } + + /// Must be called before any SharedTimers have been created. + static void enableCompilationTimers() { + assert(CompilationTimersEnabled != State::Skipped && + "a timer has already been created"); + CompilationTimersEnabled = State::Enabled; + } + }; +} + +#endif // SWIFT_BASIC_TIMER_H diff --git a/include/swift/Basic/TreeScopedHashTable.h b/include/swift/Basic/TreeScopedHashTable.h index 7faa9a6a818d7..2d03b20aba501 100644 --- a/include/swift/Basic/TreeScopedHashTable.h +++ b/include/swift/Basic/TreeScopedHashTable.h @@ -1,8 +1,8 @@ -//===- TreeScopedHashTable.h - A scoped hash table with multiple active scopes -===// +//===--- TreeScopedHashTable.h - Hash table with multiple active scopes ---===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/UUID.h b/include/swift/Basic/UUID.h index efd7948f5a035..d88fd000dc8c4 100644 --- a/include/swift/Basic/UUID.h +++ b/include/swift/Basic/UUID.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/Unicode.h b/include/swift/Basic/Unicode.h index 7a4219284df20..988a4c0da8f32 100644 --- a/include/swift/Basic/Unicode.h +++ b/include/swift/Basic/Unicode.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Basic/ValueEnumerator.h b/include/swift/Basic/ValueEnumerator.h index 946fb3d4c718c..201c692740e3d 100644 --- a/include/swift/Basic/ValueEnumerator.h +++ b/include/swift/Basic/ValueEnumerator.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,7 @@ namespace swift { template class ValueEnumerator { /// A running counter to enumerate values. - IndexTy counter; + IndexTy counter = 0; /// Maps values to unique integers. llvm::DenseMap ValueToIndex; diff --git a/include/swift/Basic/Varint.h b/include/swift/Basic/Varint.h new file mode 100644 index 0000000000000..c53429747bad7 --- /dev/null +++ b/include/swift/Basic/Varint.h @@ -0,0 +1,110 @@ +//===--- Varint.h - Variable length integer encoding ------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file Varint.h +/// \brief Defines transformations of integral types to/from variable length +/// 7-bit encoding. +//===----------------------------------------------------------------------===// + +#include +#include + +#include "llvm/ADT/SmallVector.h" + +#ifndef SWIFT_BASIC_VARINT_H +#define SWIFT_BASIC_VARINT_H + +namespace swift { +namespace Varint { + +/// Encode an unsigned integral type to a variable length 7-bit-encoded sequence +/// of bytes. +template +llvm::SmallVector encode( + typename std::enable_if< + std::is_integral::value && std::is_unsigned::value, T + >::type i +) { + llvm::SmallVector bytes; + do { + uint8_t b = i & 0x7F; + i >>= 7; + if (i) + b |= 0x80; + bytes.push_back(b); + } while (i); + return bytes; +} + +/// Encode a signed integral type to a variable length 7-bit-encoded sequence of +/// bytes. +/// +/// This transforms the signed value into an unsigned value and delegates +/// to the unsigned version of `encode`. +template +llvm::SmallVector encode( + typename std::enable_if< + std::is_integral::value && std::is_signed::value, T + >::type i +) { + // Zig-zag encode the signed integer into the unsigned integer type. + // Negative numbers are encoded as unsigned odd numbers in the + // unsigned type, positive numbers are even. This prioritizes the + // smaller numbers around zero, while making it compatible with + // 7-bit encoding: + // -3 -> 5 + // -2 -> 3 + // -1 -> 1 + // 0 -> 0 + // 1 -> 2 + // 2 -> 4 + // 3 -> 6 + typename std::make_unsigned::type z = i < 0 ? ~(i << 1) : (i << 1); + return encode(z); +} + +/// Decode a variable length 7-bit encoded sequence of bytes to an unsigned +/// integer type. +template +typename std::enable_if< + std::is_integral::value && std::is_unsigned::value, T +>::type +decode(const uint8_t *bytes) { + size_t i = 0; + size_t shift = 0; + T decoded = 0; + do { + decoded |= T(bytes[i] & 0x7F) << shift; + shift += 7; + } while (bytes[i++] & 0x80); + return decoded; +} + +/// Decode a variable length 7-bit-encoded sequence of bytes to a signed integer +/// type. +/// +/// This delegates to the unsigned version of `decode` and transforms the +/// value back into its signed version. +template +typename std::enable_if< + std::is_integral::value && std::is_signed::value, T +>::type +decode(const uint8_t *bytes) { + auto decoded = decode::type>(bytes); + // Zig-zag decode back into the signed integer type. + return decoded & 1 ? ~(decoded >> 1) : (decoded >> 1); +} + +} // end namespace Varint +} // end namespace swift + +#endif // SWIFT_BASIC_VARINT_H diff --git a/include/swift/Basic/Version.h b/include/swift/Basic/Version.h index b4ffcb6e84e4a..c88702bf7585a 100644 --- a/include/swift/Basic/Version.h +++ b/include/swift/Basic/Version.h @@ -1,8 +1,8 @@ -//===- Version.h - Swift Version Number -------------------------*- C++ -*-===// +//===--- Version.h - Swift Version Number -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,6 +21,7 @@ #include +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" @@ -97,15 +98,20 @@ class Version { /// Parse a generic version string of the format [0-9]+(.[0-9]+)* /// /// Version components can be any unsigned 64-bit number. - static Version parseVersionString(llvm::StringRef VersionString, - SourceLoc Loc, - DiagnosticEngine *Diags); + static llvm::Optional parseVersionString( + llvm::StringRef VersionString, + SourceLoc Loc, + DiagnosticEngine *Diags); /// Returns a version from the currently defined SWIFT_COMPILER_VERSION. /// /// If SWIFT_COMPILER_VERSION is undefined, this will return the empty /// compiler version. static Version getCurrentCompilerVersion(); + + /// Returns a version from the currently defined SWIFT_VERSION_MAJOR and + /// SWIFT_VERSION_MINOR. + static Version getCurrentLanguageVersion(); }; bool operator>=(const Version &lhs, const Version &rhs); diff --git a/include/swift/Basic/type_traits.h b/include/swift/Basic/type_traits.h index 1270bb5402c71..8aee295aa6de8 100644 --- a/include/swift/Basic/type_traits.h +++ b/include/swift/Basic/type_traits.h @@ -1,8 +1,8 @@ -//===--- type_traits.h - Type traits -----------------------------*- C++ -*-==// +//===--- type_traits.h - Type traits ----------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,7 @@ namespace swift { -/// Same as \c std::is_trivially_copyable, which we can not use directly +/// Same as \c std::is_trivially_copyable, which we cannot use directly /// because it is not implemented yet in all C++11 standard libraries. /// /// Unlike \c llvm::isPodLike, this trait should produce a precise result and diff --git a/include/swift/ClangImporter/BuiltinMappedTypes.def b/include/swift/ClangImporter/BuiltinMappedTypes.def index 9fd1b2e0a420b..00825c8d8187b 100644 --- a/include/swift/ClangImporter/BuiltinMappedTypes.def +++ b/include/swift/ClangImporter/BuiltinMappedTypes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 8720ea5716573..cb4a65a0d1519 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -1,8 +1,8 @@ -//===--- ClangImporter.cpp - Import Clang Modules --------------*- C++ -*--===// +//===--- ClangImporter.h - Import Clang Modules -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -114,14 +114,7 @@ class ClangImporter final : public ClangModuleLoader { /// \brief Look for declarations associated with the given name. /// /// \param name The name we're searching for. - void lookupValue(Identifier name, VisibleDeclConsumer &consumer); - - /// \brief Look for visible declarations in the Clang translation unit and - /// import them as Swift decls. - /// - /// \param Consumer The VisibleDeclConsumer that will be fed decls as they - /// are found and imported. - void lookupVisibleDecls(VisibleDeclConsumer &Consumer) const; + void lookupValue(DeclName name, VisibleDeclConsumer &consumer); /// Look for textually included declarations from the bridging header. /// diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h index 283109ed284b9..506dfc0a00a64 100644 --- a/include/swift/ClangImporter/ClangImporterOptions.h +++ b/include/swift/ClangImporter/ClangImporterOptions.h @@ -1,8 +1,8 @@ -//===-- ClangImporterOptions.h ---------------------------------*- C++ -*--===// +//===--- ClangImporterOptions.h ---------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index e797db9ac64f9..c12eef8dd6717 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -73,6 +73,10 @@ class ClangModuleUnit final : public LoadedFile { lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, SmallVectorImpl &decls) const override; + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + virtual void getTopLevelDecls(SmallVectorImpl &results) const override; virtual void getDisplayDecls(SmallVectorImpl &results) const override; diff --git a/include/swift/ClangImporter/SIMDMappedTypes.def b/include/swift/ClangImporter/SIMDMappedTypes.def index 814f555d9beb5..d020788ae169f 100644 --- a/include/swift/ClangImporter/SIMDMappedTypes.def +++ b/include/swift/ClangImporter/SIMDMappedTypes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Driver/Action.h b/include/swift/Driver/Action.h index 23c5b7d724002..2da8575a047a3 100644 --- a/include/swift/Driver/Action.h +++ b/include/swift/Driver/Action.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -54,40 +54,27 @@ class Action { static const char *getClassName(ActionClass AC); private: - ActionClass Kind; - types::ID Type; - - ActionList Inputs; - unsigned OwnsInputs : 1; + unsigned Kind : 4; + unsigned Type : 27; protected: Action(ActionClass Kind, types::ID Type) - : Kind(Kind), Type(Type), OwnsInputs(true) {} - Action(ActionClass Kind, ArrayRef Inputs, types::ID Type) - : Kind(Kind), Type(Type), Inputs(Inputs.begin(), Inputs.end()), - OwnsInputs(true) {} - -public: - virtual ~Action(); - - const char *getClassName() const { return Action::getClassName(getKind()); } + : OwnsInputs(true), Kind(Kind), Type(Type) { + assert(Kind == getKind() && "not enough bits"); + assert(Type == getType() && "not enough bits"); + } bool getOwnsInputs() const { return OwnsInputs; } void setOwnsInputs(bool Value) { OwnsInputs = Value; } - ActionClass getKind() const { return Kind; } - types::ID getType() const { return Type; } - - ArrayRef getInputs() const { return Inputs; } - void addInput(Action *Input) { Inputs.push_back(Input); } +public: + virtual ~Action() = default; - size_type size() const { return Inputs.size(); } + const char *getClassName() const { return Action::getClassName(getKind()); } - iterator begin() { return Inputs.begin(); } - iterator end() { return Inputs.end(); } - const_iterator begin() const { return Inputs.begin(); } - const_iterator end() const { return Inputs.end(); } + ActionClass getKind() const { return static_cast(Kind); } + types::ID getType() const { return static_cast(Type); } }; class InputAction : public Action { @@ -105,21 +92,37 @@ class InputAction : public Action { }; class JobAction : public Action { + ActionList Inputs; virtual void anchor(); protected: JobAction(ActionClass Kind, ArrayRef Inputs, types::ID Type) - : Action(Kind, Inputs, Type) {} + : Action(Kind, Type), Inputs(Inputs.begin(), Inputs.end()) {} public: - static bool classof(const Action *A) { - return (A->getKind() >= ActionClass::JobFirst && - A->getKind() <= ActionClass::JobLast); - } - + ~JobAction() override; + + bool getOwnsInputs() const { return Action::getOwnsInputs(); } + void setOwnsInputs(bool Value) { Action::setOwnsInputs(Value); } + + ArrayRef getInputs() const { return Inputs; } + void addInput(Action *Input) { Inputs.push_back(Input); } + + size_type size() const { return Inputs.size(); } + + iterator begin() { return Inputs.begin(); } + iterator end() { return Inputs.end(); } + const_iterator begin() const { return Inputs.begin(); } + const_iterator end() const { return Inputs.end(); } + // Returns the index of the Input action's output file which is used as // (single) input to this action. Most actions produce only a single output // file, so we return 0 by default. virtual int getInputIndex() const { return 0; } + + static bool classof(const Action *A) { + return (A->getKind() >= ActionClass::JobFirst && + A->getKind() <= ActionClass::JobLast); + } }; class CompileJobAction : public JobAction { diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h index 1c97b80ba9eab..9af09e2cdece2 100644 --- a/include/swift/Driver/Compilation.h +++ b/include/swift/Driver/Compilation.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,6 +18,7 @@ #define SWIFT_DRIVER_COMPILATION_H #include "swift/Driver/Job.h" +#include "swift/Driver/Util.h" #include "swift/Basic/ArrayRefView.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/DenseSet.h" @@ -56,12 +57,6 @@ enum class OutputLevel { class Compilation { private: - /// The driver we were created by. - const Driver &TheDriver; - - /// The default tool chain. - const ToolChain &DefaultToolChain; - /// The DiagnosticEngine to which this Compilation should emit diagnostics. DiagnosticEngine &Diags; @@ -72,11 +67,21 @@ class Compilation { SmallVector, 32> Jobs; /// The original (untranslated) input argument list. - std::unique_ptr InputArgs; + /// + /// This is only here for lifetime management. Any inspection of + /// command-line arguments should use #getArgs(). + std::unique_ptr RawInputArgs; /// The translated input arg list. std::unique_ptr TranslatedArgs; + /// A list of input files and their associated types. + InputFileList InputFilesWithTypes; + + /// When non-null, a temporary file containing all input .swift files. + /// Used for large compilations to avoid overflowing argv. + const char *AllSourceFilesPath = nullptr; + /// Temporary files that should be cleaned up after the compilation finishes. /// /// These apply whether the compilation succeeds or fails. @@ -132,10 +137,10 @@ class Compilation { } public: - Compilation(const Driver &D, const ToolChain &DefaultToolChain, - DiagnosticEngine &Diags, OutputLevel Level, + Compilation(DiagnosticEngine &Diags, OutputLevel Level, std::unique_ptr InputArgs, std::unique_ptr TranslatedArgs, + InputFileList InputsWithTypes, StringRef ArgsHash, llvm::sys::TimeValue StartTime, unsigned NumberOfParallelCommands = 1, bool EnableIncrementalBuild = false, @@ -143,10 +148,6 @@ class Compilation { bool SaveTemps = false); ~Compilation(); - const Driver &getDriver() const { return TheDriver; } - - const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } - ArrayRefView, const Job *, Compilation::unwrap> getJobs() const { return llvm::makeArrayRef(Jobs); @@ -163,9 +164,8 @@ class Compilation { TempFilePaths.end(); } - const llvm::opt::InputArgList &getInputArgs() const { return *InputArgs; } - const llvm::opt::DerivedArgList &getArgs() const { return *TranslatedArgs; } + ArrayRef getInputFiles() const { return InputFilesWithTypes; } unsigned getNumberOfParallelCommands() const { return NumberOfParallelCommands; @@ -198,6 +198,15 @@ class Compilation { LastBuildTime = time; } + /// Requests the path to a file containing all input source files. This can + /// be shared across jobs. + /// + /// If this is never called, the Compilation does not bother generating such + /// a file. + /// + /// \sa types::isPartOfSwiftCompilation + const char *getAllSourcesPath() const; + /// Asks the Compilation to perform the Jobs which it knows about. /// \returns result code for the Compilation's Jobs; 0 indicates success and /// -2 indicates that one of the Compilation's Jobs crashed during execution diff --git a/include/swift/Driver/DependencyGraph.h b/include/swift/Driver/DependencyGraph.h index b6c786b16cb1a..6348f7009424e 100644 --- a/include/swift/Driver/DependencyGraph.h +++ b/include/swift/Driver/DependencyGraph.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -94,7 +94,7 @@ class DependencyGraphImpl { static_assert(std::is_move_constructible::value, ""); /// The "outgoing" edge map. This lists all outgoing (kind, string) edges - /// representing satisified dependencies from a particular node. + /// representing satisfied dependencies from a particular node. /// /// For multiple outgoing edges with the same string, the kinds are combined /// into one field. diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h index 3057df7e30665..43a544cea58ae 100644 --- a/include/swift/Driver/Driver.h +++ b/include/swift/Driver/Driver.h @@ -1,8 +1,8 @@ -//===-- Driver.h - Swift compiler driver -----------------------*- C++ -*--===// +//===--- Driver.h - Swift compiler driver -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,6 +44,7 @@ namespace swift { namespace driver { class Compilation; class Job; + class JobAction; class OutputFileMap; class ToolChain; @@ -158,9 +159,6 @@ class Driver { mutable llvm::StringMap ToolChains; public: - typedef std::pair InputPair; - typedef SmallVector InputList; - Driver(StringRef DriverExecutable, StringRef Name, ArrayRef Args, DiagnosticEngine &Diags); ~Driver(); @@ -205,7 +203,7 @@ class Driver { /// \param[out] Inputs The list in which to store the resulting compilation /// inputs. void buildInputs(const ToolChain &TC, const llvm::opt::DerivedArgList &Args, - InputList &Inputs) const; + InputFileList &Inputs) const; /// Construct the OutputInfo for the driver from the given arguments. /// @@ -216,7 +214,7 @@ class Driver { /// information. void buildOutputInfo(const ToolChain &TC, const llvm::opt::DerivedArgList &Args, - const InputList &Inputs, OutputInfo &OI) const; + const InputFileList &Inputs, OutputInfo &OI) const; /// Construct the list of Actions to perform for the given arguments, /// which are only done for a single architecture. @@ -231,8 +229,8 @@ class Driver { /// need to be rebuilt. /// \param[out] Actions The list in which to store the resulting Actions. void buildActions(const ToolChain &TC, const llvm::opt::DerivedArgList &Args, - const InputList &Inputs, const OutputInfo &OI, - const OutputFileMap *OFM, InputInfoMap *OutOfDateMap, + const InputFileList &Inputs, const OutputInfo &OI, + const OutputFileMap *OFM, const InputInfoMap *OutOfDateMap, ActionList &Actions) const; /// Construct the OutputFileMap for the driver from the given arguments. @@ -243,11 +241,13 @@ class Driver { /// OutputInfo. /// /// \param Actions The Actions for which Jobs should be generated. - /// \param OI The OutputInfo for which Jobs should be generated - /// \param OFM The OutputFileMap for which Jobs should be generated - /// \param[out] C The Compilation to which Jobs should be added + /// \param OI The OutputInfo for which Jobs should be generated. + /// \param OFM The OutputFileMap for which Jobs should be generated. + /// \param TC The ToolChain to build Jobs with. + /// \param[out] C The Compilation to which Jobs should be added. void buildJobs(const ActionList &Actions, const OutputInfo &OI, - const OutputFileMap *OFM, Compilation &C) const; + const OutputFileMap *OFM, const ToolChain &TC, + Compilation &C) const; /// A map for caching Jobs for a given Action/ToolChain pair using JobCacheMap = @@ -257,7 +257,7 @@ class Driver { /// input Jobs. /// /// \param C The Compilation which this Job will eventually be part of - /// \param A The Action for which a Job should be created + /// \param JA The Action for which a Job should be created /// \param OI The OutputInfo for which a Job should be created /// \param OFM The OutputFileMap for which a Job should be created /// \param TC The tool chain which should be used to create the Job @@ -265,7 +265,7 @@ class Driver { /// \param JobCache maps existing Action/ToolChain pairs to Jobs /// /// \returns a Job for the given Action/ToolChain pair - Job *buildJobsForAction(Compilation &C, const Action *A, + Job *buildJobsForAction(Compilation &C, const JobAction *JA, const OutputInfo &OI, const OutputFileMap *OFM, const ToolChain &TC, bool AtTopLevel, JobCacheMap &JobCache) const; diff --git a/include/swift/Driver/FrontendUtil.h b/include/swift/Driver/FrontendUtil.h index 5e9791840936b..cb18368c8f379 100644 --- a/include/swift/Driver/FrontendUtil.h +++ b/include/swift/Driver/FrontendUtil.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Driver/Job.h b/include/swift/Driver/Job.h index dd72770a4fd81..8f7b774747da1 100644 --- a/include/swift/Driver/Job.h +++ b/include/swift/Driver/Job.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,9 +30,8 @@ namespace swift { namespace driver { -class Action; -class InputAction; class Job; +class JobAction; class CommandOutput { types::ID PrimaryOutputType; @@ -92,7 +91,7 @@ class Job { private: /// The action which caused the creation of this Job, and the conditions /// under which it must be run. - llvm::PointerIntPair SourceAndCondition; + llvm::PointerIntPair SourceAndCondition; /// The list of other Jobs which are inputs to this Job. SmallVector Inputs; @@ -114,25 +113,33 @@ class Job { /// These strings must be kept alive as long as the Job is alive. EnvironmentVector ExtraEnvironment; + /// Whether the job wants a list of input or output files created. + FilelistInfo FilelistFileInfo; + /// The modification time of the main input file, if any. llvm::sys::TimeValue InputModTime = llvm::sys::TimeValue::MaxTime(); public: - Job(const Action &Source, + Job(const JobAction &Source, SmallVectorImpl &&Inputs, std::unique_ptr Output, const char *Executable, llvm::opt::ArgStringList Arguments, - EnvironmentVector ExtraEnvironment = {}) + EnvironmentVector ExtraEnvironment = {}, + FilelistInfo Info = {}) : SourceAndCondition(&Source, Condition::Always), Inputs(std::move(Inputs)), Output(std::move(Output)), Executable(Executable), Arguments(std::move(Arguments)), - ExtraEnvironment(std::move(ExtraEnvironment)) {} + ExtraEnvironment(std::move(ExtraEnvironment)), + FilelistFileInfo(std::move(Info)) {} - const Action &getSource() const { return *SourceAndCondition.getPointer(); } + const JobAction &getSource() const { + return *SourceAndCondition.getPointer(); + } const char *getExecutable() const { return Executable; } const llvm::opt::ArgStringList &getArguments() const { return Arguments; } + FilelistInfo getFilelistInfo() const { return FilelistFileInfo; } ArrayRef getInputs() const { return Inputs; } const CommandOutput &getOutput() const { return *Output; } diff --git a/include/swift/Driver/OutputFileMap.h b/include/swift/Driver/OutputFileMap.h index 4afe6d8eb835f..fe6ff7cbaa76e 100644 --- a/include/swift/Driver/OutputFileMap.h +++ b/include/swift/Driver/OutputFileMap.h @@ -1,8 +1,8 @@ -//===-- OutputFileMap.h - Driver output file map ---------------*- C++ -*--===// +//===--- OutputFileMap.h - Driver output file map ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Driver/ParseableOutput.h b/include/swift/Driver/ParseableOutput.h index 6064a97e29221..d878614a0be2c 100644 --- a/include/swift/Driver/ParseableOutput.h +++ b/include/swift/Driver/ParseableOutput.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index 79299d89a18e7..e2aee67bbedd6 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,12 +50,39 @@ class ToolChain { constexpr static const char * const SWIFT_EXECUTABLE_NAME = "swift"; /// Packs together the supplementary information about the job being created. - struct JobContext { + class JobContext { + private: + Compilation &C; + + public: ArrayRef Inputs; - const CommandOutput &Output; ArrayRef InputActions; - const llvm::opt::ArgList &Args; + const CommandOutput &Output; const OutputInfo &OI; + + /// The arguments to the driver. Can also be used to create new strings with + /// the same lifetime. + /// + /// This just caches C.getArgs(). + const llvm::opt::ArgList &Args; + + public: + JobContext(Compilation &C, ArrayRef Inputs, + ArrayRef InputActions, + const CommandOutput &Output, const OutputInfo &OI); + + /// Forwards to Compilation::getInputFiles. + ArrayRef getTopLevelInputFiles() const; + + /// Forwards to Compilation::getAllSourcesPath. + const char *getAllSourcesPath() const; + + /// Creates a new temporary file for use by a job. + /// + /// The returned string already has its lifetime extended to match other + /// arguments. + const char *getTemporaryFilePath(const llvm::Twine &name, + StringRef suffix = "") const; }; /// Packs together information chosen by toolchains to create jobs. @@ -63,10 +90,12 @@ class ToolChain { const char *ExecutableName; llvm::opt::ArgStringList Arguments; std::vector> ExtraEnvironment; + FilelistInfo FilelistInfo; - InvocationInfo(const char *name, llvm::opt::ArgStringList args, + InvocationInfo(const char *name, llvm::opt::ArgStringList args = {}, decltype(ExtraEnvironment) extraEnv = {}) - : ExecutableName(name), Arguments(args), ExtraEnvironment(extraEnv) {} + : ExecutableName(name), Arguments(std::move(args)), + ExtraEnvironment(std::move(extraEnv)) {} }; virtual InvocationInfo @@ -125,13 +154,13 @@ class ToolChain { /// This method dispatches to the various \c constructInvocation methods, /// which may be overridden by platform-specific subclasses. std::unique_ptr constructJob(const JobAction &JA, + Compilation &C, SmallVectorImpl &&inputs, - std::unique_ptr output, const ActionList &inputActions, - const llvm::opt::ArgList &args, + std::unique_ptr output, const OutputInfo &OI) const; - /// Return the default langauge type to use for the given extension. + /// Return the default language type to use for the given extension. virtual types::ID lookupTypeForExtension(StringRef Ext) const; }; } // end namespace driver diff --git a/include/swift/Driver/Types.def b/include/swift/Driver/Types.def index 0a6027c70b780..5b01b5f3ba252 100644 --- a/include/swift/Driver/Types.def +++ b/include/swift/Driver/Types.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Driver/Types.h b/include/swift/Driver/Types.h index 309a4520307d4..5445bc3d0ded9 100644 --- a/include/swift/Driver/Types.h +++ b/include/swift/Driver/Types.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,11 +44,19 @@ namespace types { /// Returns true if the type represents textual data. bool isTextual(ID Id); - /// Returns true if the type is produced in the compiler after the LLVM passes. + /// Returns true if the type is produced in the compiler after the LLVM + /// passes. + /// /// For those types the compiler produces multiple output files in multi- /// threaded compilation. bool isAfterLLVM(ID Id); + /// Returns true if the type is a file that contributes to the Swift module + /// being compiled. + /// + /// These need to be passed to the Swift frontend + bool isPartOfSwiftCompilation(ID Id); + template void forAllTypes(const Fn &fn); } // end namespace types diff --git a/include/swift/Driver/Util.h b/include/swift/Driver/Util.h index ef5b7e7ea32ec..5e76855bcbab6 100644 --- a/include/swift/Driver/Util.h +++ b/include/swift/Driver/Util.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,9 +13,16 @@ #ifndef SWIFT_DRIVER_UTIL_H #define SWIFT_DRIVER_UTIL_H +#include "swift/Driver/Types.h" #include "swift/Basic/LLVM.h" #include "llvm/ADT/SmallVector.h" +namespace llvm { +namespace opt { + class Arg; +} // end namespace opt +} // end namespace llvm + namespace swift { namespace driver { @@ -24,12 +31,33 @@ namespace driver { /// Type used for list of Actions. typedef SmallVector ActionList; + /// An input argument from the command line and its inferred type. + typedef std::pair InputPair; + /// Type used for a list of input arguments. + typedef SmallVector InputFileList; + enum class LinkKind { None, Executable, DynamicLibrary }; + /// Used by a Job to request a "filelist": a file containing a list of all + /// input or output files of a certain type. + /// + /// The Compilation is responsible for generating this file before running + /// the Job this info is attached to. + struct FilelistInfo { + enum WhichFiles : bool { + Input, + Output + }; + + StringRef path; + types::ID type; + WhichFiles whichFiles; + }; + } // end namespace driver } // end namespace swift diff --git a/include/swift/Frontend/DiagnosticVerifier.h b/include/swift/Frontend/DiagnosticVerifier.h index 18b9f25d4283d..0ec8ea152c1c3 100644 --- a/include/swift/Frontend/DiagnosticVerifier.h +++ b/include/swift/Frontend/DiagnosticVerifier.h @@ -1,8 +1,8 @@ -//===- DiagnosticVerifier.h - Diagnostic Verifier (-verify) -----*- C++ -*-===// +//===--- DiagnosticVerifier.h - Diagnostic Verifier (-verify) ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 8c25b9336ddf6..d92aa359eddda 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -1,8 +1,8 @@ -//===-- Frontend.h - frontend utility methods ------------------*- C++ -*--===// +//===--- Frontend.h - frontend utility methods ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -267,8 +267,6 @@ class CompilerInvocation { void setCodeCompletionFactory(CodeCompletionCallbacksFactory *Factory) { CodeCompletionFactory = Factory; - if (Factory) - LangOpts.EnableCodeCompletionDelayedEnumConformanceHack = true; } CodeCompletionCallbacksFactory *getCodeCompletionFactory() const { diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 4e36b180035c3..e0e98a31fd4b6 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -166,6 +166,12 @@ class FrontendOptions { /// If set, dumps wall time taken to check each function body to llvm::errs(). bool DebugTimeFunctionBodies = false; + /// If set, prints the time taken in each major compilation phase to + /// llvm::errs(). + /// + /// \sa swift::SharedTimer + bool DebugTimeCompilation = false; + /// Indicates whether function body parsing should be delayed /// until the end of all files. bool DelayedFunctionBodyParsing = false; @@ -176,9 +182,14 @@ class FrontendOptions { /// Indicates whether we are compiling for testing. /// - /// \see Module::isTestingEnabled + /// \see ModuleDecl::isTestingEnabled bool EnableTesting = false; + /// Indicates whether we are compiling for resilience. + /// + /// \see ModuleDecl::isResilienceEnabled + bool EnableResilience = false; + /// Indicates that the frontend should emit "verbose" SIL /// (if asked to emit SIL). bool EmitVerboseSIL = false; diff --git a/include/swift/Frontend/PrintingDiagnosticConsumer.h b/include/swift/Frontend/PrintingDiagnosticConsumer.h index 14f2ce7f3609a..e714f9d76ce0b 100644 --- a/include/swift/Frontend/PrintingDiagnosticConsumer.h +++ b/include/swift/Frontend/PrintingDiagnosticConsumer.h @@ -1,8 +1,8 @@ -//===- PrintingDiagnosticConsumer.h - Print Text Diagnostics ----*- C++ -*-===// +//===--- PrintingDiagnosticConsumer.h - Print Text Diagnostics --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Frontend/SerializedDiagnosticConsumer.h b/include/swift/Frontend/SerializedDiagnosticConsumer.h index ad866121f0e56..296b0547c2cc7 100644 --- a/include/swift/Frontend/SerializedDiagnosticConsumer.h +++ b/include/swift/Frontend/SerializedDiagnosticConsumer.h @@ -1,8 +1,8 @@ -//===- SerializedDiagnosticConsumer.h - Serialize Diagnostics --*- C++ -*--===// +//===--- SerializedDiagnosticConsumer.h - Serialize Diagnostics -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 20923273e8aba..e4bbf08f7db15 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -1,8 +1,8 @@ -//===- CodeCompletion.h - Routines for code completion --------------------===// +//===--- CodeCompletion.h - Routines for code completion --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -266,13 +266,13 @@ class CodeCompletionString { } static Chunk createWithText(ChunkKind Kind, unsigned NestingLevel, - StringRef Text, bool isAnnoation = false) { - return Chunk(Kind, NestingLevel, Text, isAnnoation); + StringRef Text, bool isAnnotation = false) { + return Chunk(Kind, NestingLevel, Text, isAnnotation); } static Chunk createSimple(ChunkKind Kind, unsigned NestingLevel, - bool isAnnoation = false) { - return Chunk(Kind, NestingLevel, isAnnoation); + bool isAnnotation = false) { + return Chunk(Kind, NestingLevel, isAnnotation); } }; @@ -387,6 +387,7 @@ enum class CodeCompletionDeclKind { Enum, EnumElement, Protocol, + AssociatedType, TypeAlias, GenericTypeParam, Constructor, @@ -446,6 +447,7 @@ enum class CompletionKind { CallArg, ReturnStmtExpr, AfterPound, + GenericParams, }; /// \brief A single code completion result. @@ -732,7 +734,7 @@ struct SimpleCachingCodeCompletionConsumer : public CodeCompletionConsumer { ArrayRef requestedModules, DeclContext *DCForModules) override; - /// Clients should overrride this method to receive \p Results. + /// Clients should override this method to receive \p Results. virtual void handleResults( MutableArrayRef Results) = 0; }; @@ -775,5 +777,27 @@ void copyCodeCompletionResults(CodeCompletionResultSink &targetSink, CodeComplet } // namespace ide } // namespace swift +template <> struct llvm::DenseMapInfo { + using Kind = swift::ide::CodeCompletionKeywordKind; + static Kind getEmptyKey() { return Kind(~0u); } + static Kind getTombstoneKey() { return Kind(~1u); } + static unsigned getHashValue(const Kind &Val) { return unsigned(Val); } + static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; } +}; +template <> struct llvm::DenseMapInfo { + using Kind = swift::ide::CodeCompletionLiteralKind; + static Kind getEmptyKey() { return Kind(~0u); } + static Kind getTombstoneKey() { return Kind(~1u); } + static unsigned getHashValue(const Kind &Val) { return unsigned(Val); } + static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; } +}; +template <> struct llvm::DenseMapInfo { + using Kind = swift::ide::CodeCompletionDeclKind; + static Kind getEmptyKey() { return Kind(~0u); } + static Kind getTombstoneKey() { return Kind(~1u); } + static unsigned getHashValue(const Kind &Val) { return unsigned(Val); } + static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; } +}; + #endif // SWIFT_IDE_CODE_COMPLETION_H diff --git a/include/swift/IDE/CodeCompletionCache.h b/include/swift/IDE/CodeCompletionCache.h index c7fa9c441e592..14e0b7c79fc61 100644 --- a/include/swift/IDE/CodeCompletionCache.h +++ b/include/swift/IDE/CodeCompletionCache.h @@ -1,8 +1,8 @@ -//===- CodeCompletionCache.h - Routines for code completion caching -------===// +//===--- CodeCompletionCache.h - Routines for code completion caching -----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/CommentConversion.h b/include/swift/IDE/CommentConversion.h index 99594c76a2ee2..af87e4aa8844a 100644 --- a/include/swift/IDE/CommentConversion.h +++ b/include/swift/IDE/CommentConversion.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/ModuleInterfacePrinting.h b/include/swift/IDE/ModuleInterfacePrinting.h index 937a64a15d4d1..26d80e9740757 100644 --- a/include/swift/IDE/ModuleInterfacePrinting.h +++ b/include/swift/IDE/ModuleInterfacePrinting.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/REPLCodeCompletion.h b/include/swift/IDE/REPLCodeCompletion.h index f58cb29fd6ac7..834a3d77fd417 100644 --- a/include/swift/IDE/REPLCodeCompletion.h +++ b/include/swift/IDE/REPLCodeCompletion.h @@ -1,8 +1,8 @@ -//===--- REPLCodeCompletion.h - Code completion for REPL ----------* C++ *-===// +//===--- REPLCodeCompletion.h - Code completion for REPL --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/SourceEntityWalker.h b/include/swift/IDE/SourceEntityWalker.h index 4f74a48e10a9f..b604e60a488dc 100644 --- a/include/swift/IDE/SourceEntityWalker.h +++ b/include/swift/IDE/SourceEntityWalker.h @@ -1,8 +1,8 @@ -//===- SourceEntityWalker.h - Routines for semantic source info -----------===// +//===--- SourceEntityWalker.h - Routines for semantic source info ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h index ccdcd6f67b487..d0d1593ecdeea 100644 --- a/include/swift/IDE/SyntaxModel.h +++ b/include/swift/IDE/SyntaxModel.h @@ -1,8 +1,8 @@ -//===- SyntaxModel.h - Routines for IDE syntax model ---------------------===// +//===--- SyntaxModel.h - Routines for IDE syntax model ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 7bada60065100..8e5578ef08a19 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -1,8 +1,8 @@ -//===- Utils.h - Misc utilities -------------------------------------------===// +//===--- Utils.h - Misc utilities -------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -123,6 +123,14 @@ void getLocationInfoForClangNode(ClangNode ClangNode, Optional> parseLineCol(StringRef LineCol); +Type getTypeFromMangledTypename(ASTContext &Ctx, + const char *mangled_typename, + std::string &error); + +Type getTypeFromMangledSymbolname(ASTContext &Ctx, + const char *mangled_typename, + std::string &error); + class XMLEscapingPrinter : public StreamPrinter { public: XMLEscapingPrinter(raw_ostream &OS) : StreamPrinter(OS){}; @@ -179,7 +187,6 @@ class SemaLocResolver : public SourceEntityWalker { bool visitSubscriptReference(ValueDecl *D, CharSourceRange Range, bool IsOpenBracket) override; }; - } // namespace ide class ArchetypeTransformer { diff --git a/include/swift/Immediate/Immediate.h b/include/swift/Immediate/Immediate.h index 6027ea076319d..101aeb416f338 100644 --- a/include/swift/Immediate/Immediate.h +++ b/include/swift/Immediate/Immediate.h @@ -1,8 +1,8 @@ -//===-- Immediate.h - Entry point for swift immediate mode -----*- C++ -*--===// +//===--- Immediate.h - Entry point for swift immediate mode -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/LLVMPasses/Passes.h b/include/swift/LLVMPasses/Passes.h index d53d69b17f910..0d2f06ea1791e 100644 --- a/include/swift/LLVMPasses/Passes.h +++ b/include/swift/LLVMPasses/Passes.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/LLVMPasses/PassesFwd.h b/include/swift/LLVMPasses/PassesFwd.h index f1dcdb6eabb07..bf36b95b5ddcf 100644 --- a/include/swift/LLVMPasses/PassesFwd.h +++ b/include/swift/LLVMPasses/PassesFwd.h @@ -1,8 +1,8 @@ -//===--- PassesFwd.h - Creation functions for LLVM passes ------*- C++ -*-===// +//===--- PassesFwd.h - Creation functions for LLVM passes -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/AST.h b/include/swift/Markup/AST.h index 0238e16fe5abd..f50741a90c4b0 100644 --- a/include/swift/Markup/AST.h +++ b/include/swift/Markup/AST.h @@ -1,8 +1,8 @@ -//===--- AST.h - Markup AST nodes ---------------------------------------===// +//===--- AST.h - Markup AST nodes -------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -199,15 +199,19 @@ class Item final : public MarkupASTNode { class CodeBlock final : public MarkupASTNode { StringRef LiteralContent; + StringRef Language; - CodeBlock(StringRef LiteralContent) + CodeBlock(StringRef LiteralContent, StringRef Language) : MarkupASTNode(ASTNodeKind::CodeBlock), - LiteralContent(LiteralContent) {} + LiteralContent(LiteralContent), + Language(Language) {} public: - static CodeBlock *create(MarkupContext &MC, StringRef LiteralContent); + static CodeBlock *create(MarkupContext &MC, StringRef LiteralContent, + StringRef Language); StringRef getLiteralContent() const { return LiteralContent; }; + StringRef getLanguage() const { return Language; }; ArrayRef getChildren() const { return {}; diff --git a/include/swift/Markup/ASTNodes.def b/include/swift/Markup/ASTNodes.def index df95413c3f475..b1330bb66ceaa 100644 --- a/include/swift/Markup/ASTNodes.def +++ b/include/swift/Markup/ASTNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/LineList.h b/include/swift/Markup/LineList.h index 539df74a07587..29d78cc245e1f 100644 --- a/include/swift/Markup/LineList.h +++ b/include/swift/Markup/LineList.h @@ -1,8 +1,8 @@ -//===--- LineList.h - Data structures for Markup parsing ------------------===// +//===--- LineList.h - Data structures for Markup parsing --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/Markup.h b/include/swift/Markup/Markup.h index ace38deee7b63..72c1c40279e8e 100644 --- a/include/swift/Markup/Markup.h +++ b/include/swift/Markup/Markup.h @@ -1,8 +1,8 @@ -//===--- Markup.h - Markup ------------------------------------------------===// +//===--- Markup.h - Markup --------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/SimpleFields.def b/include/swift/Markup/SimpleFields.def index b86676d1006b6..6ccd4b526869a 100644 --- a/include/swift/Markup/SimpleFields.def +++ b/include/swift/Markup/SimpleFields.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/SourceLoc.h b/include/swift/Markup/SourceLoc.h index 57db0d91f6813..4b383b30917d4 100644 --- a/include/swift/Markup/SourceLoc.h +++ b/include/swift/Markup/SourceLoc.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Markup/XMLUtils.h b/include/swift/Markup/XMLUtils.h index 1d3977b705b76..6632d15387891 100644 --- a/include/swift/Markup/XMLUtils.h +++ b/include/swift/Markup/XMLUtils.h @@ -1,8 +1,8 @@ -//===--- XMLUtils.h - Various XML utility routines ------------------------===// +//===--- XMLUtils.h - Various XML utility routines --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 9ae6a131418b9..028bae91aa2ab 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,6 +28,11 @@ def delayed_function_body_parsing : def primary_file : Separate<["-"], "primary-file">, HelpText<"Produce output for this file, not the whole module">; +def filelist : Separate<["-"], "filelist">, + HelpText<"Specify source inputs in a file rather than on the command line">; +def output_filelist : Separate<["-"], "output-filelist">, + HelpText<"Specify outputs in a file rather than on the command line">; + def emit_module_doc : Flag<["-"], "emit-module-doc">, HelpText<"Emit a module documentation file based on documentation " "comments">; @@ -124,6 +129,8 @@ def debug_forbid_typecheck_prefix : Separate<["-"], "debug-forbid-typecheck-pref HelpText<"Triggers llvm fatal_error if typechecker tries to typecheck a decl " "with the provided prefix name">; +def debug_time_compilation : Flag<["-"], "debug-time-compilation">, + HelpText<"Prints the time taken by each compilation phase">; def debug_time_function_bodies : Flag<["-"], "debug-time-function-bodies">, HelpText<"Dumps the time it takes to type-check each function body">; @@ -142,6 +149,9 @@ def debugger_support : Flag<["-"], "debugger-support">, def disable_arc_opts : Flag<["-"], "disable-arc-opts">, HelpText<"Don't run SIL ARC optimization passes.">; +def enable_guaranteed_closure_contexts : Flag<["-"], "enable-guaranteed-closure-contexts">, + HelpText<"Use @guaranteed convention for closure context">; + def remove_runtime_asserts : Flag<["-"], "remove-runtime-asserts">, HelpText<"Remove runtime asserts.">; @@ -171,6 +181,18 @@ def disable_llvm_slp_vectorizer : Flag<["-"], "disable-llvm-slp-vectorizer">, def disable_llvm_verify : Flag<["-"], "disable-llvm-verify">, HelpText<"Don't run the LLVM IR verifier.">; +def disable_llvm_value_names : Flag<["-"], "disable-llvm-value-names">, + HelpText<"Don't add names to local values in LLVM IR">; + +def enable_llvm_value_names : Flag<["-"], "enable-llvm-value-names">, + HelpText<"Add names to local values in LLVM IR">; + +def strip_field_names : Flag<["-"], "strip-field-names">, + HelpText<"Strip field names from nominal type metadata">; + +def strip_field_metadata : Flag<["-"], "strip-field-metadata">, + HelpText<"Strip all field metadata for nominal types">; + def stack_promotion_checks : Flag<["-"], "emit-stack-promotion-checks">, HelpText<"Emit runtime checks for correct stack promotion of objects.">; @@ -187,15 +209,6 @@ def dump_clang_diagnostics : Flag<["-"], "dump-clang-diagnostics">, def emit_verbose_sil : Flag<["-"], "emit-verbose-sil">, HelpText<"Emit locations during SIL emission">; -def use_native_super_method : Flag<["-"], "use-native-super-method">, - HelpText<"Use super_method for super calls in native classes">; - -def force_resilient_super_dispatch: Flag<["-"], "force-resilient-super-dispatch">, - HelpText<"Assume all super member accesses are resilient">; - -def disable_self_type_mangling : Flag<["-"], "disable-self-type-mangling">, - HelpText<"Disable including Self type in method type manglings">; - def enable_experimental_patterns : Flag<["-"], "enable-experimental-patterns">, HelpText<"Enable experimental 'switch' pattern matching features">; @@ -215,6 +228,10 @@ def enable_swift_name_lookup_tables : Flag<["-"], "enable-swift-name-lookup-tables">, HelpText<"Enable Swift name lookup tables in the Clang importer">; +def swift3_migration : + Flag<["-"], "swift3-migration">, + HelpText<"Enable Fix-It based migration aids for Swift 3">; + def warn_omit_needless_words : Flag<["-"], "Womit-needless-words">, HelpText<"Warn about needless words in names">; @@ -290,9 +307,7 @@ def dump_api_path : Separate<["-"], "dump-api-path">, HelpText<"The path to output swift interface files for the compiled source files">; def enable_resilience : Flag<["-"], "enable-resilience">, - HelpText<"Treat all types as resilient by default">; - -def disable_resilience : Flag<["-"], "disable-resilience">, - HelpText<"Treat all types as fixed layout by default">; + HelpText<"Compile the library with resilient interfaces for all " + "public declarations">; } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/include/swift/Option/Options.h b/include/swift/Option/Options.h index a46922eacfcb0..5a29259e1dc95 100644 --- a/include/swift/Option/Options.h +++ b/include/swift/Option/Options.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 1ade695a92ab1..3b14a5e86b372 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -88,6 +88,8 @@ def driver_use_frontend_path : Separate<["-"], "driver-use-frontend-path">, def driver_show_incremental : Flag<["-"], "driver-show-incremental">, InternalDebugOpt, HelpText<"With -v, dump information about why files are being rebuilt">; +def driver_use_filelists : Flag<["-"], "driver-use-filelists">, + InternalDebugOpt, HelpText<"Pass input files as filelists whenever possible">; def driver_always_rebuild_dependents : Flag<["-"], "driver-always-rebuild-dependents">, InternalDebugOpt, @@ -216,6 +218,15 @@ def solver_memory_threshold : Separate<["-"], "solver-memory-threshold">, Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>, HelpText<"Set the upper bound for memory consumption, in bytes, by the constraint solver">; +// Diagnostic control options +def suppress_warnings : Flag<["-"], "suppress-warnings">, + Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Suppress all warnings">; + +def warnings_as_errors : Flag<["-"], "warnings-as-errors">, + Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Treat warnings as errors">; + // Platform options. def enable_app_extension : Flag<["-"], "application-extension">, Flags<[FrontendOption, NoInteractiveOption]>, diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index 58dc1c8ad1d55..81c9cbc7af472 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -1,8 +1,8 @@ -//===- CodeCompletionCallbacks.h - Parser's interface to code completion --===// +//===--- CodeCompletionCallbacks.h - Parser's interface to code completion ===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -170,6 +170,8 @@ class CodeCompletionCallbacks { virtual void completeAfterPound(CodeCompletionExpr *E, StmtKind ParentKind) = 0; + virtual void completeGenericParams(TypeLoc TL) = 0; + /// \brief Signals that the AST for the all the delayed-parsed code was /// constructed. No \c complete*() callbacks will be done after this. virtual void doneParsing() = 0; diff --git a/include/swift/Parse/DelayedParsingCallbacks.h b/include/swift/Parse/DelayedParsingCallbacks.h index 05e5987806569..f9763dedb0ad4 100644 --- a/include/swift/Parse/DelayedParsingCallbacks.h +++ b/include/swift/Parse/DelayedParsingCallbacks.h @@ -1,8 +1,8 @@ -//===- DelayedParsingCallbacks.h - Callbacks for Parser's delayed parsing -===// +//===--- DelayedParsingCallbacks.h - Delayed parsing callbacks --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index f6f4afa4d7abe..23afd38505714 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -240,6 +240,15 @@ class Lexer { restoreState(S); } + /// \brief Retrieve the Token referred to by \c Loc. + /// + /// \param SM The source manager in which the given source location + /// resides. + /// + /// \param Loc The source location of the beginning of a token. + static Token getTokenAtLocation(const SourceManager &SM, SourceLoc Loc); + + /// \brief Retrieve the source location that points just past the /// end of the token referred to by \c Loc. /// @@ -255,8 +264,9 @@ class Lexer { /// resides. /// /// \param SR The source range - static CharSourceRange getCharSourceRangeFromSourceRange(const SourceManager &SM, - const SourceRange &SR) { + static CharSourceRange + getCharSourceRangeFromSourceRange(const SourceManager &SM, + const SourceRange &SR) { return CharSourceRange(SM, SR.Start, getLocForEndOfToken(SM, SR.End)); } @@ -299,6 +309,10 @@ class Lexer { /// reserved word. static tok kindOfIdentifier(StringRef Str, bool InSILMode); + /// \brief Determines if the given string is a valid operator identifier, + /// without escaping characters. + static bool isOperator(StringRef string); + SourceLoc getLocForStartOfBuffer() const { return SourceLoc(llvm::SMLoc::getFromPointer(BufferStart)); } @@ -425,7 +439,6 @@ class Lexer { const char *findEndOfCurlyQuoteStringLiteral(const char*); }; - } // end namespace swift #endif diff --git a/include/swift/Parse/LocalContext.h b/include/swift/Parse/LocalContext.h index 8bdc36e4759ee..9615b0fc094e7 100644 --- a/include/swift/Parse/LocalContext.h +++ b/include/swift/Parse/LocalContext.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 3b3468ef4831d..3c69790f74b84 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -71,6 +71,7 @@ class Parser { bool IsInputIncomplete = false; SourceLoc DelayedDeclEnd; + std::vector SplitTokens; public: SourceManager &SourceMgr; @@ -83,7 +84,7 @@ class Parser { DeclContext *CurDeclContext; ASTContext &Context; CodeCompletionCallbacks *CodeCompletion = nullptr; - std::vector>> AnonClosureVars; + std::vector>> AnonClosureVars; bool IsParsingInterfaceTokens = false; @@ -155,6 +156,10 @@ class Parser { return SF.isScriptMode(); } + const std::vector &getSplitTokens() { return SplitTokens; } + + void markSplitToken(tok Kind, StringRef Txt); + /// Returns true if the parser reached EOF with incomplete source input, due /// for example, a missing right brace. bool isInputIncomplete() const { return IsInputIncomplete; } @@ -373,13 +378,17 @@ class Parser { class BacktrackingScope { Parser &P; ParserPosition PP; + bool Backtrack = true; public: BacktrackingScope(Parser &P) : P(P), PP(P.getParserPosition()) {} ~BacktrackingScope() { - P.backtrackToPosition(PP); + if (Backtrack) + P.backtrackToPosition(PP); } + + void cancelBacktrack() { Backtrack = false; } }; /// RAII object that, when it is destructed, restores the parser and lexer to @@ -448,10 +457,11 @@ class Parser { void skipUntil(tok T1, tok T2 = tok::unknown); void skipUntilAnyOperator(); - /// \brief Skip until a token that starts with '>'. Applies heuristics that - /// are suitable when trying to find the end of a list of generic parameters, - /// generic arguments, or list of types in a protocol composition. - void skipUntilGreaterInTypeList(bool protocolComposition=false); + /// \brief Skip until a token that starts with '>', and consume it if found. + /// Applies heuristics that are suitable when trying to find the end of a list + /// of generic parameters, generic arguments, or list of types in a protocol + /// composition. + SourceLoc skipUntilGreaterInTypeList(bool protocolComposition = false); /// skipUntilDeclStmtRBrace - Skip to the next decl or '}'. void skipUntilDeclRBrace(); @@ -706,7 +716,7 @@ class Parser { bool parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, DeclAttrKind DK); - + /// Parse a version tuple of the form x[.y[.z]]. Returns true if there was /// an error parsing. bool parseVersionTuple(clang::VersionTuple &Version, SourceRange &Range, @@ -760,18 +770,18 @@ class Parser { void record(Parser &P, AbstractStorageDecl *storage, bool invalid, ParseDeclOptions flags, SourceLoc staticLoc, const DeclAttributes &attrs, - TypeLoc elementTy, Pattern *indices, + TypeLoc elementTy, ParameterList *indices, SmallVectorImpl &decls); }; bool parseGetSetImpl(ParseDeclOptions Flags, - Pattern *Indices, TypeLoc ElementTy, + ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc &LastValidLoc, SourceLoc StaticLoc, SourceLoc VarLBLoc, SmallVectorImpl &Decls); bool parseGetSet(ParseDeclOptions Flags, - Pattern *Indices, TypeLoc ElementTy, + ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc StaticLoc, SmallVectorImpl &Decls); void recordAccessors(AbstractStorageDecl *storage, ParseDeclOptions flags, @@ -803,6 +813,7 @@ class Parser { parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes); void addPatternVariablesToScope(ArrayRef Patterns); + void addParametersToScope(ParameterList *PL); ParserResult parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes); @@ -859,7 +870,7 @@ class Parser { ParserResult parseTypeComposition(); ParserResult parseTypeTupleBody(); - ParserResult parseTypeArray(TypeRepr *Base); + ParserResult parseTypeArray(TypeRepr *Base); /// Parse a collection type. /// type-simple: @@ -900,8 +911,8 @@ class Parser { /// function. void setFunctionContext(DeclContext *DC); - DefaultArgumentInfo() { - NextIndex = 0; + DefaultArgumentInfo(bool inTypeContext) { + NextIndex = inTypeContext ? 1 : 0; HasDefaultArgument = false; } }; @@ -922,10 +933,6 @@ class Parser { }; SpecifierKindTy SpecifierKind = Let; // Defaults to let. - - /// The location of the back-tick preceding the first name, if any. - SourceLoc PoundLoc; - /// The location of the first name. /// /// \c FirstName is the name. @@ -997,23 +1004,23 @@ class Parser { DefaultArgumentInfo *defaultArgs, ParameterContextKind paramContext); - ParserResult parseSingleParameterClause( + ParserResult parseSingleParameterClause( ParameterContextKind paramContext, SmallVectorImpl *namePieces = nullptr); ParserStatus parseFunctionArguments(SmallVectorImpl &NamePieces, - SmallVectorImpl &BodyPatterns, + SmallVectorImpl &BodyParams, ParameterContextKind paramContext, DefaultArgumentInfo &defaultArgs); ParserStatus parseFunctionSignature(Identifier functionName, DeclName &fullName, - SmallVectorImpl &bodyPatterns, + SmallVectorImpl &bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throws, bool &rethrows, TypeRepr *&retType); ParserStatus parseConstructorArguments(DeclName &FullName, - Pattern *&BodyPattern, + ParameterList *&BodyParams, DefaultArgumentInfo &defaultArgs); //===--------------------------------------------------------------------===// @@ -1095,10 +1102,28 @@ class Parser { bool isExprBasic); ParserResult parseExprPostfix(Diag<> ID, bool isExprBasic); ParserResult parseExprUnary(Diag<> ID, bool isExprBasic); + ParserResult parseExprSelector(); ParserResult parseExprSuper(); ParserResult parseExprConfiguration(); Expr *parseExprStringLiteral(); - + + /// If the token is an escaped identifier being used as an argument + /// label, but doesn't need to be, diagnose it. + void diagnoseEscapedArgumentLabel(const Token &tok); + + /// Parse an unqualified-decl-name. + /// + /// unqualified-decl-name: + /// identifier + /// identifier '(' ((identifier | '_') ':') + ')' + /// + /// + /// \param allowInit Whether to allow 'init' for initializers. + /// \param loc Will be populated with the location of the name. + /// \param diag The diagnostic to emit if this is not a name. + DeclName parseUnqualifiedDeclName(bool allowInit, DeclNameLoc &loc, + const Diagnostic &diag); + Expr *parseExprIdentifier(); Expr *parseExprEditorPlaceholder(Token PlaceholderTok, Identifier PlaceholderId); @@ -1137,7 +1162,7 @@ class Parser { /// \returns true if an error occurred, false otherwise. bool parseClosureSignatureIfPresent( SmallVectorImpl &captureList, - Pattern *¶ms, + ParameterList *¶ms, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeRepr *&explicitResultType, @@ -1193,11 +1218,12 @@ class Parser { //===--------------------------------------------------------------------===// // Generics Parsing - GenericParamList *parseGenericParameters(); - GenericParamList *parseGenericParameters(SourceLoc LAngleLoc); - GenericParamList *maybeParseGenericParams(); - bool parseGenericWhereClause(SourceLoc &WhereLoc, - SmallVectorImpl &Requirements); + ParserResult parseGenericParameters(); + ParserResult parseGenericParameters(SourceLoc LAngleLoc); + ParserResult maybeParseGenericParams(); + ParserStatus parseGenericWhereClause(SourceLoc &WhereLoc, + SmallVectorImpl &Requirements, + bool &FirstTypeInComplete); //===--------------------------------------------------------------------===// // Availability Specification Parsing @@ -1210,6 +1236,20 @@ class Parser { ParserResult parseVersionConstraintSpec(); }; +/// Parse a stringified Swift declaration name, e.g. "init(frame:)". +StringRef parseDeclName(StringRef name, + SmallVectorImpl &argumentLabels, + bool &isFunctionName); + +/// Form a Swift declaration name from its constituent parts. +DeclName formDeclName(ASTContext &ctx, + StringRef baseName, + ArrayRef argumentLabels, + bool isFunctionName); + +/// Parse a stringified Swift declaration name, e.g. "init(frame:)". +DeclName parseDeclName(ASTContext &ctx, StringRef name); + } // end namespace swift #endif diff --git a/include/swift/Parse/ParserResult.h b/include/swift/Parse/ParserResult.h index ef42b3cd82ff1..a66e4c6e7d8a5 100644 --- a/include/swift/Parse/ParserResult.h +++ b/include/swift/Parse/ParserResult.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -49,7 +49,7 @@ template class ParserResult { /// Construct a successful parser result. explicit ParserResult(T *Result) : PtrAndBits(Result) { - assert(Result && "a successful parser result can not be null"); + assert(Result && "a successful parser result cannot be null"); } /// Convert from a different but compatible parser result. @@ -125,8 +125,8 @@ static inline ParserResult makeParserCodeCompletionResult(T *Result = /// \brief Same as \c ParserResult, but just the status bits without the AST /// node. /// -/// Useful when the AST node is returned by some other means (for example, a in -/// vector out parameter). +/// Useful when the AST node is returned by some other means (for example, in +/// a vector out parameter). /// /// If you want to use 'bool' as a result type in the Parser, consider using /// ParserStatus instead. @@ -222,6 +222,7 @@ enum class ConfigExprKind { Error, OS, Arch, + LanguageVersion, CompilerVersion, Binary, Paren, @@ -261,7 +262,9 @@ class ConfigParserState { bool shouldParse() const { if (Kind == ConfigExprKind::Error) return true; - return ConditionActive || (Kind != ConfigExprKind::CompilerVersion); + return ConditionActive || + (Kind != ConfigExprKind::CompilerVersion && + Kind != ConfigExprKind::LanguageVersion); } static ConfigParserState error() { diff --git a/include/swift/Parse/PersistentParserState.h b/include/swift/Parse/PersistentParserState.h index 4c20d0ab0557c..8971ee1ab25f7 100644 --- a/include/swift/Parse/PersistentParserState.h +++ b/include/swift/Parse/PersistentParserState.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Parse/Scope.h b/include/swift/Parse/Scope.h index d375e4a59ba3e..cafd90bef6c91 100644 --- a/include/swift/Parse/Scope.h +++ b/include/swift/Parse/Scope.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h index 5cc1f18ee14e9..a6f2a3a815a96 100644 --- a/include/swift/Parse/Token.h +++ b/include/swift/Parse/Token.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,6 +44,7 @@ enum class tok { pound_endif, pound_line, pound_available, + pound_selector, comment, #define KEYWORD(X) kw_ ## X, @@ -190,6 +191,22 @@ class Token { return isAnyOperator() && Text == ContextPunc; } + /// Determine whether the token can be an argument label. + /// + /// This covers all identifiers and keywords except those keywords + /// used + bool canBeArgumentLabel() const { + // Identifiers, escaped identifiers, and '_' can be argument labels. + if (is(tok::identifier) || isEscapedIdentifier() || is(tok::kw__)) + return true; + + // 'let', 'var', and 'inout' cannot be argument labels. + if (isAny(tok::kw_let, tok::kw_var, tok::kw_inout)) return false; + + // All other keywords can be argument labels. + return isKeyword(); + } + /// True if the token is an identifier or '_'. bool isIdentifierOrUnderscore() const { return isAny(tok::identifier, tok::kw__); @@ -245,6 +262,9 @@ class Token { return SourceLoc(llvm::SMLoc::getFromPointer(trimComment().begin())); } + StringRef getRawText() const { + return Text; + } StringRef getText() const { if (EscapedIdentifier) { diff --git a/include/swift/Parse/Tokens.def b/include/swift/Parse/Tokens.def index 834e0a53e0784..9317ea412b894 100644 --- a/include/swift/Parse/Tokens.def +++ b/include/swift/Parse/Tokens.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -63,6 +63,7 @@ DECL_KEYWORD(protocol) DECL_KEYWORD(struct) DECL_KEYWORD(subscript) DECL_KEYWORD(typealias) +DECL_KEYWORD(associatedtype) DECL_KEYWORD(var) DECL_KEYWORD(internal) diff --git a/include/swift/PrintAsObjC/PrintAsObjC.h b/include/swift/PrintAsObjC/PrintAsObjC.h index 676600c18968f..6b4762ae7db34 100644 --- a/include/swift/PrintAsObjC/PrintAsObjC.h +++ b/include/swift/PrintAsObjC/PrintAsObjC.h @@ -1,8 +1,8 @@ -//===-- PrintAsObjC.h - Emit a header file for a Swift AST --------------===// +//===--- PrintAsObjC.h - Emit a header file for a Swift AST -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/Concurrent.h b/include/swift/Runtime/Concurrent.h index 9f9e26125c199..adf8fd31e6e20 100644 --- a/include/swift/Runtime/Concurrent.h +++ b/include/swift/Runtime/Concurrent.h @@ -1,8 +1,8 @@ -//===--- Concurrent.h - Concurrent Data Structures ------------*- C++ -*--===// +//===--- Concurrent.h - Concurrent Data Structures -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -145,7 +145,7 @@ template struct ConcurrentMapNode { /// The method findOrAllocateNode searches the binary tree in search of the /// exact Key value. If it finds an edge that points to NULL that should /// contain the value then it tries to compare and swap the new node into -/// place. If it looses the race to a different thread it de-allocates +/// place. If it loses the race to a different thread it de-allocates /// the node and starts the search again since the new node should /// be placed (or found) on the new link. See findOrAllocateNode for more /// details. @@ -164,7 +164,7 @@ template class ConcurrentMap { /// accelerating the search of the same value again and again. std::atomic LastSearch; - /// Search a for a node with key value \p. If the node does not exist then + /// Search for a node with key value \p. If the node does not exist then /// allocate a new bucket and add it to the tree. ConcurrentList &findOrAllocateNode(KeyTy Key) { // Try looking at the last node we searched. diff --git a/include/swift/Runtime/Config.h b/include/swift/Runtime/Config.h index 91a4b62f8f2da..7307a435392f0 100644 --- a/include/swift/Runtime/Config.h +++ b/include/swift/Runtime/Config.h @@ -1,8 +1,8 @@ -//===--- Config.h - Swift Language Platform Configuration ------*- C++ -*--===// +//===--- Config.h - Swift Language Platform Configuration -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index 7e9c09a8222ac..3bfc1410300de 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -1,8 +1,8 @@ -//===--- Debug.h - Swift Runtime debug helpers ----------------------------===// +//===--- Debug.h - Swift Runtime debug helpers ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -101,7 +101,10 @@ swift_dynamicCastFailure(const void *sourceType, const char *sourceName, const void *targetType, const char *targetName, const char *message = nullptr); +extern "C" +void swift_reportError(const char *message); + // namespace swift -}; +} #endif // _SWIFT_RUNTIME_DEBUG_HELPERS_ diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h index 887ecad99cd3c..95ad9c8e0f6c4 100644 --- a/include/swift/Runtime/Enum.h +++ b/include/swift/Runtime/Enum.h @@ -1,8 +1,8 @@ -//===--- Enum.h - Runtime declarations for enums ---------------*- C++ -*--===// +//===--- Enum.h - Runtime declarations for enums ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/Heap.h b/include/swift/Runtime/Heap.h index fc6f30e25ad4b..749eb7f9337e8 100644 --- a/include/swift/Runtime/Heap.h +++ b/include/swift/Runtime/Heap.h @@ -1,8 +1,8 @@ -//===--- Heap.h - Swift Language Heap ABI ----------------------*- C++ -*--===// +//===--- Heap.h - Swift Language Heap ABI -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h index 3153f49961568..4ec557716b52b 100644 --- a/include/swift/Runtime/HeapObject.h +++ b/include/swift/Runtime/HeapObject.h @@ -1,8 +1,8 @@ -//===--- Alloc.h - Swift Language Allocation ABI ---------------*- C++ -*--===// +//===--- HeapObject.h - Swift Language Allocation ABI -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -123,26 +123,6 @@ inline TwoWordPair::TwoWordPair(A first, B second) using BoxPair = TwoWordPair; -/// Allocates a heap object with POD value semantics. The returned memory is -/// uninitialized outside of the heap object header. The object has an -/// initial retain count of 1, and its metadata is set to a predefined -/// POD heap metadata for which destruction is a no-op. -/// -/// \param dataSize The size of the data area for the allocation. -/// Excludes the heap metadata header. -/// \param dataAlignmentMask The alignment of the data area. -/// -/// \returns a BoxPair in which the heapObject field points to the newly-created -/// HeapObject and the value field points to the data area inside the -/// allocation. The value pointer will have the alignment specified -/// by the dataAlignmentMask and point to dataSize bytes of memory. -extern "C" BoxPair::Return -swift_allocPOD(size_t dataSize, size_t dataAlignmentMask); - -/// Deallocates a heap object known to have been allocated by swift_allocPOD and -/// to have no remaining owners. -extern "C" void swift_deallocPOD(HeapObject *obj); - /// Allocates a heap object that can contain a value of the given type. /// Returns a Box structure containing a HeapObject* pointer to the /// allocated object, and a pointer to the value inside the heap object. @@ -226,10 +206,6 @@ extern "C" void swift_release(HeapObject *object); /// count reaches zero, the object is destroyed extern "C" void swift_release_n(HeapObject *object, uint32_t n); -/// ObjC compatibility. Never call this. -extern "C" size_t swift_retainCount(HeapObject *object); -extern "C" size_t swift_unownedRetainCount(HeapObject *object); - /// Is this pointer a non-null unique reference to an object /// that uses Swift reference counting? extern "C" bool swift_isUniquelyReferencedNonObjC(const void *); diff --git a/include/swift/Runtime/InstrumentsSupport.h b/include/swift/Runtime/InstrumentsSupport.h index 78218ce206223..3b5dbc9901930 100644 --- a/include/swift/Runtime/InstrumentsSupport.h +++ b/include/swift/Runtime/InstrumentsSupport.h @@ -1,8 +1,8 @@ -//===--- InstrumentsSupport.h - Support for Instruments.app ------ C++ -*--===// +//===--- InstrumentsSupport.h - Support for Instruments.app -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 143cf5460ff4f..f46a82570b11d 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -93,7 +93,7 @@ struct OpaqueValue; /// A buffer can be in one of three states: /// - An unallocated buffer has a completely unspecified state. /// - An allocated buffer has been initialized so that it -/// owns unintialized value storage for the stored type. +/// owns uninitialized value storage for the stored type. /// - An initialized buffer is an allocated buffer whose value /// storage has been initialized. struct ValueBuffer { @@ -247,9 +247,9 @@ typedef void destroyBuffer(ValueBuffer *buffer, const Metadata *self); /// Given an unallocated buffer, initialize it as a copy of the /// object in the source buffer. This can be decomposed as: /// -/// self->initalizeBufferWithCopy(dest, self->projectBuffer(src), self) +/// self->initializeBufferWithCopy(dest, self->projectBuffer(src), self) /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// /// Preconditions: /// 'dest' is an unallocated buffer @@ -305,7 +305,7 @@ typedef OpaqueValue *initializeBufferWithCopy(ValueBuffer *dest, /// Given an uninitialized object and an initialized object, copy /// the value. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// /// Returns the dest object. /// @@ -322,7 +322,7 @@ typedef OpaqueValue *initializeWithCopy(OpaqueValue *dest, /// Given two initialized objects, copy the value from one to the /// other. /// -/// This operation must be safe aginst 'dest' and 'src' aliasing. +/// This operation must be safe against 'dest' and 'src' aliasing. /// /// Returns the dest object. /// @@ -337,7 +337,7 @@ typedef OpaqueValue *assignWithCopy(OpaqueValue *dest, /// the value from the object to the buffer, leaving the source object /// uninitialized. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// /// Returns the dest object. /// @@ -355,11 +355,11 @@ typedef OpaqueValue *initializeBufferWithTake(ValueBuffer *dest, /// the value from one to the other, leaving the source object /// uninitialized. /// -/// There is no need for a initializeBufferWithTakeOfBuffer, because that +/// There is no need for an initializeBufferWithTakeOfBuffer, because that /// can simply be a pointer-aligned memcpy of sizeof(ValueBuffer) /// bytes. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// /// Returns the dest object. /// @@ -377,7 +377,7 @@ typedef OpaqueValue *initializeWithTake(OpaqueValue *dest, /// the value from one to the other, leaving the source object /// uninitialized. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// Therefore this can be decomposed as: /// /// self->destroy(dest, self); @@ -411,10 +411,10 @@ typedef OpaqueValue *allocateBuffer(ValueBuffer *buffer, /// value from one buffer to the other, leaving the source buffer /// unallocated. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// Therefore this can be decomposed as: /// -/// self->initalizeBufferWithTake(dest, self->projectBuffer(src), self) +/// self->initializeBufferWithTake(dest, self->projectBuffer(src), self) /// self->deallocateBuffer(src, self) /// /// However, it may be more efficient because values stored out-of-line @@ -447,7 +447,7 @@ typedef void destroyArray(OpaqueValue *array, size_t n, /// Given an uninitialized array and an initialized array, copy /// the value. /// -/// This operation does not need to be safe aginst 'dest' and 'src' aliasing. +/// This operation does not need to be safe against 'dest' and 'src' aliasing. /// /// Returns the dest object. /// @@ -532,11 +532,14 @@ typedef int getExtraInhabitantIndex(const OpaqueValue *src, const Metadata *self); /// Given a valid object of this enum type, extracts the tag value indicating -/// which case of the enum is inhabited. The tag value can be used to index -/// into the array returned by the NominalTypeDescriptor's GetCaseTypes -/// function to get the payload type and check if the payload is indirect. -typedef unsigned getEnumTag(const OpaqueValue *src, - const Metadata *self); +/// which case of the enum is inhabited. Returned values are in the range +/// [-ElementsWithPayload..ElementsWithNoPayload-1]. +/// +/// The tag value can be used to index into the array returned by the +/// NominalTypeDescriptor's GetCaseTypes function to get the payload type +/// and check if the payload is indirect. +typedef int getEnumTag(const OpaqueValue *src, + const Metadata *self); /// Given a valid object of this enum type, destructively strips the tag /// bits, leaving behind a value of the inhabited case payload type. @@ -548,9 +551,10 @@ typedef void destructiveProjectEnumData(OpaqueValue *src, /// Given a valid object of an enum case payload's type, destructively add /// the tag bits for the given case, leaving behind a fully-formed value of /// the enum type. If the enum case does not have a payload, the initial -/// state of the value can be undefined. +/// state of the value can be undefined. The given tag value must be in +/// the range [-ElementsWithPayload..ElementsWithNoPayload-1]. typedef void destructiveInjectEnumTag(OpaqueValue *src, - unsigned tag, + int tag, const Metadata *self); } // end namespace value_witness_types @@ -935,6 +939,17 @@ static const uintptr_t ObjCReservedBitsMask = static const unsigned ObjCReservedLowBits = SWIFT_ABI_ARM64_OBJC_NUM_RESERVED_LOW_BITS; +#elif defined(__powerpc64__) + +static const uintptr_t LeastValidPointerValue = + SWIFT_ABI_DEFAULT_LEAST_VALID_POINTER; +static const uintptr_t SwiftSpareBitsMask = + SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK; +static const uintptr_t ObjCReservedBitsMask = + SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK; +static const unsigned ObjCReservedLowBits = + SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS; + #else static const uintptr_t LeastValidPointerValue = @@ -1077,7 +1092,7 @@ struct Metadata { getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this); } - unsigned vw_getEnumTag(const OpaqueValue *value) const { + int vw_getEnumTag(const OpaqueValue *value) const { return getValueWitnesses()->_asEVWT()->getEnumTag(value, this); } void vw_destructiveProjectEnumData(OpaqueValue *value) const { @@ -1202,10 +1217,8 @@ struct EnumTypeDescriptor; /// Common information about all nominal types. For generic types, this /// descriptor is shared for all instantiations of the generic type. struct NominalTypeDescriptor { - /// The kind of nominal type descriptor. - NominalTypeKind Kind; /// The mangled name of the nominal type, with no generic parameters. - const char *Name; + RelativeDirectPointer Name; /// The following fields are kind-dependent. union { @@ -1225,12 +1238,12 @@ struct NominalTypeDescriptor { /// The field names. A doubly-null-terminated list of strings, whose /// length and order is consistent with that of the field offset vector. - const char *FieldNames; + RelativeDirectPointer FieldNames; /// The field type vector accessor. Returns a pointer to an array of /// type metadata references whose order is consistent with that of the /// field offset vector. - const FieldType *(*GetFieldTypes)(const Metadata *Self); + RelativeDirectPointer GetFieldTypes; /// True if metadata records for this type have a field offset vector for /// its stored properties. @@ -1249,12 +1262,12 @@ struct NominalTypeDescriptor { /// The field names. A doubly-null-terminated list of strings, whose /// length and order is consistent with that of the field offset vector. - const char *FieldNames; + RelativeDirectPointer FieldNames; /// The field type vector accessor. Returns a pointer to an array of /// type metadata references whose order is consistent with that of the /// field offset vector. - const FieldType *(*GetFieldTypes)(const Metadata *Self); + RelativeDirectPointer GetFieldTypes; /// True if metadata records for this type have a field offset vector for /// its stored properties. @@ -1272,11 +1285,11 @@ struct NominalTypeDescriptor { /// The names of the cases. A doubly-null-terminated list of strings, /// whose length is NumNonEmptyCases + NumEmptyCases. Cases are named in /// tag order, non-empty cases first, followed by empty cases. - const char *CaseNames; + RelativeDirectPointer CaseNames; /// The field type vector accessor. Returns a pointer to an array of /// type metadata references whose order is consistent with that of the /// CaseNames. Only types for payload cases are provided. - const FieldType *(*GetCaseTypes)(const Metadata *Self); + RelativeDirectPointer GetCaseTypes; uint32_t getNumPayloadCases() const { return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU; @@ -1297,10 +1310,20 @@ struct NominalTypeDescriptor { } Enum; }; + RelativeDirectPointerIntPair + GenericMetadataPatternAndKind; + /// A pointer to the generic metadata pattern that is used to instantiate - /// instances of this type. Null if the type is not generic. - GenericMetadata *GenericMetadataPattern; - + /// instances of this type. Zero if the type is not generic. + GenericMetadata *getGenericMetadataPattern() const { + return const_cast( + GenericMetadataPatternAndKind.getPointer()); + } + + NominalTypeKind getKind() const { + return GenericMetadataPatternAndKind.getInt(); + } + /// The generic parameter descriptor header. This describes how to find and /// parse the generic parameter vector in metadata records for this nominal /// type. @@ -1504,7 +1527,7 @@ struct ClassMetadata : public HeapMetadata { /// Get a pointer to the field type vector, if present, or null. const FieldType *getFieldTypes() const { assert(isTypeMetadata()); - auto *getter = Description->Class.GetFieldTypes; + auto *getter = Description->Class.GetFieldTypes.get(); if (!getter) return nullptr; @@ -1682,7 +1705,7 @@ struct StructMetadata : public Metadata { /// Get a pointer to the field type vector, if present, or null. const FieldType *getFieldTypes() const { - auto *getter = Description->Struct.GetFieldTypes; + auto *getter = Description->Struct.GetFieldTypes.get(); if (!getter) return nullptr; @@ -2104,6 +2127,144 @@ struct GenericMetadata { const void *getMetadataTemplate() const { return reinterpret_cast(this + 1); } + + /// Return the nominal type descriptor for the template metadata + const NominalTypeDescriptor *getTemplateDescription() const { + auto bytes = reinterpret_cast(getMetadataTemplate()); + auto metadata = reinterpret_cast(bytes + AddressPoint); + return metadata->getNominalTypeDescriptor(); + } +}; + +/// \brief The control structure of a generic protocol conformance. +struct GenericWitnessTable { + /// The size of the witness table in words. + uint16_t WitnessTableSizeInWords; + + /// The amount to copy from the pattern in words. The rest is zeroed. + uint16_t WitnessTableSizeInWordsToCopy; + + /// The pattern. + RelativeDirectPointer Pattern; + + /// The instantiation function, which is called after the template is copied. + RelativeDirectPointer Instantiator; + + void *PrivateData[swift::NumGenericMetadataPrivateDataWords]; +}; + +/// The structure of a type metadata record. +/// +/// This contains enough static information to recover type metadata from a +/// name. It is only emitted for types that do not have an explicit protocol +/// conformance record. +/// +/// This structure is notionally a subtype of a protocol conformance record +/// but as we cannot change the conformance record layout we have to make do +/// with some duplicated code. +struct TypeMetadataRecord { +private: + // Some description of the type that is resolvable at runtime. + union { + /// A direct reference to the metadata. + RelativeDirectPointer DirectType; + + /// The nominal type descriptor for a resilient or generic type. + RelativeDirectPointer TypeDescriptor; + }; + + /// Flags describing the type metadata record. + TypeMetadataRecordFlags Flags; + +public: + TypeMetadataRecordKind getTypeKind() const { + return Flags.getTypeKind(); + } + + const Metadata *getDirectType() const { + switch (Flags.getTypeKind()) { + case TypeMetadataRecordKind::Universal: + return nullptr; + + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: + case TypeMetadataRecordKind::UniqueDirectClass: + break; + + case TypeMetadataRecordKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: + assert(false && "not direct type metadata"); + } + + return DirectType; + } + + const NominalTypeDescriptor *getNominalTypeDescriptor() const { + switch (Flags.getTypeKind()) { + case TypeMetadataRecordKind::Universal: + return nullptr; + + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: + break; + + case TypeMetadataRecordKind::UniqueDirectClass: + case TypeMetadataRecordKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: + assert(false && "not generic metadata pattern"); + } + + return TypeDescriptor; + } + + /// Get the canonical metadata for the type referenced by this record, or + /// return null if the record references a generic or universal type. + const Metadata *getCanonicalTypeMetadata() const; +}; + +struct FieldRecord { +private: + FieldRecordFlags Flags; + + union { + /// A direct reference to the metadata. + RelativeDirectPointer DirectType; + + /// A direct reference to a mangled name which must be + /// looked up in another binary image. + RelativeDirectPointer MangledTypeName; + }; + + RelativeDirectPointer FieldName; + +public: + const Metadata *getDirectType() const { + assert(isInternal() && "Field does not have an internal type metadata"); + return DirectType; + } + + const char *getTypeMangledName() const { + assert(isExternal() && "Field does not have an external type metadata"); + return MangledTypeName; + } + + const char *getFieldName() const { + return FieldName; + } + + bool isInternal() const { + return Flags.isInternal(); + } + + bool isExternal() const { + return Flags.isExternal(); + } + + Ownership getOwnership() const { + return Flags.getOwnership(); + } }; /// The structure of a protocol conformance record. @@ -2129,9 +2290,9 @@ struct ProtocolConformanceRecord { /// An indirect reference to the metadata. RelativeIndirectablePointer IndirectClass; - /// The generic metadata pattern for a generic type which has instances that - /// conform to the protocol. - RelativeIndirectablePointer GenericPattern; + /// The nominal type descriptor for a resilient or generic type which has + /// instances that conform to the protocol. + RelativeIndirectablePointer TypeDescriptor; }; @@ -2158,7 +2319,7 @@ struct ProtocolConformanceRecord { return Flags; } - ProtocolConformanceTypeKind getTypeKind() const { + TypeMetadataRecordKind getTypeKind() const { return Flags.getTypeKind(); } ProtocolConformanceReferenceKind getConformanceKind() const { @@ -2167,16 +2328,16 @@ struct ProtocolConformanceRecord { const Metadata *getDirectType() const { switch (Flags.getTypeKind()) { - case ProtocolConformanceTypeKind::Universal: + case TypeMetadataRecordKind::Universal: return nullptr; - case ProtocolConformanceTypeKind::UniqueDirectType: - case ProtocolConformanceTypeKind::NonuniqueDirectType: + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: break; - case ProtocolConformanceTypeKind::UniqueDirectClass: - case ProtocolConformanceTypeKind::UniqueIndirectClass: - case ProtocolConformanceTypeKind::UniqueGenericPattern: + case TypeMetadataRecordKind::UniqueDirectClass: + case TypeMetadataRecordKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: assert(false && "not direct type metadata"); } @@ -2186,15 +2347,15 @@ struct ProtocolConformanceRecord { // FIXME: This shouldn't exist const ClassMetadata *getDirectClass() const { switch (Flags.getTypeKind()) { - case ProtocolConformanceTypeKind::Universal: + case TypeMetadataRecordKind::Universal: return nullptr; - case ProtocolConformanceTypeKind::UniqueDirectClass: + case TypeMetadataRecordKind::UniqueDirectClass: break; - case ProtocolConformanceTypeKind::UniqueDirectType: - case ProtocolConformanceTypeKind::NonuniqueDirectType: - case ProtocolConformanceTypeKind::UniqueGenericPattern: - case ProtocolConformanceTypeKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: + case TypeMetadataRecordKind::UniqueIndirectClass: assert(false && "not direct class object"); } @@ -2205,38 +2366,38 @@ struct ProtocolConformanceRecord { const ClassMetadata * const *getIndirectClass() const { switch (Flags.getTypeKind()) { - case ProtocolConformanceTypeKind::Universal: + case TypeMetadataRecordKind::Universal: return nullptr; - case ProtocolConformanceTypeKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueIndirectClass: break; - case ProtocolConformanceTypeKind::UniqueDirectType: - case ProtocolConformanceTypeKind::UniqueDirectClass: - case ProtocolConformanceTypeKind::NonuniqueDirectType: - case ProtocolConformanceTypeKind::UniqueGenericPattern: + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::UniqueDirectClass: + case TypeMetadataRecordKind::NonuniqueDirectType: + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: assert(false && "not indirect class object"); } return IndirectClass; } - const GenericMetadata *getGenericPattern() const { + const NominalTypeDescriptor *getNominalTypeDescriptor() const { switch (Flags.getTypeKind()) { - case ProtocolConformanceTypeKind::Universal: + case TypeMetadataRecordKind::Universal: return nullptr; - case ProtocolConformanceTypeKind::UniqueGenericPattern: + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: break; - case ProtocolConformanceTypeKind::UniqueDirectClass: - case ProtocolConformanceTypeKind::UniqueIndirectClass: - case ProtocolConformanceTypeKind::UniqueDirectType: - case ProtocolConformanceTypeKind::NonuniqueDirectType: + case TypeMetadataRecordKind::UniqueDirectClass: + case TypeMetadataRecordKind::UniqueIndirectClass: + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: assert(false && "not generic metadata pattern"); } - return GenericPattern; + return TypeDescriptor; } /// Get the directly-referenced static witness table. @@ -2271,7 +2432,7 @@ struct ProtocolConformanceRecord { /// type. const swift::WitnessTable *getWitnessTable(const Metadata *type) const; -#if defined(NDEBUG) && SWIFT_OBJC_INTEROP +#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP void dump() const; #endif }; @@ -2302,27 +2463,6 @@ extern "C" const Metadata * swift_getGenericMetadata(GenericMetadata *pattern, const void *arguments); -// Fast entry points for swift_getGenericMetadata with a small number of -// template arguments. -extern "C" const Metadata * -swift_getGenericMetadata1(GenericMetadata *pattern, - const void *arg0); -extern "C" const Metadata * -swift_getGenericMetadata2(GenericMetadata *pattern, - const void *arg0, - const void *arg1); -extern "C" const Metadata * -swift_getGenericMetadata3(GenericMetadata *pattern, - const void *arg0, - const void *arg1, - const void *arg2); -extern "C" const Metadata * -swift_getGenericMetadata4(GenericMetadata *pattern, - const void *arg0, - const void *arg1, - const void *arg2, - const void *arg3); - // Callback to allocate a generic class metadata object. extern "C" ClassMetadata * swift_allocateGenericClassMetadata(GenericMetadata *pattern, @@ -2333,6 +2473,20 @@ swift_allocateGenericClassMetadata(GenericMetadata *pattern, extern "C" Metadata * swift_allocateGenericValueMetadata(GenericMetadata *pattern, const void *arguments); + +/// Instantiate a generic protocol witness table. +/// +/// +/// \param instantiationArgs - An opaque pointer that's forwarded to +/// the instantiation function, used for conditional conformances. +/// This API implicitly embeds an assumption that these arguments +/// never form part of the uniquing key for the conformance, which +/// is ultimately a statement about the user model of overlapping +/// conformances. +extern "C" const WitnessTable * +swift_getGenericWitnessTable(GenericWitnessTable *genericTable, + const Metadata *type, + void * const *instantiationArgs); /// \brief Fetch a uniqued metadata for a function type. extern "C" const FunctionTypeMetadata * @@ -2491,7 +2645,6 @@ struct ClassFieldLayout { /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. extern "C" void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, - const ClassMetadata *super, size_t numFields, const ClassFieldLayout *fieldLayouts, size_t *fieldOffsets); @@ -2785,17 +2938,11 @@ const WitnessTable *swift_conformsToProtocol(const Metadata *type, extern "C" void swift_registerProtocolConformances(const ProtocolConformanceRecord *begin, const ProtocolConformanceRecord *end); - -/// FIXME: This doesn't belong in the runtime. -extern "C" void swift_printAny(OpaqueValue *value, const Metadata *type); -/// \brief Demangle a mangled class name into module+class. -/// Returns true if the name was successfully decoded. -/// On success, *outModule and *outClass must be freed with free(). -extern "C" bool -swift_demangleSimpleClass(const char *mangledName, - char **outModule, char **outClass); - +/// Register a block of type metadata records dynamic lookup. +extern "C" +void swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, + const TypeMetadataRecord *end); /// Return the type name for a given type metadata. std::string nameForMetadata(const Metadata *type, diff --git a/include/swift/Runtime/ObjCBridge.h b/include/swift/Runtime/ObjCBridge.h index 01949cabdaba5..44f2ad4b7a3b3 100644 --- a/include/swift/Runtime/ObjCBridge.h +++ b/include/swift/Runtime/ObjCBridge.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -54,7 +54,7 @@ typedef struct objc_image_info { } objc_image_info; // Class and metaclass construction from a compiler-generated memory image. -// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.· +// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes. // Extra bytes not used the metadata must be zero. // info is the same objc_image_info that would be emitted by a static compiler. // Returns nil if a class with the same name already exists. diff --git a/include/swift/Runtime/Once.h b/include/swift/Runtime/Once.h index c31f0623a96e3..ee546272a46a4 100644 --- a/include/swift/Runtime/Once.h +++ b/include/swift/Runtime/Once.h @@ -1,8 +1,8 @@ -//===--- Once.h - Runtime support for lazy initialization ------*- C++ -*--===// +//===--- Once.h - Runtime support for lazy initialization -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Runtime/Reflection.h b/include/swift/Runtime/Reflection.h index 7a948faf57792..e29ad6242fb76 100644 --- a/include/swift/Runtime/Reflection.h +++ b/include/swift/Runtime/Reflection.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index 8849874e8fc3b..0909b5552f6a9 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -1,8 +1,8 @@ -//===--- AbstractionPattern.h - SIL type abstraction pattersn ---*- C++ -*-===// +//===--- AbstractionPattern.h - SIL type abstraction patterns ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -248,32 +248,8 @@ class AbstractionPattern { }; CanGenericSignature GenericSig; - static bool isOpaqueType(CanGenericSignature signature, CanType type) { - assert(signature || !type->hasTypeParameter()); - if (auto arch = dyn_cast(type)) - return !arch->requiresClass(); - // FIXME: Check class constraint of dependent types in their originating - // context. Even for direct parameters this requires a more principled - // check than this. - if (auto paramType = dyn_cast(type)) - return isOpaqueType(signature, paramType); - if (isa(type)) - return true; - return false; - } - - static bool isOpaqueType(CanGenericSignature signature, - CanGenericTypeParamType type); - Kind getKind() const { return Kind(TheKind); } - CanGenericSignature getGenericSignature() const { - assert(getKind() == Kind::Type || - hasStoredClangType() || - hasStoredObjCMethod()); - return CanGenericSignature(GenericSig); - } - CanGenericSignature getGenericSignatureForFunctionComponent() const { if (auto genericFn = dyn_cast(getType())) { return genericFn.getGenericSignature(); @@ -304,36 +280,29 @@ class AbstractionPattern { return hasStoredObjCMethod(); } - void initSwiftType(CanGenericSignature signature, CanType origType) { + void initSwiftType(CanGenericSignature signature, CanType origType, + Kind kind = Kind::Type) { assert(signature || !origType->hasTypeParameter()); - if (isOpaqueType(signature, origType)) { - TheKind = unsigned(Kind::Opaque); - } else { - TheKind = unsigned(Kind::Type); - OrigType = origType; + TheKind = unsigned(kind); + OrigType = origType; + GenericSig = CanGenericSignature(); + if (origType->hasTypeParameter()) GenericSig = signature; - } } void initClangType(CanGenericSignature signature, CanType origType, const clang::Type *clangType, Kind kind = Kind::ClangType) { - assert(!isOpaqueType(signature, origType)); - TheKind = unsigned(kind); - OrigType = origType; + initSwiftType(signature, origType, kind); ClangType = clangType; - GenericSig = signature; } void initObjCMethod(CanGenericSignature signature, CanType origType, const clang::ObjCMethodDecl *method, Kind kind, EncodedForeignErrorInfo errorInfo) { - assert(!isOpaqueType(signature, origType)); - TheKind = unsigned(kind); - OrigType = origType; + initSwiftType(signature, origType, kind); ObjCMethod = method; OtherData = errorInfo.getOpaqueValue(); - GenericSig = signature; } AbstractionPattern() {} @@ -362,6 +331,19 @@ class AbstractionPattern { return AbstractionPattern(Kind::Invalid); } + bool hasGenericSignature() const { + return (getKind() == Kind::Type || + hasStoredClangType() || + hasStoredObjCMethod()); + } + + CanGenericSignature getGenericSignature() const { + assert(getKind() == Kind::Type || + hasStoredClangType() || + hasStoredObjCMethod()); + return CanGenericSignature(GenericSig); + } + /// Return an open-coded abstraction pattern for a tuple. The /// caller is responsible for ensuring that the storage for the /// tuple elements is valid for as long as the abstraction pattern is. @@ -498,10 +480,43 @@ class AbstractionPattern { return getKind() != Kind::Invalid; } - /// Is this abstraction pattern fully opaque? - bool isOpaque() const { - assert(isValid()); - return getKind() == Kind::Opaque; + bool isTypeParameter() const { + switch (getKind()) { + case Kind::Opaque: + return true; + case Kind::Type: { + auto type = getType(); + if (isa(type) || + isa(type) || + isa(type)) { + return true; + } + return false; + } + default: + return false; + } + } + + bool requiresClass(ModuleDecl &module) { + switch (getKind()) { + case Kind::Opaque: + return false; + case Kind::Type: { + auto type = getType(); + if (auto archetype = dyn_cast(type)) + return archetype->requiresClass(); + else if (isa(type) || + isa(type)) { + assert(GenericSig && + "Dependent type in pattern without generic signature?"); + return GenericSig->requiresClass(type, module); + } + return false; + } + default: + return false; + } } /// Return the Swift type which provides structure for this diff --git a/include/swift/SIL/BridgedTypes.def b/include/swift/SIL/BridgedTypes.def index 0b725397e1ac7..9e95c144233cd 100644 --- a/include/swift/SIL/BridgedTypes.def +++ b/include/swift/SIL/BridgedTypes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/CFG.h b/include/swift/SIL/CFG.h index b253fcb5858e9..281ccb4d5ff84 100644 --- a/include/swift/SIL/CFG.h +++ b/include/swift/SIL/CFG.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/Consumption.h b/include/swift/SIL/Consumption.h index 7a6b34ff8ac50..31ac3541b4c29 100644 --- a/include/swift/SIL/Consumption.h +++ b/include/swift/SIL/Consumption.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/DebugUtils.h b/include/swift/SIL/DebugUtils.h index 3550e7b77f818..99746b4f8bd02 100644 --- a/include/swift/SIL/DebugUtils.h +++ b/include/swift/SIL/DebugUtils.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -59,13 +59,13 @@ inline void deleteAllDebugUses(ValueBase *Inst) { } /// This iterator filters out any debug (or non-debug) instructions from a range -/// of uses, provided by the underlying use-iterator \p Base. +/// of uses, provided by the underlying ValueBaseUseIterator. /// If \p nonDebugInsts is true, then the iterator provides a view to all non- /// debug instructions. Otherwise it provides a view ot all debug-instructions. -template class DebugUseIterator +template class DebugUseIterator : public std::iterator { - Base BaseIterator; + ValueBaseUseIterator BaseIterator; // Skip any debug or non-debug instructions (depending on the nonDebugInsts // template argument). @@ -84,7 +84,8 @@ template class DebugUseIterator public: - DebugUseIterator(Base BaseIterator) : BaseIterator(BaseIterator) { + DebugUseIterator(ValueBaseUseIterator BaseIterator) : + BaseIterator(BaseIterator) { skipInsts(); } @@ -116,52 +117,43 @@ template class DebugUseIterator }; /// Iterator for iteration over debug instructions. -template using DUIterator = - DebugUseIterator; +using DUIterator = DebugUseIterator; /// Iterator for iteration over non-debug instructions. -template using NonDUIterator = - DebugUseIterator; +using NonDUIterator = DebugUseIterator; /// Returns a range of all debug instructions in the uses of a value (e.g. /// SILValue or SILInstruction). -template -inline iterator_range> getDebugUses(const V &value) { - return make_range(DUIterator(value.use_begin()), - DUIterator(value.use_end())); +inline iterator_range getDebugUses(SILValue V) { + return make_range(DUIterator(V->use_begin()), DUIterator(V->use_end())); } /// Returns a range of all non-debug instructions in the uses of a value (e.g. /// SILValue or SILInstruction). -template -inline iterator_range> getNonDebugUses(const V &value) { - return make_range(NonDUIterator(value.use_begin()), - NonDUIterator(value.use_end())); +inline iterator_range getNonDebugUses(SILValue V) { + return make_range(NonDUIterator(V->use_begin()), NonDUIterator(V->use_end())); } /// Returns true if a value (e.g. SILInstruction) has no uses except debug /// instructions. -template -inline bool hasNoUsesExceptDebug(V *I) { - auto NonDebugUses = getNonDebugUses(*I); +inline bool hasNoUsesExceptDebug(SILValue V) { + auto NonDebugUses = getNonDebugUses(V); return NonDebugUses.begin() == NonDebugUses.end(); } /// Returns true if a value (e.g. SILInstruction) has exactly one use which is /// not a debug instruction. -template -inline bool hasOneNonDebugUse(const V &value) { - auto Range = getNonDebugUses(value); +inline bool hasOneNonDebugUse(SILValue V) { + auto Range = getNonDebugUses(V); auto I = Range.begin(), E = Range.end(); if (I == E) return false; return ++I == E; } // Returns the use if the value has only one non debug user. -template -inline SILInstruction *getSingleNonDebugUser(const V &value) { - auto Range = getNonDebugUses(value); +inline SILInstruction *getSingleNonDebugUser(SILValue V) { + auto Range = getNonDebugUses(V); auto I = Range.begin(), E = Range.end(); if (I == E) return nullptr; if (std::next(I) != E) diff --git a/include/swift/SIL/Dominance.h b/include/swift/SIL/Dominance.h index a98cee032c69f..62da9a5f15912 100644 --- a/include/swift/SIL/Dominance.h +++ b/include/swift/SIL/Dominance.h @@ -1,8 +1,8 @@ -//===--- Dominance.h - SIL dominance analysis ------------------*- C++ -*-===// +//===--- Dominance.h - SIL dominance analysis -------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -138,6 +138,16 @@ class PostDominanceInfo : public llvm::DominatorTreeBase { if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) return true; + if (!R->getBlock()) { + // The post dom-tree has multiple roots. The compare() function can not + // cope with multiple roots if at least one of the roots is caused by + // an infinite loop in the CFG (it crashes because no nodes are allocated + // for the blocks in the infinite loop). + // So we return a conservative false in this case. + // TODO: eventually fix the DominatorTreeBase::compare() function. + return false; + } + // Returns *false* if they match. if (compare(Other)) return true; diff --git a/include/swift/SIL/DynamicCasts.h b/include/swift/SIL/DynamicCasts.h index bed027ce33933..695f84172e400 100644 --- a/include/swift/SIL/DynamicCasts.h +++ b/include/swift/SIL/DynamicCasts.h @@ -1,8 +1,8 @@ -//===--- DynamicsCasts.h - SIL dynamic-cast utilities -----------*- C++ -*-===// +//===--- DynamicCasts.h - SIL dynamic-cast utilities ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -24,7 +24,6 @@ class CanType; class ModuleDecl; class SILBuilder; class SILLocation; -class SILValue; class SILModule; class SILType; enum class CastConsumptionKind : unsigned char; diff --git a/include/swift/SIL/FormalLinkage.h b/include/swift/SIL/FormalLinkage.h index 5bc39f676c1ac..f6fa16de6c6a3 100644 --- a/include/swift/SIL/FormalLinkage.h +++ b/include/swift/SIL/FormalLinkage.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h new file mode 100644 index 0000000000000..50e2ef433df7e --- /dev/null +++ b/include/swift/SIL/InstructionUtils.h @@ -0,0 +1,65 @@ +//===--- InstructionUtils.h - Utilities for SIL instructions ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_INSTRUCTIONUTILS_H +#define SWIFT_SIL_INSTRUCTIONUTILS_H + +#include "swift/SIL/SILInstruction.h" + +namespace swift { + +/// Strip off casts/indexing insts/address projections from V until there is +/// nothing left to strip. +SILValue getUnderlyingObject(SILValue V); + +SILValue stripSinglePredecessorArgs(SILValue V); + +/// Return the underlying SILValue after stripping off all casts from the +/// current SILValue. +SILValue stripCasts(SILValue V); + +/// Return the underlying SILValue after stripping off all upcasts from the +/// current SILValue. +SILValue stripUpCasts(SILValue V); + +/// Return the underlying SILValue after stripping off all +/// upcasts and downcasts. +SILValue stripClassCasts(SILValue V); + +/// Return the underlying SILValue after stripping off all address projection +/// instructions. +SILValue stripAddressProjections(SILValue V); + +/// Return the underlying SILValue after stripping off all address projection +/// instructions which have a single operand. +SILValue stripUnaryAddressProjections(SILValue V); + +/// Return the underlying SILValue after stripping off all aggregate projection +/// instructions. +/// +/// An aggregate projection instruction is either a struct_extract or a +/// tuple_extract instruction. +SILValue stripValueProjections(SILValue V); + +/// Return the underlying SILValue after stripping off all indexing +/// instructions. +/// +/// An indexing inst is either index_addr or index_raw_pointer. +SILValue stripIndexingInsts(SILValue V); + +/// Returns the underlying value after stripping off a builtin expect +/// intrinsic call. +SILValue stripExpectIntrinsic(SILValue V); + +} // end namespace swift + +#endif diff --git a/include/swift/SIL/LoopInfo.h b/include/swift/SIL/LoopInfo.h index 73f8b4d581fac..7a761a9d95e59 100644 --- a/include/swift/SIL/LoopInfo.h +++ b/include/swift/SIL/LoopInfo.h @@ -1,8 +1,8 @@ -//===-------------- LoopInfo.h - SIL Loop Analysis -----*- C++ -*----------===// +//===--- LoopInfo.h - SIL Loop Analysis -------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/Mangle.h b/include/swift/SIL/Mangle.h index 4d77c5e673209..1425aead3dcad 100644 --- a/include/swift/SIL/Mangle.h +++ b/include/swift/SIL/Mangle.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,8 +26,6 @@ namespace swift { class AbstractClosureExpr; -namespace Mangle { - enum class SpecializationKind : uint8_t { Generic, FunctionSignature, @@ -40,7 +38,7 @@ class SpecializationManglerBase { protected: SpecializationKind Kind; SpecializationPass Pass; - Mangler &M; + Mangle::Mangler &M; SILFunction *Function; public: @@ -57,34 +55,34 @@ class SpecializationManglerBase { protected: SpecializationManglerBase(SpecializationKind K, SpecializationPass P, - Mangler &M, SILFunction *F) + Mangle::Mangler &M, SILFunction *F) : Kind(K), Pass(P), M(M), Function(F) {} - llvm::raw_ostream &getBuffer() { return M.Buffer; } SILFunction *getFunction() const { return Function; } - Mangler &getMangler() const { return M; } + Mangle::Mangler &getMangler() const { return M; } void mangleKind() { switch (Kind) { case SpecializationKind::Generic: - M.Buffer << "g"; + M.append("g"); break; case SpecializationKind::FunctionSignature: - M.Buffer << "f"; + M.append("f"); break; } } void manglePass() { - M.Buffer << encodeSpecializationPass(Pass); + M.append(encodeSpecializationPass(Pass)); } void mangleSpecializationPrefix() { - M.Buffer << "_TTS"; + M.append("_TTS"); } void mangleFunctionName() { - M.Buffer << "_" << Function->getName(); + M.append("_"); + M.appendSymbol(Function->getName()); } }; @@ -112,8 +110,8 @@ class SpecializationMangler : public SpecializationManglerBase { } protected: - SpecializationMangler(SpecializationKind K, SpecializationPass P, Mangler &M, - SILFunction *F) + SpecializationMangler(SpecializationKind K, SpecializationPass P, + Mangle::Mangler &M, SILFunction *F) : SpecializationManglerBase(K, P, M, F) {} }; @@ -125,7 +123,7 @@ class GenericSpecializationMangler : ArrayRef Subs; public: - GenericSpecializationMangler(Mangler &M, SILFunction *F, + GenericSpecializationMangler(Mangle::Mangler &M, SILFunction *F, ArrayRef Subs) : SpecializationMangler(SpecializationKind::Generic, SpecializationPass::GenericSpecializer, @@ -165,7 +163,7 @@ class FunctionSignatureSpecializationMangler public: FunctionSignatureSpecializationMangler(SpecializationPass Pass, - Mangler &M, SILFunction *F); + Mangle::Mangler &M, SILFunction *F); void setArgumentConstantProp(unsigned ArgNo, LiteralInst *LI); void setArgumentClosureProp(unsigned ArgNo, PartialApplyInst *PAI); void setArgumentClosureProp(unsigned ArgNo, ThinToThickFunctionInst *TTTFI); @@ -184,7 +182,6 @@ class FunctionSignatureSpecializationMangler NullablePtr Inst); }; -} // end namespace Mangle } // end namespace swift #endif diff --git a/include/swift/SIL/Notifications.h b/include/swift/SIL/Notifications.h index 850280a086670..244f749bb517a 100644 --- a/include/swift/SIL/Notifications.h +++ b/include/swift/SIL/Notifications.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h index 68df32c62aea8..0eb909e75d411 100644 --- a/include/swift/SIL/PatternMatch.h +++ b/include/swift/SIL/PatternMatch.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -136,7 +136,7 @@ inline match_combine_and m_CombineAnd(const LTy &L, const RTy &R) { /// Helper class to track the return type of vararg m_CombineOr matcher. template -struct OneOf_match; +struct OneOf_match; template struct OneOf_match { @@ -404,8 +404,8 @@ struct BinaryOp_match { if (!I || I->getNumOperands() != 2) return false; - return L.match(I->getOperand(0).getDef()) && - R.match(I->getOperand(1).getDef()); + return L.match((ValueBase *)I->getOperand(0)) && + R.match((ValueBase *)I->getOperand(1)); } }; @@ -431,7 +431,7 @@ struct tupleextract_ty { if (!TEI) return false; - return TEI->getFieldNo() == index && L.match(TEI->getOperand().getDef()); + return TEI->getFieldNo() == index && L.match((ValueBase *)TEI->getOperand()); } }; @@ -522,10 +522,10 @@ struct Argument_match { template bool match(ITy *V) { if (auto *Apply = dyn_cast(V)) { - return Val.match(Apply->getArgument(OpI).getDef()); + return Val.match((ValueBase *)Apply->getArgument(OpI)); } if (auto *Builtin = dyn_cast(V)) { - return Val.match(Builtin->getArguments()[OpI].getDef()); + return Val.match((ValueBase *)Builtin->getArguments()[OpI]); } return false; } @@ -711,8 +711,8 @@ m_Ext(const T0 &Op0) { /// Matcher for any of the builtin CheckedTrunc instructions. template -inline typename OneOf_match, BuiltinApplyTy, - BuiltinApplyTy, BuiltinApplyTy>::Ty +inline typename OneOf_match, BuiltinApplyTy, + BuiltinApplyTy, BuiltinApplyTy>::Ty m_CheckedTrunc(const T0 &Op0) { return m_UToSCheckedTrunc(Op0) || m_SToUCheckedTrunc(Op0) || m_UToUCheckedTrunc(Op0) || m_SToSCheckedTrunc(Op0); diff --git a/include/swift/SIL/PrettyStackTrace.h b/include/swift/SIL/PrettyStackTrace.h index 8baaf11021723..0459d186e3476 100644 --- a/include/swift/SIL/PrettyStackTrace.h +++ b/include/swift/SIL/PrettyStackTrace.h @@ -1,8 +1,8 @@ -//===- PrettyStackTrace.h - Crash trace information -------------*- C++ -*-===// +//===--- PrettyStackTrace.h - Crash trace information -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/Projection.h b/include/swift/SIL/Projection.h index a555e9b9917ba..e89d919c2ade6 100644 --- a/include/swift/SIL/Projection.h +++ b/include/swift/SIL/Projection.h @@ -1,8 +1,8 @@ -//===--- Projection.h - Utilities for working with Projections -*- C++ -*-===// +//===--- Projection.h - Utilities for working with Projections --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,8 @@ #define SWIFT_SIL_PROJECTION_H #include "swift/Basic/NullablePtr.h" +#include "swift/Basic/PointerIntEnum.h" +#include "swift/AST/TypeAlignments.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/SILInstruction.h" #include "llvm/ADT/Hashing.h" @@ -27,13 +29,14 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/Allocator.h" -#include namespace swift { class SILBuilder; class ProjectionPath; +class NewProjectionPath; using ProjectionPathList = llvm::SmallVector, 8>; +using NewProjectionPathList = llvm::SmallVector, 8>; enum class SubSeqRelation_t : uint8_t { Unknown, @@ -92,6 +95,13 @@ struct ProjectionIndex { Aggregate = REA->getOperand(); break; } + case ValueKind::ProjectBoxInst: { + ProjectBoxInst *PBI = cast(V); + // A box has only a single payload. + Index = 0; + Aggregate = PBI->getOperand(); + break; + } case ValueKind::TupleElementAddrInst: { TupleElementAddrInst *TEA = cast(V); Index = TEA->getFieldNo(); @@ -112,16 +122,559 @@ struct ProjectionIndex { } } } - bool isValid() const { return Aggregate.isValid(); } + bool isValid() const { return (bool)Aggregate; } }; /// The kind of projection that we are representing. -enum class ProjectionKind : uint8_t { +/// +/// We represent types that need to have a type pointer (i.e. casts) using only +/// up to 3 bits. This is because types are only aligned up to 8 bits. See +/// TypeAlignments.h. +/// +/// Projection Kinds which can be represented via indices can use as many bits +/// as they want to represent the kind. When the index value is uses at most 11 +/// bits, we represent it inline in the data structure. This is taking advantage +/// of the fact that on most modern OSes (including Darwin), the zero page is +/// not allocated. In the case where we have more than 11 bits of value +/// (i.e. the index is >= 2048), we malloc memory to represent the index. In +/// most cases this will not happen. For simplicity, we limit such kinds to use +/// no more than 4 bits. +/// +/// The NewProjection class contains the logic to use NewProjectionKind in this +/// manner. +enum class NewProjectionKind : unsigned { + // PointerProjectionKinds + Upcast = 0, + RefCast = 1, + BitwiseCast = 2, + FirstPointerKind = Upcast, + LastPointerKind = BitwiseCast, + + // Index Projection Kinds + FirstIndexKind = 7, + Struct = PointerIntEnumIndexKindValue<0, NewProjectionKind>::value, + Tuple = PointerIntEnumIndexKindValue<1, NewProjectionKind>::value, + Index = PointerIntEnumIndexKindValue<2, NewProjectionKind>::value, + Class = PointerIntEnumIndexKindValue<3, NewProjectionKind>::value, + Enum = PointerIntEnumIndexKindValue<4, NewProjectionKind>::value, + Box = PointerIntEnumIndexKindValue<5, NewProjectionKind>::value, + LastIndexKind = Enum, +}; + +constexpr unsigned MaxPointerProjectionKind = ((1 << TypeAlignInBits) - 1); +/// Make sure that our tagged pointer assumptions are true. See comment above +/// the declaration of NewProjectionKind. +static_assert(unsigned(NewProjectionKind::LastPointerKind) <= + unsigned(MaxPointerProjectionKind), + "Too many projection kinds to fit in Projection"); + +static inline bool isCastNewProjectionKind(NewProjectionKind Kind) { + switch (Kind) { + case NewProjectionKind::Upcast: + case NewProjectionKind::RefCast: + case NewProjectionKind::BitwiseCast: + return true; + case NewProjectionKind::Struct: + case NewProjectionKind::Tuple: + case NewProjectionKind::Index: + case NewProjectionKind::Class: + case NewProjectionKind::Enum: + case NewProjectionKind::Box: + return false; + } +} + +/// An abstract representation of the index of a subtype of an aggregate +/// type. This is a value type. +/// +/// The intention is it to be paired with a base SILValue in order to provide a +/// lightweight manner of working at a high level with object and address +/// projections. +/// +/// It is intended to be pointer sized and trivially copyable so that memcpy can +/// be used to copy a NewProjection. +class NewProjection { + + friend NewProjectionPath; + + static constexpr unsigned NumPointerKindBits = TypeAlignInBits; + + /// This is the number of bits that we currently use to represent indices at + /// the top of our word. + static constexpr unsigned NumIndexKindBits = 4; + + using ValueTy = PointerIntEnum; + /// A pointer sized type that is used to store the kind of projection that is + /// being represented and also all of the necessary information to convert a + /// base SILType to a derived field SILType. + ValueTy Value; + +public: + NewProjection() = delete; + + explicit NewProjection(SILValue V) + : NewProjection(dyn_cast(V)) {} + explicit NewProjection(SILInstruction *I); + + NewProjection(NewProjection &&P) = default; + NewProjection(const NewProjection &P) = default; + ~NewProjection() = default; + + NewProjection &operator=(const NewProjection &P) = default; + + NewProjection &operator=(NewProjection &&P) = default; + + bool isValid() const { return Value.isValid(); } + + /// Determine if I is a value projection instruction whose corresponding + /// projection equals this projection. + bool matchesObjectProjection(SILInstruction *I) const { + NewProjection P(I); + return P.isValid() && P == *this; + } + + /// If Base's type matches this Projections type ignoring Address vs Object + /// type differences and this Projection is representable as a value + /// projection, create the relevant value projection and return it. Otherwise, + /// return nullptr. + NullablePtr + createObjectProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const; + + /// If Base's type matches this Projections type ignoring Address vs Object + /// type differences and this projection is representable as an address + /// projection, create the relevant address projection and return + /// it. Otherwise, return nullptr. + NullablePtr + createAddressProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const; + + /// Apply this projection to \p BaseType and return the relevant subfield's + /// SILType if BaseField has less subtypes than projection's offset. + SILType getType(SILType BaseType, SILModule &M) const { + assert(isValid()); + switch (getKind()) { + case NewProjectionKind::Struct: + case NewProjectionKind::Class: + return BaseType.getFieldType(getVarDecl(BaseType), M); + case NewProjectionKind::Enum: + return BaseType.getEnumElementType(getEnumElementDecl(BaseType), M); + case NewProjectionKind::Box: + return SILType::getPrimitiveAddressType(BaseType.castTo()-> + getBoxedType()); + case NewProjectionKind::Tuple: + return BaseType.getTupleElementType(getIndex()); + case NewProjectionKind::Upcast: + case NewProjectionKind::RefCast: + case NewProjectionKind::BitwiseCast: + return getCastType(BaseType); + case NewProjectionKind::Index: + // Index types do not change the underlying type. + return BaseType; + } + } + + VarDecl *getVarDecl(SILType BaseType) const { + assert(isValid()); + assert((getKind() == NewProjectionKind::Struct || + getKind() == NewProjectionKind::Class)); + assert(BaseType.getNominalOrBoundGenericNominal() && + "This should only be called with a nominal type"); + auto *NDecl = BaseType.getNominalOrBoundGenericNominal(); + auto Iter = NDecl->getStoredProperties().begin(); + std::advance(Iter, getIndex()); + return *Iter; + } + + EnumElementDecl *getEnumElementDecl(SILType BaseType) const { + assert(isValid()); + assert(getKind() == NewProjectionKind::Enum); + assert(BaseType.getEnumOrBoundGenericEnum() && "Expected enum type"); + auto Iter = BaseType.getEnumOrBoundGenericEnum()->getAllElements().begin(); + std::advance(Iter, getIndex()); + return *Iter; + } + + ValueDecl *getValueDecl(SILType BaseType) const { + assert(isValid()); + switch (getKind()) { + case NewProjectionKind::Enum: + return getEnumElementDecl(BaseType); + case NewProjectionKind::Struct: + case NewProjectionKind::Class: + return getVarDecl(BaseType); + case NewProjectionKind::Upcast: + case NewProjectionKind::RefCast: + case NewProjectionKind::BitwiseCast: + case NewProjectionKind::Index: + case NewProjectionKind::Tuple: + case NewProjectionKind::Box: + llvm_unreachable("NewProjectionKind that does not have a value decl?"); + } + } + + SILType getCastType(SILType BaseType) const { + assert(isValid()); + assert(getKind() == NewProjectionKind::Upcast || + getKind() == NewProjectionKind::RefCast || + getKind() == NewProjectionKind::BitwiseCast); + auto *Ty = getPointer(); + assert(Ty->isCanonical()); + return SILType::getPrimitiveType(Ty->getCanonicalType(), + BaseType.getCategory()); + } + + bool operator==(const NewProjection &Other) const { + return Value == Other.Value; + } + + bool operator!=(const NewProjection &Other) const { + return !(*this == Other); + } + + /// Convenience method for getting the raw underlying kind. + NewProjectionKind getKind() const { return *Value.getKind(); } + + /// Returns true if this instruction projects from an address type to an + /// address subtype. + static bool isAddressProjection(SILValue V) { + switch (V->getKind()) { + default: + return false; + case ValueKind::IndexAddrInst: { + unsigned Scalar; + return getIntegerIndex(cast(V)->getIndex(), Scalar); + } + case ValueKind::StructElementAddrInst: + case ValueKind::RefElementAddrInst: + case ValueKind::ProjectBoxInst: + case ValueKind::TupleElementAddrInst: + case ValueKind::UncheckedTakeEnumDataAddrInst: + return true; + } + } + + /// Returns true if this instruction projects from an object type to an object + /// subtype. + static bool isObjectProjection(SILValue V) { + switch (V->getKind()) { + default: + return false; + case ValueKind::StructExtractInst: + case ValueKind::TupleExtractInst: + return true; + } + } + + /// Returns true if this instruction projects from an object type into an + /// address subtype. + static bool isObjectToAddressProjection(SILValue V) { + return isa(V) || isa(V); + } + + /// Given a specific SILType, return all first level projections if it is an + /// aggregate. + static void getFirstLevelProjections(SILType V, SILModule &Mod, + llvm::SmallVectorImpl &Out); + + /// Is this cast which only allows for equality? + /// + /// If we enforce strict type based aliasing when computing access paths this + /// will not be necessary. For now we are conservative since I don't have time + /// to track down potential miscompiles. If we introduce such a thing, we will + /// need a new instruction that a frontend can use to introduce aliasing + /// relationships when TBAA would say that aliasing can not occur. + bool isAliasingCast() const { + switch (getKind()) { + case NewProjectionKind::RefCast: + case NewProjectionKind::BitwiseCast: + return true; + case NewProjectionKind::Upcast: + case NewProjectionKind::Struct: + case NewProjectionKind::Tuple: + case NewProjectionKind::Index: + case NewProjectionKind::Class: + case NewProjectionKind::Enum: + case NewProjectionKind::Box: + return false; + } + } + + bool isNominalKind() const { + switch (getKind()) { + case NewProjectionKind::Class: + case NewProjectionKind::Enum: + case NewProjectionKind::Struct: + return true; + case NewProjectionKind::BitwiseCast: + case NewProjectionKind::Index: + case NewProjectionKind::RefCast: + case NewProjectionKind::Tuple: + case NewProjectionKind::Upcast: + case NewProjectionKind::Box: + return false; + } + } + +private: + /// Convenience method for getting the underlying index. Assumes that this + /// projection is valid. Otherwise it asserts. + unsigned getIndex() const { + return Value.getIndex(); + } + + /// Convenience method for getting the raw underlying index as a pointer. + TypeBase *getPointer() const { + return Value.getPointer(); + } + + NewProjection(NewProjectionKind Kind, unsigned NewIndex) + : Value(Kind, NewIndex) {} + + NewProjection(NewProjectionKind Kind, TypeBase *Ptr) + : Value(Kind, Ptr) {} +}; + +/// This is to make sure that new projection is never bigger than a +/// pointer. This is just for performance. +static_assert(sizeof(NewProjection) == sizeof(uintptr_t), + "IndexType should be pointer sized"); + +/// A "path" of projections abstracting either value or aggregate projections +/// upon a value. +/// +/// The main purpose of this class is to enable one to reason about iterated +/// chains of projections. Some example usages are: +/// +/// 1. Converting value projections to aggregate projections or vis-a-versa. +/// 2. Performing tuple operations on two paths (using the mathematical +/// definition of tuples as ordered sets). +class NewProjectionPath { +public: + using PathTy = llvm::SmallVector; + +private: + SILType BaseType; + SILType MostDerivedType; + PathTy Path; + +public: + /// Create an empty path which serves as a stack. Use push_back() to populate + /// the stack with members. + NewProjectionPath(SILType Base) + : BaseType(Base), MostDerivedType(SILType()), Path() {} + NewProjectionPath(SILType Base, SILType End) + : BaseType(Base), MostDerivedType(End), Path() {} + ~NewProjectionPath() = default; + + /// Do not allow copy construction. The only way to get one of these is from + /// getProjectionPath. + NewProjectionPath(const NewProjectionPath &Other) { + BaseType = Other.BaseType; + MostDerivedType = Other.MostDerivedType; + Path = Other.Path; + } + + NewProjectionPath &operator=(const NewProjectionPath &O) { + BaseType = O.BaseType; + MostDerivedType = O.MostDerivedType; + Path = O.Path; + return *this; + } + + /// We only allow for moves of NewProjectionPath since we only want them to be + /// able to be constructed by calling our factory method. + NewProjectionPath(NewProjectionPath &&O) { + BaseType = O.BaseType; + MostDerivedType = O.MostDerivedType; + Path = O.Path; + O.BaseType = SILType(); + O.MostDerivedType = SILType(); + O.Path.clear(); + } + + NewProjectionPath &operator=(NewProjectionPath &&O) { + BaseType = O.BaseType; + MostDerivedType = O.MostDerivedType; + Path = O.Path; + O.BaseType = SILType(); + O.MostDerivedType = SILType(); + O.Path.clear(); + return *this; + } + + /// Append the projection \p P onto this. + NewProjectionPath &append(const NewProjection &P) { + push_back(P); + // Invalidate most derived type. + MostDerivedType = SILType(); + return *this; + } + + /// Append the projections in \p Other onto this. + NewProjectionPath &append(const NewProjectionPath &Other) { + for (auto &X : Other.Path) { + push_back(X); + } + // Invalidate most derived type. + MostDerivedType = SILType(); + return *this; + } + + /// Create a new projection path from the SILValue Start to End. Returns + /// Nothing::None if there is no such path. + /// + /// *NOTE* This method allows for transitions from object types to address + /// types via ref_element_addr. If Start is an address type though, End will + /// always also be an address type. + static Optional getProjectionPath(SILValue Start, + SILValue End); + + /// Treating a projection path as an ordered set, if RHS is a prefix of LHS, + /// return the projection path with that prefix removed. + /// + /// An example of this transformation would be: + /// + /// LHS = [A, B, C, D, E], RHS = [A, B, C] => Result = [D, E] + static Optional + removePrefix(const NewProjectionPath &Path, const NewProjectionPath &Prefix); + + /// Given the SILType Base, expand every leaf nodes in the type tree. + /// + /// NOTE: this function returns a single empty projection path if the BaseType + /// is a leaf node in the type tree. + static void expandTypeIntoLeafProjectionPaths(SILType BaseType, + SILModule *Mod, + NewProjectionPathList &P); + + /// Given the SILType Base, expand every intermediate and leaf nodes in the + /// type tree. + /// + /// NOTE: this function returns a single empty projection path if the BaseType + /// is a leaf node in the type tree. + static void expandTypeIntoNodeProjectionPaths(SILType BaseType, + SILModule *Mod, + NewProjectionPathList &P); + + /// Returns true if the two paths have a non-empty symmetric + /// difference. + /// + /// This means that the two objects have the same base but access different + /// fields of the base object. + bool hasNonEmptySymmetricDifference(const NewProjectionPath &RHS) const; + + /// Compute the subsequence relation in between LHS and RHS which tells the + /// user whether or not the two sequences are unrelated, equal, or if one is a + /// subsequence of the other. + SubSeqRelation_t computeSubSeqRelation(const NewProjectionPath &RHS) const; + + /// Returns true if this is a projection path that takes an address base type + /// to an address derived type. + bool isAddressProjectionPath() const; + + /// Returns true if this is a projection path that takes an object base type + /// to an object derived type. + bool isObjectProjectionPath() const; + + /// Find all object projection paths from I that matches this projection + /// path. Return the tails of each extract path in T. + bool + findMatchingObjectProjectionPaths(SILInstruction *I, + SmallVectorImpl &T) const; + + /// If this is an address projection path and \p Base is a SILValue with the + /// object version of said type, use \p B and \p Loc to recreate the stored + /// address projection path as an object projection path from \p Base. Return + /// the SILValue at the end of the path. + SILValue createObjectProjections(SILBuilder &B, SILLocation Loc, + SILValue Base); + + /// Pushes an element to the path. + void push_back(const NewProjection &Proj) { Path.push_back(Proj); } + + /// Removes the last element from the path. + void pop_back() { Path.pop_back(); } + + /// Returns the last element of the path. + const NewProjection &back() const { return Path.back(); } + + /// Returns true if LHS and RHS have all the same projections in the same + /// order. + bool operator==(const NewProjectionPath &RHS) const { + return computeSubSeqRelation(RHS) == SubSeqRelation_t::Equal; + } + + bool operator!=(const NewProjectionPath &RHS) const { + return !(*this == RHS); + } + + /// Returns the base type of the ProjectionPath. + SILType getBaseType() const { return BaseType; } + + /// Returns the most derived type of the projection path. + SILType getMostDerivedType(SILModule &M) { + if (Path.empty()) + return getBaseType(); + if (MostDerivedType) + return MostDerivedType; + MostDerivedType = getDerivedType(Path.size(), M); + return MostDerivedType; + } + + /// Returns the ith derived type of the path. This is zero indexed with 0 + /// being the base type and n consisting of applying the up to n projections + /// to the base type. + SILType getDerivedType(unsigned i, SILModule &M) const { + assert(i <= Path.size()); + SILType IterTy = getBaseType(); + if (i == 0) + return IterTy; + for (unsigned j : range(i)) { + auto &Proj = Path[j]; + IterTy = Proj.getType(IterTy, M); + } + return IterTy; + } + + /// Returns true if the contained projection path is empty. + bool empty() const { return Path.empty(); } + + /// Returns the number of path elements in the given projection path. + unsigned size() const { return Path.size(); } + + using iterator = PathTy::iterator; + using const_iterator = PathTy::const_iterator; + using reverse_iterator = PathTy::reverse_iterator; + using const_reverse_iterator = PathTy::const_reverse_iterator; + + iterator begin() { return Path.begin(); } + iterator end() { return Path.end(); } + const_iterator begin() const { return Path.begin(); } + const_iterator end() const { return Path.end(); } + + reverse_iterator rbegin() { return Path.rbegin(); } + reverse_iterator rend() { return Path.rend(); } + const_reverse_iterator rbegin() const { return Path.rbegin(); } + const_reverse_iterator rend() const { return Path.rend(); } + + void verify(SILModule &M); + + raw_ostream &print(raw_ostream &OS, SILModule &M); + raw_ostream &printProjections(raw_ostream &OS, SILModule &M) const; + void dump(SILModule &M); + void dumpProjections(SILModule &M) const; +}; + +//===----------------------------------------------------------------------===// +// Projection +//===----------------------------------------------------------------------===// + +enum class ProjectionKind : unsigned { Struct, Tuple, Index, Class, Enum, + Box, LastProjectionKind = Enum, }; @@ -209,6 +762,7 @@ class Projection { case ValueKind::StructElementAddrInst: case ValueKind::TupleElementAddrInst: case ValueKind::RefElementAddrInst: + case ValueKind::ProjectBoxInst: case ValueKind::UncheckedTakeEnumDataAddrInst: return true; default: @@ -216,6 +770,23 @@ class Projection { } } + /// Helper method that returns isAddrProjection(I->getKind()); + static bool isIndexProjection(SILValue V) { + switch (V->getKind()) { + case ValueKind::IndexAddrInst: { + unsigned Scalar; + return getIntegerIndex(cast(V)->getIndex(), Scalar); + } + case ValueKind::StructElementAddrInst: + case ValueKind::TupleElementAddrInst: + case ValueKind::RefElementAddrInst: + case ValueKind::ProjectBoxInst: + case ValueKind::UncheckedTakeEnumDataAddrInst: + default: + return false; + } + } + /// Helper method that returns isValueProjection(I->getKind()); static bool isValueProjection(SILValue V) { return isValueProjection(V->getKind()); @@ -273,6 +844,7 @@ class Projection { return true; case ProjectionKind::Tuple: case ProjectionKind::Index: + case ProjectionKind::Box: return false; } } @@ -285,6 +857,7 @@ class Projection { switch (getKind()) { case ProjectionKind::Tuple: case ProjectionKind::Index: + case ProjectionKind::Box: return true; case ProjectionKind::Struct: case ProjectionKind::Class: @@ -308,9 +881,9 @@ class Projection { NullablePtr createProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const { - if (Base.getType().isAddress()) { + if (Base->getType().isAddress()) { return createAddrProjection(B, Loc, Base); - } else if (Base.getType().isObject()) { + } else if (Base->getType().isObject()) { return createValueProjection(B, Loc, Base); } else { llvm_unreachable("Unsupported SILValueCategory"); @@ -336,7 +909,7 @@ class Projection { /// Given a specific SILType, return all first level address projections if /// it is an aggregate. static void getFirstLevelAddrProjections(SILType V, SILModule &Mod, - llvm::SmallVectorImpl &Out); + llvm::SmallVectorImpl &Out); /// Form an aggregate of type BaseType using the SILValue Values. Returns the /// aggregate on success if this is a case we handle or an empty SILValue @@ -358,6 +931,7 @@ class Projection { explicit Projection(TupleElementAddrInst *TEA); explicit Projection(IndexAddrInst *SEA); explicit Projection(RefElementAddrInst *REA); + explicit Projection(ProjectBoxInst *PBI); explicit Projection(UncheckedTakeEnumDataAddrInst *UTEDAI); explicit Projection(StructExtractInst *SEI); explicit Projection(TupleExtractInst *TEI); @@ -394,7 +968,7 @@ class ProjectionPath { /// We only allow for moves of ProjectionPath since we only want them to be /// able to be constructed by calling our factory method or by going through /// the append function. - ProjectionPath(ProjectionPath &&Other) : Path(Other.Path) {} + ProjectionPath(ProjectionPath &&Other) : Path(std::move(Other.Path)) {} /// Append the projection P onto this. ProjectionPath &append(const Projection &P) { @@ -411,8 +985,7 @@ class ProjectionPath { } ProjectionPath &operator=(ProjectionPath &&O) { - *this = std::move(O); - O.Path.clear(); + std::swap(Path, O.Path); return *this; } @@ -511,6 +1084,12 @@ static inline llvm::hash_code hash_value(const ProjectionPath &P) { return llvm::hash_combine_range(P.begin(), P.end()); } +/// Returns the hashcode for the new projection path. +static inline llvm::hash_code hash_value(const NewProjectionPath &P) { + return llvm::hash_combine_range(P.begin(), P.end()); +} + +/// Returns the hashcode for the projection path. static inline llvm::hash_code hash_value(const Projection &P) { if (P.isNominalKind()) { return llvm::hash_value(P.getDecl()); @@ -519,11 +1098,16 @@ static inline llvm::hash_code hash_value(const Projection &P) { } } +/// Returns the hashcode for the projection path. +static inline llvm::hash_code hash_value(const NewProjection &P) { + return llvm::hash_combine(static_cast(P.getKind())); +} + inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Projection &P) { // Print the projection type first. OS << "Address Projection Type: "; - OS << P.getType() << "\n"; + OS << P.getType().getAddressType() << "\n"; if (P.isNominalKind()) { OS << "Field Type: "; P.getDecl()->print(OS); @@ -625,11 +1209,11 @@ class ProjectionTreeNode { } bool isRoot() const { - // Root does not have a parent. So if we have a parent, we can not be root. + // Root does not have a parent. So if we have a parent, we cannot be root. if (Parent.hasValue()) { assert(Proj.hasValue() && "If parent is not none, then P should be not " "none"); - assert(Index != RootIndex && "If parent is not none, we can not be root"); + assert(Index != RootIndex && "If parent is not none, we cannot be root"); return false; } else { assert(!Proj.hasValue() && "If parent is none, then P should be none"); @@ -799,7 +1383,7 @@ class ProjectionTree { "Should only create root when ProjectionTreeNodes is empty"); auto *Node = new (Allocator) ProjectionTreeNode(BaseTy); ProjectionTreeNodes.push_back(Node); - } + } ProjectionTreeNode *createChild(ProjectionTreeNode *Parent, SILType BaseTy, diff --git a/include/swift/SIL/SILAllocated.h b/include/swift/SIL/SILAllocated.h index ca22106a371ba..6f69e7c8ef3ad 100644 --- a/include/swift/SIL/SILAllocated.h +++ b/include/swift/SIL/SILAllocated.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILArgument.h b/include/swift/SIL/SILArgument.h index 76eb832465fad..69421f52495d3 100644 --- a/include/swift/SIL/SILArgument.h +++ b/include/swift/SIL/SILArgument.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -38,9 +38,6 @@ class SILArgument : public ValueBase { SILType Ty, const ValueDecl *D = nullptr) : SILArgument(&*ParentBB, Pos, Ty, D) {} - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - SILBasicBlock *getParent() { return ParentBB; } const SILBasicBlock *getParent() const { return ParentBB; } @@ -91,6 +88,10 @@ class SILArgument : public ValueBase { bool getIncomingValues( llvm::SmallVectorImpl> &OutArray); + /// If this SILArgument's parent block has one predecessor, return the + /// incoming value from that predecessor. Returns SILValue() otherwise. + SILValue getSingleIncomingValue() const; + /// Returns true if this SILArgument is the self argument of its /// function. This means that this will return false always for SILArguments /// of SILFunctions that do not have self argument and for non-function diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h index f4a849b9ef241..7640b134b822a 100644 --- a/include/swift/SIL/SILBasicBlock.h +++ b/include/swift/SIL/SILBasicBlock.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 87840d4de964d..aebf870c64281 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1,8 +1,8 @@ -//===--- SILBuilder.h - Class for creating SIL Constructs --------*- C++ -*-==// +//===--- SILBuilder.h - Class for creating SIL Constructs -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -260,11 +260,11 @@ class SILBuilder { AllocExistentialBoxInst * createAllocExistentialBox(SILLocation Loc, SILType ExistentialType, - CanType ConcreteType, SILType ConcreteLoweredType, - ArrayRef Conformances) { + CanType ConcreteType, + ArrayRef Conformances) { return insert(AllocExistentialBoxInst::create( createSILDebugLocation(Loc), ExistentialType, ConcreteType, - ConcreteLoweredType, Conformances, &F)); + Conformances, &F)); } ApplyInst *createApply(SILLocation Loc, SILValue Fn, SILType SubstFnTy, @@ -276,7 +276,7 @@ class SILBuilder { ApplyInst *createApply(SILLocation Loc, SILValue Fn, ArrayRef Args, bool isNonThrowing) { - auto FnTy = Fn.getType(); + auto FnTy = Fn->getType(); return createApply(Loc, Fn, FnTy, FnTy.castTo()->getResult().getSILType(), ArrayRef(), Args, isNonThrowing); @@ -337,14 +337,14 @@ class SILBuilder { createBuiltinBinaryFunctionWithOverflow(SILLocation Loc, StringRef Name, ArrayRef Args) { assert(Args.size() == 3 && "Need three arguments"); - assert(Args[0].getType() == Args[1].getType() && + assert(Args[0]->getType() == Args[1]->getType() && "Binary operands must match"); - assert(Args[2].getType().is() && - Args[2].getType().getSwiftRValueType()->isBuiltinIntegerType(1) && + assert(Args[2]->getType().is() && + Args[2]->getType().getSwiftRValueType()->isBuiltinIntegerType(1) && "Must have a third Int1 operand"); - SILType OpdTy = Args[0].getType(); - SILType Int1Ty = Args[2].getType(); + SILType OpdTy = Args[0]->getType(); + SILType Int1Ty = Args[2]->getType(); TupleTypeElt ResultElts[] = {OpdTy.getSwiftRValueType(), Int1Ty.getSwiftRValueType()}; @@ -359,6 +359,10 @@ class SILBuilder { return insert(new (F.getModule()) FunctionRefInst(createSILDebugLocation(Loc), f)); } + AllocGlobalInst *createAllocGlobal(SILLocation Loc, SILGlobalVariable *g) { + return insert(new (F.getModule()) + AllocGlobalInst(createSILDebugLocation(Loc), g)); + } GlobalAddrInst *createGlobalAddr(SILLocation Loc, SILGlobalVariable *g) { return insert(new (F.getModule()) GlobalAddrInst(createSILDebugLocation(Loc), g)); @@ -475,7 +479,7 @@ class SILBuilder { CopyAddrInst *createCopyAddr(SILLocation Loc, SILValue srcAddr, SILValue destAddr, IsTake_t isTake, IsInitialization_t isInitialize) { - assert(srcAddr.getType() == destAddr.getType()); + assert(srcAddr->getType() == destAddr->getType()); return insert(new (F.getModule()) CopyAddrInst( createSILDebugLocation(Loc), srcAddr, destAddr, isTake, isInitialize)); } @@ -731,7 +735,7 @@ class SILBuilder { SILValue Operand, EnumElementDecl *Element) { SILType EltType = - Operand.getType().getEnumElementType(Element, getModule()); + Operand->getType().getEnumElementType(Element, getModule()); return createUncheckedEnumData(Loc, Operand, Element, EltType); } @@ -746,7 +750,7 @@ class SILBuilder { createUncheckedTakeEnumDataAddr(SILLocation Loc, SILValue Operand, EnumElementDecl *Element) { SILType EltType = - Operand.getType().getEnumElementType(Element, getModule()); + Operand->getType().getEnumElementType(Element, getModule()); return createUncheckedTakeEnumDataAddr(Loc, Operand, Element, EltType); } @@ -786,7 +790,7 @@ class SILBuilder { TupleExtractInst *createTupleExtract(SILLocation Loc, SILValue Operand, unsigned FieldNo) { - auto type = Operand.getType().getTupleElementType(FieldNo); + auto type = Operand->getType().getTupleElementType(FieldNo); return createTupleExtract(Loc, Operand, FieldNo, type); } @@ -802,7 +806,7 @@ class SILBuilder { createTupleElementAddr(SILLocation Loc, SILValue Operand, unsigned FieldNo) { return insert(new (F.getModule()) TupleElementAddrInst( createSILDebugLocation(Loc), Operand, FieldNo, - Operand.getType().getTupleElementType(FieldNo))); + Operand->getType().getTupleElementType(FieldNo))); } StructExtractInst *createStructExtract(SILLocation Loc, SILValue Operand, @@ -813,7 +817,7 @@ class SILBuilder { StructExtractInst *createStructExtract(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto type = Operand.getType().getFieldType(Field, F.getModule()); + auto type = Operand->getType().getFieldType(Field, F.getModule()); return createStructExtract(Loc, Operand, Field, type); } @@ -827,7 +831,7 @@ class SILBuilder { StructElementAddrInst * createStructElementAddr(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto ResultTy = Operand.getType().getFieldType(Field, F.getModule()); + auto ResultTy = Operand->getType().getFieldType(Field, F.getModule()); return createStructElementAddr(Loc, Operand, Field, ResultTy); } @@ -838,7 +842,7 @@ class SILBuilder { } RefElementAddrInst *createRefElementAddr(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto ResultTy = Operand.getType().getFieldType(Field, F.getModule()); + auto ResultTy = Operand->getType().getFieldType(Field, F.getModule()); return createRefElementAddr(Loc, Operand, Field, ResultTy); } @@ -873,7 +877,7 @@ class SILBuilder { } WitnessMethodInst *createWitnessMethod(SILLocation Loc, CanType LookupTy, - ProtocolConformance *Conformance, + ProtocolConformanceRef Conformance, SILDeclRef Member, SILType MethodTy, SILValue OptionalOpenedExistential, bool Volatile = false) { @@ -918,7 +922,7 @@ class SILBuilder { createInitExistentialAddr(SILLocation Loc, SILValue Existential, CanType FormalConcreteType, SILType LoweredConcreteType, - ArrayRef Conformances) { + ArrayRef Conformances) { return insert(InitExistentialAddrInst::create( createSILDebugLocation(Loc), Existential, FormalConcreteType, LoweredConcreteType, Conformances, &F)); @@ -927,7 +931,7 @@ class SILBuilder { InitExistentialMetatypeInst * createInitExistentialMetatype(SILLocation Loc, SILValue metatype, SILType existentialType, - ArrayRef conformances) { + ArrayRef conformances) { return insert(InitExistentialMetatypeInst::create( createSILDebugLocation(Loc), existentialType, metatype, conformances, &F)); @@ -936,7 +940,7 @@ class SILBuilder { InitExistentialRefInst * createInitExistentialRef(SILLocation Loc, SILType ExistentialType, CanType FormalConcreteType, SILValue Concrete, - ArrayRef Conformances) { + ArrayRef Conformances) { return insert(InitExistentialRefInst::create( createSILDebugLocation(Loc), ExistentialType, FormalConcreteType, Concrete, Conformances, &F)); @@ -950,7 +954,7 @@ class SILBuilder { ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc, SILValue Storage) { - auto CaptureTy = Storage.getType() + auto CaptureTy = Storage->getType() .castTo() ->getCaptureAddressType(); return createProjectBlockStorage(Loc, Storage, CaptureTy); @@ -1037,7 +1041,7 @@ class SILBuilder { FixLifetimeInst(createSILDebugLocation(Loc), Operand)); } void emitFixLifetime(SILLocation Loc, SILValue Operand) { - if (getTypeLowering(Operand.getType()).isTrivial()) + if (getTypeLowering(Operand->getType()).isTrivial()) return; createFixLifetime(Loc, Operand); } @@ -1080,7 +1084,7 @@ class SILBuilder { } DeallocBoxInst *createDeallocBox(SILLocation Loc, SILValue operand) { auto eltType = - operand.getType().castTo()->getBoxedAddressType(); + operand->getType().castTo()->getBoxedAddressType(); return insert(new (F.getModule()) DeallocBoxInst( createSILDebugLocation(Loc), eltType, operand)); } @@ -1109,7 +1113,7 @@ class SILBuilder { } ProjectBoxInst *createProjectBox(SILLocation Loc, SILValue boxOperand) { auto valueTy = - boxOperand.getType().castTo()->getBoxedAddressType(); + boxOperand->getType().castTo()->getBoxedAddressType(); return insert(new (F.getModule()) ProjectBoxInst( createSILDebugLocation(Loc), valueTy, boxOperand)); @@ -1119,6 +1123,12 @@ class SILBuilder { return insert(new (F.getModule()) ProjectBoxInst( createSILDebugLocation(Loc), valueTy, boxOperand)); } + ProjectExistentialBoxInst *createProjectExistentialBox(SILLocation Loc, + SILType valueTy, + SILValue boxOperand) { + return insert(new (F.getModule()) ProjectExistentialBoxInst( + createSILDebugLocation(Loc), valueTy, boxOperand)); + } //===--------------------------------------------------------------------===// // Unchecked cast helpers @@ -1360,16 +1370,16 @@ class SILBuilder { /// Convenience function for calling emitRetain on the type lowering /// for the non-address value. void emitRetainValueOperation(SILLocation Loc, SILValue v) { - assert(!v.getType().isAddress()); - auto &lowering = getTypeLowering(v.getType()); + assert(!v->getType().isAddress()); + auto &lowering = getTypeLowering(v->getType()); return lowering.emitRetainValue(*this, Loc, v); } /// Convenience function for calling TypeLowering.emitRelease on the type /// lowering for the non-address value. void emitReleaseValueOperation(SILLocation Loc, SILValue v) { - assert(!v.getType().isAddress()); - auto &lowering = getTypeLowering(v.getType()); + assert(!v->getType().isAddress()); + auto &lowering = getTypeLowering(v->getType()); lowering.emitReleaseValue(*this, Loc, v); } @@ -1385,7 +1395,7 @@ class SILBuilder { SILValue emitTupleExtract(SILLocation Loc, SILValue Operand, unsigned FieldNo) { return emitTupleExtract(Loc, Operand, FieldNo, - Operand.getType().getTupleElementType(FieldNo)); + Operand->getType().getTupleElementType(FieldNo)); } SILValue emitStructExtract(SILLocation Loc, SILValue Operand, VarDecl *Field, @@ -1398,7 +1408,7 @@ class SILBuilder { SILValue emitStructExtract(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto type = Operand.getType().getFieldType(Field, F.getModule()); + auto type = Operand->getType().getFieldType(Field, F.getModule()); return emitStructExtract(Loc, Operand, Field, type); } diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 57331c03fd189..7c7d50b58bd15 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1,8 +1,8 @@ -//===--- SILCloner.h - Defines the SILCloner class ---------------*- C++ -*-==// +//===--- SILCloner.h - Defines the SILCloner class --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -29,7 +29,7 @@ namespace swift { /// operations requiring cloning (while possibly modifying, at the same time) /// instruction sequences. /// -/// By default, this visitor will not do anything useful when when called on a +/// By default, this visitor will not do anything useful when called on a /// basic block, or function; subclasses that want to handle those should /// implement the appropriate visit functions and/or provide other entry points. template @@ -75,8 +75,7 @@ class SILCloner : protected SILVisitor { const SILDebugScope *remapScope(const SILDebugScope *DS) { return DS; } SILType remapType(SILType Ty) { return Ty; } CanType remapASTType(CanType Ty) { return Ty; } - ProtocolConformance *remapConformance(ArchetypeType *archetype, - CanType Ty, ProtocolConformance *C) { + ProtocolConformanceRef remapConformance(CanType Ty, ProtocolConformanceRef C){ return C; } SILValue remapValue(SILValue Value); @@ -97,9 +96,7 @@ class SILCloner : protected SILVisitor { CanType newReplacement = asImpl().getOpASTType(sub.getReplacement()->getCanonicalType()); - return Substitution(sub.getArchetype(), - newReplacement, - sub.getConformances()); + return Substitution(newReplacement, sub.getConformances()); } ArrayRef getOpSubstitutions(ArrayRef Subs) { MutableArrayRef newSubsBuf; @@ -107,13 +104,13 @@ class SILCloner : protected SILVisitor { auto copySubs = [&]{ if (!newSubsBuf.empty()) return; - newSubsBuf = Subs[0].getArchetype()->getASTContext() - .Allocate(Subs.size()); + newSubsBuf = getBuilder().getASTContext() + .template Allocate(Subs.size()); memcpy(newSubsBuf.data(), Subs.data(), sizeof(Substitution) * Subs.size()); Subs = newSubsBuf; }; - + for (unsigned i = 0, e = Subs.size(); i < e; ++i) { Substitution newSub = asImpl().getOpSubstitution(Subs[i]); if (newSub != Subs[i]) { @@ -160,12 +157,12 @@ class SILCloner : protected SILVisitor { /// /// Returns the passed-in conformances array if none of the elements /// changed. - ArrayRef getOpConformances(ArchetypeType *archetype, - CanType type, - ArrayRef oldConformances) { - Substitution sub(archetype, type, oldConformances); + ArrayRef getOpConformances(CanType type, + ArrayRef oldConformances) { + Substitution sub(type, oldConformances); Substitution mappedSub = asImpl().remapSubstitution(sub); - ArrayRef newConformances = mappedSub.getConformances(); + ArrayRef newConformances = + mappedSub.getConformances(); // Use the existing conformances array if possible. if (oldConformances == newConformances) @@ -174,34 +171,9 @@ class SILCloner : protected SILVisitor { return type->getASTContext().AllocateCopy(newConformances); } - // Find an archetype with the right shape for an existential. - static ArchetypeType *getArchetypeForExistential(CanType existential) { - assert(existential.isAnyExistentialType()); - - // Look through existential metatypes. - while (auto metatype = dyn_cast(existential)) - existential = metatype.getInstanceType(); - - // For simple protocol types, use Self. - if (auto protocol = dyn_cast(existential)) - return protocol->getDecl()->getProtocolSelf()->getArchetype(); - - // Otherwise, open a new archetype with the right conformances. - assert(isa(existential)); - return ArchetypeType::getOpened(existential); - } - - ArrayRef - getOpConformancesForExistential(CanType existential, CanType concreteType, - ArrayRef oldConformances) { - if (oldConformances.empty()) return oldConformances; - return asImpl().getOpConformances(getArchetypeForExistential(existential), - concreteType, oldConformances); - } - - ProtocolConformance *getOpConformance(ArchetypeType *archetype, CanType ty, - ProtocolConformance *conformance) { - return asImpl().remapConformance(archetype, ty, conformance); + ProtocolConformanceRef getOpConformance(CanType ty, + ProtocolConformanceRef conformance) { + return asImpl().remapConformance(ty, conformance); } SILValue getOpValue(SILValue Value) { @@ -320,7 +292,7 @@ SILCloner::remapValue(SILValue Value) { if (SILInstruction* I = dyn_cast(Value)) { auto II = InstructionMap.find(I); if (II != InstructionMap.end()) - return SILValue(II->second, Value.getResultNumber()); + return SILValue(II->second); llvm_unreachable("Unmapped instruction while cloning?"); } @@ -329,7 +301,7 @@ SILCloner::remapValue(SILValue Value) { auto type = getOpType(U->getType()); ValueBase *undef = (type == U->getType() ? U : SILUndef::get(type, Builder.getModule())); - return SILValue(undef, Value.getResultNumber()); + return SILValue(undef); } llvm_unreachable("Unmapped value while cloning?"); @@ -478,16 +450,13 @@ SILCloner::visitAllocExistentialBoxInst( auto origExistentialType = Inst->getExistentialType(); auto origFormalType = Inst->getFormalConcreteType(); - auto conformances = - getOpConformancesForExistential(origExistentialType.getSwiftRValueType(), - origFormalType, Inst->getConformances()); + auto conformances =getOpConformances(origFormalType, Inst->getConformances()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createAllocExistentialBox(getOpLocation(Inst->getLoc()), getOpType(origExistentialType), getOpASTType(origFormalType), - getOpType(Inst->getLoweredConcreteType()), conformances)); } @@ -568,13 +537,22 @@ SILCloner::visitFunctionRefInst(FunctionRefInst *Inst) { OpFunction)); } +template +void +SILCloner::visitAllocGlobalInst(AllocGlobalInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + doPostProcess(Inst, + getBuilder().createAllocGlobal(getOpLocation(Inst->getLoc()), + Inst->getReferencedGlobal())); +} + template void SILCloner::visitGlobalAddrInst(GlobalAddrInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createGlobalAddr(getOpLocation(Inst->getLoc()), - Inst->getReferencedGlobal())); + Inst->getReferencedGlobal())); } template @@ -1242,10 +1220,8 @@ SILCloner::visitSuperMethodInst(SuperMethodInst *Inst) { template void SILCloner::visitWitnessMethodInst(WitnessMethodInst *Inst) { - auto memberDC = Inst->getMember().getDecl()->getDeclContext(); auto conformance = - getOpConformance(memberDC->getProtocolSelf()->getArchetype(), - Inst->getLookupType(), Inst->getConformance()); + getOpConformance(Inst->getLookupType(), Inst->getConformance()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess( Inst, @@ -1294,7 +1270,7 @@ SILCloner:: visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *Inst) { // Create a new archetype for this opened existential type. CanType openedType = Inst->getType().getSwiftRValueType(); - CanType exType = Inst->getOperand().getType().getSwiftRValueType(); + CanType exType = Inst->getOperand()->getType().getSwiftRValueType(); while (auto exMetatype = dyn_cast(exType)) { exType = exMetatype.getInstanceType(); openedType = cast(openedType).getInstanceType(); @@ -1303,7 +1279,7 @@ visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *Inst) { OpenedExistentialSubs[archetypeTy] = ArchetypeType::getOpened(archetypeTy->getOpenedExistentialType()); - if (!Inst->getOperand().getType().canUseExistentialRepresentation( + if (!Inst->getOperand()->getType().canUseExistentialRepresentation( Inst->getModule(), ExistentialRepresentation::Class)) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createOpenExistentialMetatype( @@ -1358,10 +1334,7 @@ template void SILCloner::visitInitExistentialAddrInst(InitExistentialAddrInst *Inst) { CanType origFormalType = Inst->getFormalConcreteType(); - auto conformances = - getOpConformancesForExistential( - Inst->getOperand().getType().getSwiftRValueType(), - origFormalType, Inst->getConformances()); + auto conformances =getOpConformances(origFormalType, Inst->getConformances()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createInitExistentialAddr(getOpLocation(Inst->getLoc()), @@ -1375,10 +1348,8 @@ template void SILCloner:: visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *Inst) { - auto conformances = - getOpConformancesForExistential(Inst->getType().getSwiftRValueType(), - Inst->getFormalErasedObjectType(), - Inst->getConformances()); + auto conformances = getOpConformances(Inst->getFormalErasedObjectType(), + Inst->getConformances()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createInitExistentialMetatype(getOpLocation(Inst->getLoc()), @@ -1392,9 +1363,7 @@ void SILCloner:: visitInitExistentialRefInst(InitExistentialRefInst *Inst) { CanType origFormalType = Inst->getFormalConcreteType(); - auto conformances = - getOpConformancesForExistential(Inst->getType().getSwiftRValueType(), - origFormalType, Inst->getConformances()); + auto conformances =getOpConformances(origFormalType, Inst->getConformances()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); doPostProcess(Inst, getBuilder().createInitExistentialRef(getOpLocation(Inst->getLoc()), @@ -1609,6 +1578,16 @@ void SILCloner::visitProjectBoxInst(ProjectBoxInst *Inst) { getOpValue(Inst->getOperand()))); } +template +void SILCloner::visitProjectExistentialBoxInst( + ProjectExistentialBoxInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + doPostProcess(Inst, + getBuilder().createProjectExistentialBox(getOpLocation(Inst->getLoc()), + getOpType(Inst->getValueType()), + getOpValue(Inst->getOperand()))); +} + template void SILCloner::visitCondFailInst(CondFailInst *Inst) { diff --git a/include/swift/SIL/SILCoverageMap.h b/include/swift/SIL/SILCoverageMap.h index d635d83e7bb13..44dec8a870976 100644 --- a/include/swift/SIL/SILCoverageMap.h +++ b/include/swift/SIL/SILCoverageMap.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILDebugScope.h b/include/swift/SIL/SILDebugScope.h index ad7635d96f17d..24f9299d4d9f0 100644 --- a/include/swift/SIL/SILDebugScope.h +++ b/include/swift/SIL/SILDebugScope.h @@ -1,8 +1,8 @@ -//===--- SILDebugScope.h - DebugScopes for SIL code -----------*- C++ -*-===// +//===--- SILDebugScope.h - DebugScopes for SIL code -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILDebuggerClient.h b/include/swift/SIL/SILDebuggerClient.h index d7ac89158d2d7..e691be768cc82 100644 --- a/include/swift/SIL/SILDebuggerClient.h +++ b/include/swift/SIL/SILDebuggerClient.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 3bcf51cf1ab80..5f352d3342406 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -1,8 +1,8 @@ -//===--- SILDeclRef.h - Defines the SILDeclRef struct ---------*- C++ -*---===// +//===--- SILDeclRef.h - Defines the SILDeclRef struct -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -234,8 +234,7 @@ struct SILDeclRef { /// /// If 'prefix' is non-empty, it will be used in place of the standard '_T' /// prefix. - llvm::StringRef mangle(llvm::SmallVectorImpl &buffer, - StringRef prefix = {}) const; + std::string mangle(StringRef prefix = {}) const; /// True if the SILDeclRef references a function. bool isFunc() const { @@ -270,7 +269,7 @@ struct SILDeclRef { /// \brief True if the function has __always inline attribute. bool isAlwaysInline() const; - /// \return True if the function has a effects attribute. + /// \return True if the function has an effects attribute. bool hasEffectsAttribute() const; /// \return the effects kind of the function. diff --git a/include/swift/SIL/SILExternalSource.h b/include/swift/SIL/SILExternalSource.h deleted file mode 100644 index f8780e4c6a1ce..0000000000000 --- a/include/swift/SIL/SILExternalSource.h +++ /dev/null @@ -1,42 +0,0 @@ -//===--- SILExternalSource.h - On-demand generation of SIL ------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file defines the abstract SILExternalSource class. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_SILEXTERNALSOURCE_H -#define SWIFT_SILEXTERNALSOURCE_H - -namespace swift { - -class SILFunction; - -class SILExternalSource { -public: - SILExternalSource() { } - virtual ~SILExternalSource() = default; - - /// SILExternalSource gets called for each external function - /// that the SIL linker would try to load SIL for. In particular - /// this means transparent functions. - /// - /// \param callee is the (usually empty) called function. - virtual SILFunction *lookupSILFunction(SILFunction *callee) = 0; - -private: - virtual void anchor(); -}; - -} // namespace swift - -#endif diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 5c43651b46818..f84baa6ed6fdb 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -102,7 +102,7 @@ class SILFunction /// functions in the stdlib. unsigned Fragile : 1; - /// Specifies if this function is a thunk or an reabstraction thunk. + /// Specifies if this function is a thunk or a reabstraction thunk. /// /// The inliner uses this information to avoid inlining (non-trivial) /// functions into the thunk. @@ -133,12 +133,15 @@ class SILFunction /// It does not include references from debug scopes. unsigned RefCount = 0; - /// The function's semantics attribute. - std::string SemanticsAttr; + /// The function's set of semantics attributes. + /// + /// TODO: Why is this using a std::string? Why don't we use uniqued + /// StringRefs? + llvm::SmallVector SemanticsAttrSet; /// The function's effects attribute. - EffectsKind EK; - + EffectsKind EffectsKindAttr; + /// True if this function is inlined at least once. This means that the /// debug info keeps a pointer to this function. bool Inlined = false; @@ -175,7 +178,8 @@ class SILFunction IsThunk_t isThunk = IsNotThunk, ClassVisibility_t classVisibility = NotRelevant, Inline_t inlineStrategy = InlineDefault, - EffectsKind EK = EffectsKind::Unspecified, + EffectsKind EffectsKindAttr = + EffectsKind::Unspecified, SILFunction *InsertBefore = nullptr, const SILDebugScope *DebugScope = nullptr, DeclContext *DC = nullptr); @@ -344,20 +348,39 @@ class SILFunction /// \returns True if the function is marked with the @_semantics attribute /// and has special semantics that the optimizer can use to optimize the /// function. - bool hasDefinedSemantics() const { - return SemanticsAttr.length() > 0; + bool hasSemanticsAttrs() const { return SemanticsAttrSet.size() > 0; } + + /// \returns True if the function has a semantic attribute that starts with a + /// specific string. + /// + /// TODO: This needs a better name. + bool hasSemanticsAttrThatStartsWith(StringRef S) { + return count_if(getSemanticsAttrs(), [&S](const std::string &Attr) -> bool { + return StringRef(Attr).startswith(S); + }); } /// \returns the semantics tag that describes this function. - StringRef getSemanticsString() const { - assert(hasDefinedSemantics() && - "Accessing a function with no semantics tag"); - return SemanticsAttr; - } + ArrayRef getSemanticsAttrs() const { return SemanticsAttrSet; } /// \returns True if the function has the semantics flag \p Value; - bool hasSemanticsString(StringRef Value) const { - return SemanticsAttr == Value; + bool hasSemanticsAttr(StringRef Value) const { + return std::count(SemanticsAttrSet.begin(), SemanticsAttrSet.end(), Value); + } + + /// Add the given semantics attribute to the attr list set. + void addSemanticsAttr(StringRef Ref) { + if (hasSemanticsAttr(Ref)) + return; + SemanticsAttrSet.push_back(Ref); + std::sort(SemanticsAttrSet.begin(), SemanticsAttrSet.end()); + } + + /// Remove the semantics + void removeSemanticsAttr(StringRef Ref) { + auto Iter = + std::remove(SemanticsAttrSet.begin(), SemanticsAttrSet.end(), Ref); + SemanticsAttrSet.erase(Iter); } /// \returns True if the function is optimizable (i.e. not marked as no-opt), @@ -412,13 +435,17 @@ class SILFunction void setInlineStrategy(Inline_t inStr) { InlineStrategy = inStr; } /// \return the function side effects information. - EffectsKind getEffectsKind() const { return EK; } + EffectsKind getEffectsKind() const { return EffectsKindAttr; } /// \return True if the function is annotated with the @effects attribute. - bool hasEffectsKind() const { return EK != EffectsKind::Unspecified; } + bool hasEffectsKind() const { + return EffectsKindAttr != EffectsKind::Unspecified; + } /// \brief Set the function side effect information. - void setEffectsKind(EffectsKind E) { EK = E; } + void setEffectsKind(EffectsKind E) { + EffectsKindAttr = E; + } /// Get this function's global_init attribute. /// @@ -435,9 +462,6 @@ class SILFunction bool isGlobalInit() const { return GlobalInitFlag; } void setGlobalInit(bool isGI) { GlobalInitFlag = isGI; } - StringRef getSemanticsAttr() const { return SemanticsAttr; } - void setSemanticsAttr(StringRef attr) { SemanticsAttr = attr; } - bool isKeepAsPublic() const { return KeepAsPublic; } void setKeepAsPublic(bool keep) { KeepAsPublic = keep; } @@ -546,17 +570,17 @@ class SILFunction //===--------------------------------------------------------------------===// SILArgument *getArgument(unsigned i) { - assert(!empty() && "Can not get argument of a function without a body"); + assert(!empty() && "Cannot get argument of a function without a body"); return begin()->getBBArg(i); } const SILArgument *getArgument(unsigned i) const { - assert(!empty() && "Can not get argument of a function without a body"); + assert(!empty() && "Cannot get argument of a function without a body"); return begin()->getBBArg(i); } ArrayRef getArguments() const { - assert(!empty() && "Can not get arguments of a function without a body"); + assert(!empty() && "Cannot get arguments of a function without a body"); return begin()->getBBArgs(); } diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index 4a0f7f42d24e3..044b06937b6a7 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index b4043ea119cc3..f6fe5eb512294 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,6 +22,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "swift/AST/Builtins.h" +#include "swift/AST/ProtocolConformanceRef.h" #include "swift/SIL/Consumption.h" #include "swift/SIL/SILAllocated.h" #include "swift/SIL/SILLocation.h" @@ -81,11 +82,9 @@ class SILInstruction : public ValueBase,public llvm::ilist_node{ void setDebugScope(SILBuilder &B, const SILDebugScope *DS); protected: - SILInstruction(ValueKind Kind, SILDebugLocation *DebugLoc, SILType Ty) - : ValueBase(Kind, Ty), ParentBB(0), Location(*DebugLoc) {} SILInstruction(ValueKind Kind, SILDebugLocation *DebugLoc, - SILTypeList *TypeList = nullptr) - : ValueBase(Kind, TypeList), ParentBB(0), Location(*DebugLoc) {} + SILType Ty = SILType()) + : ValueBase(Kind, Ty), ParentBB(0), Location(*DebugLoc) {} public: /// Instructions should be allocated using a dedicated instruction allocation @@ -199,20 +198,13 @@ class SILInstruction : public ValueBase,public llvm::ilist_node{ template bool isIdenticalTo(const SILInstruction *RHS, OpCmp opEqual) const { // Quick check if both instructions have the same kind, number of operands, - // and number of types. This should filter out most cases. + // and types. This should filter out most cases. if (getKind() != RHS->getKind() || getNumOperands() != RHS->getNumOperands() || - getNumTypes() != RHS->getNumTypes()) { + getType() != RHS->getType()) { return false; } - // Check types. - // - // Many instructions have only 1 type so it makes sense to check it first. - for (unsigned i = 0, e = getNumTypes(); i != e; ++i) - if (getType(i) != RHS->getType(i)) - return false; - // Check operands. for (unsigned i = 0, e = getNumOperands(); i != e; ++i) if (!opEqual(getOperand(i), RHS->getOperand(i))) @@ -282,6 +274,21 @@ class SILInstruction : public ValueBase,public llvm::ilist_node{ bool isTriviallyDuplicatable() const; }; +/// Returns the combined behavior of \p B1 and \p B2. +inline SILInstruction::MemoryBehavior +combineMemoryBehavior(SILInstruction::MemoryBehavior B1, + SILInstruction::MemoryBehavior B2) { + // Basically the combined behavior is the maximum of both operands. + auto Result = std::max(B1, B2); + + // With one exception: MayRead, MayWrite -> MayReadWrite. + if (Result == SILInstruction::MemoryBehavior::MayWrite && + (B1 == SILInstruction::MemoryBehavior::MayRead || + B2 == SILInstruction::MemoryBehavior::MayRead)) + return SILInstruction::MemoryBehavior::MayReadWrite; + return Result; +} + #ifndef NDEBUG /// Pretty-print the MemoryBehavior. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, @@ -327,9 +334,9 @@ class UnaryInstructionBase : public BASE { /// getType() is ok if this is known to only have one type. template typename std::enable_if::value, SILType>::type - getType(unsigned i = 0) const { return ValueBase::getType(i); } + getType() const { return ValueBase::getType(); } - ArrayRef getAllOperands() const { return Operands.asArray(); }\ + ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { @@ -392,9 +399,6 @@ class AllocationInst : public SILInstruction { protected: AllocationInst(ValueKind Kind, SILDebugLocation *DebugLoc, SILType Ty) : SILInstruction(Kind, DebugLoc, Ty) {} - AllocationInst(ValueKind Kind, SILDebugLocation *DebugLoc, - SILTypeList *TypeList = nullptr) - : SILInstruction(Kind, DebugLoc, TypeList) {} public: @@ -446,14 +450,11 @@ class AllocStackInst : public AllocationInst { void setArgNo(unsigned N) { VarInfo.setArgNo(N); } /// getElementType - Get the type of the allocated memory (as opposed to the - /// (second) type of the instruction itself, which will be an address type). + /// type of the instruction itself, which will be an address type). SILType getElementType() const { - return getType(1).getObjectType(); + return getType().getObjectType(); } - SILValue getContainerResult() const { return SILValue(this, 0); } - SILValue getAddressResult() const { return SILValue(this, 1); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -474,8 +475,6 @@ class AllocRefInst : public AllocationInst, public StackPromotable { public: - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -541,12 +540,10 @@ class AllocBoxInst : public AllocationInst { public: SILType getElementType() const { - return getType(1).getObjectType(); + return SILType::getPrimitiveObjectType(getType().castTo()-> + getBoxedType()); } - SILValue getContainerResult() const { return SILValue(this, 0); } - SILValue getAddressResult() const { return SILValue(this, 1); } - /// Return the underlying variable declaration associated with this /// allocation, or null if this is a temporary allocation. VarDecl *getDecl() const; @@ -571,19 +568,18 @@ class AllocBoxInst : public AllocationInst { /// value is uninitialized. class AllocExistentialBoxInst : public AllocationInst { friend class SILBuilder; - CanType ConcreteType; - ArrayRef Conformances; + ArrayRef Conformances; AllocExistentialBoxInst(SILDebugLocation *DebugLoc, SILType ExistentialType, - CanType ConcreteType, SILType ConcreteLoweredType, - ArrayRef Conformances, + CanType ConcreteType, + ArrayRef Conformances, SILFunction *Parent); static AllocExistentialBoxInst * create(SILDebugLocation *DebugLoc, SILType ExistentialType, - CanType ConcreteType, SILType ConcreteLoweredType, - ArrayRef Conformances, SILFunction *Parent); + CanType ConcreteType, + ArrayRef Conformances, SILFunction *Parent); public: CanType getFormalConcreteType() const { @@ -591,20 +587,13 @@ class AllocExistentialBoxInst : public AllocationInst { } SILType getExistentialType() const { - return getType(0); - } - - SILType getLoweredConcreteType() const { - return getType(1); + return getType(); } - ArrayRef getConformances() const { + ArrayRef getConformances() const { return Conformances; } - SILValue getExistentialResult() const { return SILValue(this, 0); } - SILValue getValueAddressResult() const { return SILValue(this, 1); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -681,24 +670,24 @@ class ApplyInstBase : public Base { bool isNonThrowingApply() const { return NonThrowing; } public: - // The operand number of the first argument. + /// The operand number of the first argument. static unsigned getArgumentOperandNumber() { return 1; } SILValue getCallee() const { return Operands[Callee].get(); } - // Gets the referenced function if the callee is a function_ref instruction. + /// Gets the referenced function if the callee is a function_ref instruction. SILFunction *getCalleeFunction() const { if (auto *FRI = dyn_cast(getCallee())) return FRI->getReferencedFunction(); return nullptr; } - // Get the type of the callee without the applied substitutions. + /// Get the type of the callee without the applied substitutions. CanSILFunctionType getOrigCalleeType() const { - return getCallee().getType().template castTo(); + return getCallee()->getType().template castTo(); } - // Get the type of the callee with the applied substitutions. + /// Get the type of the callee with the applied substitutions. CanSILFunctionType getSubstCalleeType() const { return SubstCalleeType.castTo(); } @@ -764,7 +753,7 @@ class ApplyInstBase : public Base { /// Return the ith argument passed to this instruction. SILValue getArgument(unsigned i) const { return getArguments()[i]; } - // Set the ith argument of this instruction. + /// Set the ith argument of this instruction. void setArgument(unsigned i, SILValue V) { return getArgumentOperands()[i].set(V); } @@ -778,9 +767,9 @@ class ApplyInstBase : public Base { /// does it have the given semantics? bool doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics); -// The partial specialization of ApplyInstBase for full applications. -// Adds some methods relating to 'self' and to result types that don't -// make sense for partial applications. +/// The partial specialization of ApplyInstBase for full applications. +/// Adds some methods relating to 'self' and to result types that don't +/// make sense for partial applications. template class ApplyInstBase : public ApplyInstBase { @@ -807,7 +796,7 @@ class ApplyInstBase /// The hope is that this will prevent any future bugs from coming up related /// to this. /// - /// Self is always the last parameter, but self subtitutions are always + /// Self is always the last parameter, but self substitutions are always /// first. The reason to add this method is to wrap that dichotomy to reduce /// errors. /// @@ -906,9 +895,6 @@ class ApplyInst : public ApplyInstBase { SILFunction &F); public: - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::ApplyInst; } @@ -938,10 +924,6 @@ class PartialApplyInst SILFunction &F); public: - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - - /// Return the ast level function type of this partial apply. CanSILFunctionType getFunctionType() const { return getType().castTo(); @@ -978,7 +960,7 @@ class FunctionRefInst : public LiteralInst { /// Construct a FunctionRefInst. /// /// \param DebugLoc The location of the reference. - /// \param F The function being referenced. + /// \param F The function being referenced. FunctionRefInst(SILDebugLocation *DebugLoc, SILFunction *F); public: @@ -989,10 +971,6 @@ class FunctionRefInst : public LiteralInst { void dropReferencedFunction(); - /// getType() is ok since this is known to only have one type. - /// The type is always a lowered function type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - CanSILFunctionType getFunctionType() const { return getType().castTo(); } @@ -1040,10 +1018,6 @@ class BuiltinInst : public SILInstruction { Identifier getName() const { return Name; } void setName(Identifier I) { Name = I; } - /// Currently all builtins have one result, so getType() is OK. - /// We may want to change that eventually. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - /// \brief Looks up the llvm intrinsic ID and type for the builtin function. /// /// \returns Returns llvm::Intrinsic::not_intrinsic if the function is not an @@ -1105,28 +1079,55 @@ class BuiltinInst : public SILInstruction { } }; -/// Gives the address of a SIL global variable. -class GlobalAddrInst : public LiteralInst { +/// Initializes a SIL global variable. Only valid once, before any +/// usages of the global via GlobalAddrInst. +class AllocGlobalInst : public SILInstruction { friend class SILBuilder; SILGlobalVariable *Global; - GlobalAddrInst(SILDebugLocation *DebugLoc, SILGlobalVariable *Global); + AllocGlobalInst(SILDebugLocation *DebugLoc, SILGlobalVariable *Global); public: // FIXME: This constructor should be private but is currently used // in the SILParser. /// Create a placeholder instruction with an unset global reference. - GlobalAddrInst(SILDebugLocation *DebugLoc, SILType Ty); + AllocGlobalInst(SILDebugLocation *DebugLoc); /// Return the referenced global variable. SILGlobalVariable *getReferencedGlobal() const { return Global; } void setReferencedGlobal(SILGlobalVariable *v) { Global = v; } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } + ArrayRef getAllOperands() const { return {}; } + MutableArrayRef getAllOperands() { return {}; } + + static bool classof(const ValueBase *V) { + return V->getKind() == ValueKind::AllocGlobalInst; + } +}; + +/// Gives the address of a SIL global variable. Only valid after an +/// AllocGlobalInst. +class GlobalAddrInst : public LiteralInst { + friend class SILBuilder; + + SILGlobalVariable *Global; + + GlobalAddrInst(SILDebugLocation *DebugLoc, SILGlobalVariable *Global); + +public: + // FIXME: This constructor should be private but is currently used + // in the SILParser. + + /// Create a placeholder instruction with an unset global reference. + GlobalAddrInst(SILDebugLocation *DebugLoc, SILType Ty); + + /// Return the referenced global variable. + SILGlobalVariable *getReferencedGlobal() const { return Global; } + + void setReferencedGlobal(SILGlobalVariable *v) { Global = v; } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -1156,9 +1157,6 @@ class IntegerLiteralInst : public LiteralInst { /// getValue - Return the APInt for the underlying integer literal. APInt getValue() const; - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -1188,9 +1186,6 @@ class FloatLiteralInst : public LiteralInst { /// \brief Return the bitcast representation of the FP literal as an APInt. APInt getBits() const; - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -1208,7 +1203,9 @@ class StringLiteralInst : public LiteralInst { public: enum class Encoding { UTF8, - UTF16 + UTF16, + /// UTF-8 encoding of an Objective-C selector. + ObjCSelector, }; private: @@ -1261,7 +1258,7 @@ class LoadInst /// use for the load. LoadInst(SILDebugLocation *DebugLoc, SILValue LValue) : UnaryInstructionBase(DebugLoc, LValue, - LValue.getType().getObjectType()) {} + LValue->getType().getObjectType()) {} }; /// StoreInst - Represents a store from a memory location. @@ -1314,7 +1311,7 @@ class AssignInst : public SILInstruction { SILValue getDest() const { return Operands[Dest].get(); } bool isUnownedAssign() const { - return getDest().getType().getObjectType().is(); + return getDest()->getType().getObjectType().is(); } ArrayRef getAllOperands() const { return Operands.asArray(); } @@ -1333,7 +1330,7 @@ class MarkUninitializedInst friend class SILBuilder; public: - // This enum captures what the mark_uninitialized instruction is designating. + /// This enum captures what the mark_uninitialized instruction is designating. enum Kind { /// Var designates the start of a normal variable live range. Var, @@ -1356,7 +1353,7 @@ class MarkUninitializedInst Kind ThisKind; MarkUninitializedInst(SILDebugLocation *DebugLoc, SILValue Address, Kind K) - : UnaryInstructionBase(DebugLoc, Address, Address.getType()), + : UnaryInstructionBase(DebugLoc, Address, Address->getType()), ThisKind(K) {} public: @@ -1473,7 +1470,7 @@ class LoadReferenceInstBase : public UnaryInstructionBase { protected: LoadReferenceInstBase(SILDebugLocation *loc, SILValue lvalue, IsTake_t isTake) - : UnaryInstructionBase(loc, lvalue, getResultType(lvalue.getType())), + : UnaryInstructionBase(loc, lvalue, getResultType(lvalue->getType())), IsTake(unsigned(isTake)) { } @@ -1636,9 +1633,6 @@ class ConversionInst : public SILInstruction { : SILInstruction(Kind, DebugLoc, Ty) {} public: - /// All conversion instructions return a single result. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - /// All conversion instructions take the converted value, whose reference /// identity is expected to be preserved through the conversion chain, as their /// first operand. Some instructions may take additional operands that do not @@ -2016,9 +2010,6 @@ class ObjCProtocolInst : public SILInstruction ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::ObjCProtocolInst; } @@ -2113,9 +2104,6 @@ class StructInst : public SILInstruction { return Operands.getDynamicValuesAsArray(); } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } @@ -2155,7 +2143,7 @@ class StructInst : public SILInstruction { // For each operand... for (unsigned i = 0, e = Ops.size(); i != e; ++i) { // If the operand is not trivial... - if (!Ops[i].get().getType().isTrivial(Mod)) { + if (!Ops[i].get()->getType().isTrivial(Mod)) { // And we have not found an Index yet, set index to i and continue. if (!Index.hasValue()) { Index = i; @@ -2190,9 +2178,8 @@ class StructInst : public SILInstruction { /// manipulate the reference count of their object operand. class RefCountingInst : public SILInstruction { protected: - RefCountingInst(ValueKind Kind, SILDebugLocation *DebugLoc, - SILTypeList *TypeList = 0) - : SILInstruction(Kind, DebugLoc, TypeList) {} + RefCountingInst(ValueKind Kind, SILDebugLocation *DebugLoc) + : SILInstruction(Kind, DebugLoc) {} public: static bool classof(const ValueBase *V) { @@ -2286,14 +2273,11 @@ class TupleInst : public SILInstruction { return Operands.getDynamicValuesAsArray(); } - // Return the i'th value referenced by this TupleInst. + /// Return the i'th value referenced by this TupleInst. SILValue getElement(unsigned i) const { return getElements()[i]; } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } @@ -2315,7 +2299,7 @@ class TupleInst : public SILInstruction { // For each operand... for (unsigned i = 0, e = Ops.size(); i != e; ++i) { // If the operand is not trivial... - if (!Ops[i].get().getType().isTrivial(Mod)) { + if (!Ops[i].get()->getType().isTrivial(Mod)) { // And we have not found an Index yet, set index to i and continue. if (!Index.hasValue()) { Index = i; @@ -2368,8 +2352,6 @@ class EnumInst : public SILInstruction { ? OptionalOperand->asArray() : MutableArrayRef{}; } - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::EnumInst; } @@ -2392,7 +2374,7 @@ class UncheckedEnumDataInst EnumElementDecl *getElement() const { return Element; } EnumDecl *getEnumDecl() const { - auto *E = getOperand().getType().getEnumOrBoundGenericEnum(); + auto *E = getOperand()->getType().getEnumOrBoundGenericEnum(); assert(E && "Operand of unchecked_enum_data must be of enum type"); return E; } @@ -2462,7 +2444,7 @@ class UncheckedTakeEnumDataAddrInst EnumElementDecl *getElement() const { return Element; } EnumDecl *getEnumDecl() const { - auto *E = getOperand().getType().getEnumOrBoundGenericEnum(); + auto *E = getOperand()->getType().getEnumOrBoundGenericEnum(); assert(E && "Operand of unchecked_take_enum_data_addr must be of enum" " type"); return E; @@ -2490,8 +2472,8 @@ class SelectInstBase : public SILInstruction { unsigned NumCases : 31; unsigned HasDefault : 1; - // The first operand is the operand of select_xxx instruction; - // the rest are the case values and results of a select instruction. + /// The first operand is the operand of select_xxx instruction. The rest of + /// the operands are the case values and results of a select instruction. TailAllocatedOperandList<1> Operands; public: @@ -2517,9 +2499,6 @@ class SelectInstBase : public SILInstruction { SILValue getDefaultResult() const { return static_cast(this)->getDefaultResult(); } - - // getType() is OK because there's only one result. - SILType getType() const { return SILInstruction::getType(0); } }; /// Common base class for the select_enum and select_enum_addr instructions, @@ -2579,12 +2558,12 @@ class SelectEnumInstBase return Operands[NumCases + 1].get(); } - // If there is a single case that returns a literal "true" value (an - // "integer_literal $Builtin.Int1, 1" value), return it. - // - // FIXME: This is used to interoperate with passes that reasoned about the - // old enum_is_tag insn. Ideally those passes would become general enough - // not to need this. + /// If there is a single case that returns a literal "true" value (an + /// "integer_literal $Builtin.Int1, 1" value), return it. + /// + /// FIXME: This is used to interoperate with passes that reasoned about the + /// old enum_is_tag insn. Ideally those passes would become general enough + /// not to need this. NullablePtr getSingleTrueElement() const; }; @@ -2683,9 +2662,6 @@ class MetatypeInst : public SILInstruction { public: - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } @@ -2732,7 +2708,7 @@ class TupleExtractInst unsigned getFieldNo() const { return FieldNo; } TupleType *getTupleType() const { - return getOperand().getType().getSwiftRValueType()->castTo(); + return getOperand()->getType().getSwiftRValueType()->castTo(); } unsigned getNumTupleElts() const { @@ -2762,7 +2738,7 @@ class TupleElementAddrInst TupleType *getTupleType() const { - return getOperand().getType().getSwiftRValueType()->castTo(); + return getOperand()->getType().getSwiftRValueType()->castTo(); } }; @@ -2793,7 +2769,7 @@ class StructExtractInst } StructDecl *getStructDecl() const { - auto s = getOperand().getType().getStructOrBoundGenericStruct(); + auto s = getOperand()->getType().getStructOrBoundGenericStruct(); assert(s); return s; } @@ -2835,7 +2811,7 @@ class StructElementAddrInst } StructDecl *getStructDecl() const { - auto s = getOperand().getType().getStructOrBoundGenericStruct(); + auto s = getOperand()->getType().getStructOrBoundGenericStruct(); assert(s); return s; } @@ -2869,7 +2845,7 @@ class RefElementAddrInst } ClassDecl *getClassDecl() const { - auto s = getOperand().getType().getClassOrBoundGenericClass(); + auto s = getOperand()->getType().getClassOrBoundGenericClass(); assert(s); return s; } @@ -2886,9 +2862,6 @@ class MethodInst : public SILInstruction { : SILInstruction(Kind, DebugLoc, Ty), Member(Member), Volatile(Volatile) { } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - SILDeclRef getMember() const { return Member; } /// True if this dynamic dispatch is semantically required. @@ -2935,11 +2908,11 @@ class WitnessMethodInst : public MethodInst { friend class SILBuilder; CanType LookupType; - ProtocolConformance *Conformance; + ProtocolConformanceRef Conformance; Optional> OptionalOperand; WitnessMethodInst(SILDebugLocation *DebugLoc, CanType LookupType, - ProtocolConformance *Conformance, SILDeclRef Member, + ProtocolConformanceRef Conformance, SILDeclRef Member, SILType Ty, SILValue OpenedExistential, bool Volatile = false) : MethodInst(ValueKind::WitnessMethodInst, DebugLoc, Ty, Member, @@ -2951,7 +2924,7 @@ class WitnessMethodInst : public MethodInst { static WitnessMethodInst * create(SILDebugLocation *DebugLoc, CanType LookupType, - ProtocolConformance *Conformance, SILDeclRef Member, SILType Ty, + ProtocolConformanceRef Conformance, SILDeclRef Member, SILType Ty, SILFunction *Parent, SILValue OpenedExistential, bool Volatile = false); @@ -2962,15 +2935,12 @@ class WitnessMethodInst : public MethodInst { return getMember().getDecl()->getDeclContext() ->isProtocolOrProtocolExtensionContext(); } - ProtocolConformance *getConformance() const { return Conformance; } + ProtocolConformanceRef getConformance() const { return Conformance; } /// Get a representation of the lookup type as a substitution of the /// protocol's Self archetype. Substitution getSelfSubstitution() const { - auto memberDC = getMember().getDecl()->getDeclContext(); - return Substitution{memberDC->getProtocolSelf()->getArchetype(), - getLookupType(), - Conformance}; + return Substitution{getLookupType(), Conformance}; } bool hasOperand() const { return OptionalOperand.hasValue(); } @@ -3070,11 +3040,11 @@ class InitExistentialAddrInst friend class SILBuilder; CanType ConcreteType; - ArrayRef Conformances; + ArrayRef Conformances; InitExistentialAddrInst(SILDebugLocation *DebugLoc, SILValue Existential, CanType ConcreteType, SILType ConcreteLoweredType, - ArrayRef Conformances) + ArrayRef Conformances) : UnaryInstructionBase(DebugLoc, Existential, ConcreteLoweredType.getAddressType()), ConcreteType(ConcreteType), Conformances(Conformances) {} @@ -3082,10 +3052,10 @@ class InitExistentialAddrInst static InitExistentialAddrInst * create(SILDebugLocation *DebugLoc, SILValue Existential, CanType ConcreteType, SILType ConcreteLoweredType, - ArrayRef Conformances, SILFunction *Parent); + ArrayRef Conformances, SILFunction *Parent); public: - ArrayRef getConformances() const { + ArrayRef getConformances() const { return Conformances; } @@ -3107,25 +3077,25 @@ class InitExistentialRefInst friend class SILBuilder; CanType ConcreteType; - ArrayRef Conformances; + ArrayRef Conformances; InitExistentialRefInst(SILDebugLocation *DebugLoc, SILType ExistentialType, CanType FormalConcreteType, SILValue Instance, - ArrayRef Conformances) + ArrayRef Conformances) : UnaryInstructionBase(DebugLoc, Instance, ExistentialType), ConcreteType(FormalConcreteType), Conformances(Conformances) {} static InitExistentialRefInst * create(SILDebugLocation *DebugLoc, SILType ExistentialType, CanType ConcreteType, SILValue Instance, - ArrayRef Conformances, SILFunction *Parent); + ArrayRef Conformances, SILFunction *Parent); public: CanType getFormalConcreteType() const { return ConcreteType; } - ArrayRef getConformances() const { + ArrayRef getConformances() const { return Conformances; } }; @@ -3138,18 +3108,16 @@ class InitExistentialMetatypeInst { friend class SILBuilder; - /// Pointer to the last of our tail allocated conformances. Null if this - /// existential metatype does not have any conformances. - NullablePtr LastConformance; + unsigned NumConformances; InitExistentialMetatypeInst(SILDebugLocation *DebugLoc, SILType existentialMetatypeType, SILValue metatype, - ArrayRef conformances); + ArrayRef conformances); static InitExistentialMetatypeInst * create(SILDebugLocation *DebugLoc, SILType existentialMetatypeType, - SILValue metatype, ArrayRef conformances, + SILValue metatype, ArrayRef conformances, SILFunction *parent); public: @@ -3158,7 +3126,7 @@ class InitExistentialMetatypeInst /// this method returns Decoder. CanType getFormalErasedObjectType() const { CanType exType = getType().getSwiftRValueType(); - CanType concreteType = getOperand().getType().getSwiftRValueType(); + CanType concreteType = getOperand()->getType().getSwiftRValueType(); while (auto exMetatype = dyn_cast(exType)) { exType = exMetatype.getInstanceType(); concreteType = cast(concreteType).getInstanceType(); @@ -3167,7 +3135,7 @@ class InitExistentialMetatypeInst return concreteType; } - ArrayRef getConformances() const; + ArrayRef getConformances() const; }; /// DeinitExistentialAddrInst - Given an address of an existential that has been @@ -3224,9 +3192,6 @@ class InitBlockStorageHeaderInst : public SILInstruction { ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } - /// getType() is OK since there's only one result. - SILType getType() const { return SILInstruction::getType(0); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::InitBlockStorageHeaderInst; } @@ -3317,7 +3282,7 @@ class MarkDependenceInst : public SILInstruction { MarkDependenceInst(SILDebugLocation *DebugLoc, SILValue value, SILValue base) : SILInstruction(ValueKind::MarkDependenceInst, DebugLoc, - value.getType()), + value->getType()), Operands{this, value, base} {} public: @@ -3327,8 +3292,6 @@ class MarkDependenceInst : public SILInstruction { ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::MarkDependenceInst; } @@ -3343,7 +3306,7 @@ class CopyBlockInst : friend class SILBuilder; CopyBlockInst(SILDebugLocation *DebugLoc, SILValue operand) - : UnaryInstructionBase(DebugLoc, operand, operand.getType()) {} + : UnaryInstructionBase(DebugLoc, operand, operand->getType()) {} }; /// Given an object reference, return true iff it is non-nil and refers @@ -3375,9 +3338,8 @@ class IsUniqueOrPinnedInst : /// DeallocationInst - An abstract parent class for Dealloc{Stack, Box, Ref}. class DeallocationInst : public SILInstruction { protected: - DeallocationInst(ValueKind Kind, SILDebugLocation *DebugLoc, - SILTypeList *TypeList = nullptr) - : SILInstruction(Kind, DebugLoc, TypeList) {} + DeallocationInst(ValueKind Kind, SILDebugLocation *DebugLoc) + : SILInstruction(Kind, DebugLoc) {} public: static bool classof(const ValueBase *V) { @@ -3449,7 +3411,7 @@ class DeallocPartialRefInst : public DeallocationInst { } }; -/// Deallocate memory allocated for a unsafe value buffer. +/// Deallocate memory allocated for an unsafe value buffer. class DeallocValueBufferInst : public UnaryInstructionBase { @@ -3556,6 +3518,20 @@ class ProjectBoxInst : SILType getValueType() const { return getType().getObjectType(); } }; +/// Project out the address of the value in an existential box. +class ProjectExistentialBoxInst : + public UnaryInstructionBase { + friend class SILBuilder; + + ProjectExistentialBoxInst(SILDebugLocation *DebugLoc, SILType valueType, + SILValue operand) + : UnaryInstructionBase(DebugLoc, operand, valueType.getAddressType()) {} + +public: + SILType getValueType() const { return getType().getObjectType(); } +}; + //===----------------------------------------------------------------------===// // Runtime failure //===----------------------------------------------------------------------===// @@ -3582,7 +3558,7 @@ class IndexingInst : public SILInstruction { public: IndexingInst(ValueKind Kind, SILDebugLocation *DebugLoc, SILValue Operand, SILValue Index) - : SILInstruction(Kind, DebugLoc, Operand.getType()), + : SILInstruction(Kind, DebugLoc, Operand->getType()), Operands{this, Operand, Index} {} SILValue getBase() const { return Operands[Base].get(); } @@ -3591,8 +3567,6 @@ class IndexingInst : public SILInstruction { ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_IndexingInst && V->getKind() <= ValueKind::Last_IndexingInst; @@ -3641,6 +3615,29 @@ class IndexRawPointerInst : public IndexingInst { // Instructions representing terminators //===----------------------------------------------------------------------===// +enum class TermKind { +#define TERMINATOR(Id, Parent, MemBehavior, MayRelease) Id, +#include "SILNodes.def" +}; + +struct ValueKindAsTermKind { + TermKind K; + + ValueKindAsTermKind(ValueKind V) { + switch (V) { +#define TERMINATOR(Id, Parent, MemBehavior, MayRelease) \ + case ValueKind::Id: \ + K = TermKind::Id; \ + break; +#include "SILNodes.def" + default: + llvm_unreachable("Not a terminator kind?!"); + } + } + + operator TermKind() const { return K; } +}; + /// This class defines a "terminating instruction" for a SILBasicBlock. class TermInst : public SILInstruction { protected: @@ -3664,6 +3661,8 @@ class TermInst : public SILInstruction { } bool isBranch() const { return !getSuccessors().empty(); } + + TermKind getTermKind() const { return ValueKindAsTermKind(getKind()); } }; /// UnreachableInst - Position in the code which would be undefined to reach. @@ -3788,18 +3787,18 @@ class CondBranchInst : public TermInst { ConditionIdx }; enum { - // Map branch targets to block sucessor indices. + // Map branch targets to block successor indices. TrueIdx, FalseIdx }; private: SILSuccessor DestBBs[2]; - // The number of arguments for the True branch. + /// The number of arguments for the True branch. unsigned NumTrueArgs; - // The number of arguments for the False branch. + /// The number of arguments for the False branch. unsigned NumFalseArgs; - // The first argument is the condition; the rest are BB arguments. + /// The first argument is the condition; the rest are BB arguments. TailAllocatedOperandList<1> Operands; CondBranchInst(SILDebugLocation *DebugLoc, SILValue Condition, SILBasicBlock *TrueBB, SILBasicBlock *FalseBB, @@ -3850,7 +3849,13 @@ class CondBranchInst : public TermInst { /// Returns the argument on the cond_br terminator that will be passed to /// DestBB in A. - SILValue getArgForDestBB(SILBasicBlock *DestBB, SILArgument *A); + SILValue getArgForDestBB(const SILBasicBlock *DestBB, + const SILArgument *A) const; + + /// Returns the argument on the cond_br terminator that will be passed as the + /// \p Index argument to DestBB. + SILValue getArgForDestBB(const SILBasicBlock *DestBB, + unsigned ArgIndex) const; void swapSuccessors(); @@ -4085,7 +4090,7 @@ class DynamicMethodBranchInst : public TermInst { SILSuccessor DestBBs[2]; - // The operand. + /// The operand. FixedOperandList<1> Operands; DynamicMethodBranchInst(SILDebugLocation *DebugLoc, SILValue Operand, @@ -4224,7 +4229,7 @@ class CheckedCastAddrBranchInst : public TermInst { class TryApplyInstBase : public TermInst { public: enum { - // Map branch targets to block sucessor indices. + // Map branch targets to block successor indices. NormalIdx, ErrorIdx }; @@ -4331,7 +4336,8 @@ class ApplySite { FOREACH_IMPL_RETURN(getCallee()); } - // Return the referenced function if the callee is a function_ref instruction. + /// Return the referenced function if the callee is a function_ref + /// instruction. SILFunction *getCalleeFunction() const { FOREACH_IMPL_RETURN(getCalleeFunction()); } @@ -4343,7 +4349,7 @@ class ApplySite { /// Get the type of the callee without the applied substitutions. CanSILFunctionType getOrigCalleeType() const { - return getCallee().getType().castTo(); + return getCallee()->getType().castTo(); } /// Get the type of the callee with the applied substitutions. @@ -4421,7 +4427,7 @@ class ApplySite { /// Return the ith argument passed to this instruction. SILValue getArgument(unsigned i) const { return getArguments()[i]; } - // Set the ith argument of this instruction. + /// Set the ith argument of this instruction. void setArgument(unsigned i, SILValue V) const { getArgumentOperands()[i].set(V); } diff --git a/include/swift/SIL/SILLinkage.h b/include/swift/SIL/SILLinkage.h index 3ebbd69af7c85..26d80117852a9 100644 --- a/include/swift/SIL/SILLinkage.h +++ b/include/swift/SIL/SILLinkage.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h index 5ada7bc8aad55..7dc60478f9009 100644 --- a/include/swift/SIL/SILLocation.h +++ b/include/swift/SIL/SILLocation.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index ee1d0f08f1898..1466a3e81cf01 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,8 +45,6 @@ namespace swift { class AnyFunctionType; class ASTContext; class FuncDecl; - class SILExternalSource; - class SILTypeList; class SILUndef; class SourceFile; class SerializedSILLoader; @@ -99,7 +97,6 @@ class SILModule { /// Allocator that manages the memory of all the pieces of the SILModule. mutable llvm::BumpPtrAllocator BPA; - void *TypeListUniquing; /// The swift Module associated with this SILModule. ModuleDecl *TheSwiftModule; @@ -173,9 +170,6 @@ class SILModule { /// optimizations can assume that they see the whole module. bool wholeModule; - /// The external SIL source to use when linking this module. - SILExternalSource *ExternalSource = nullptr; - /// The options passed into this SILModule. SILOptions &Options; @@ -208,9 +202,6 @@ class SILModule { /// registered handlers. The order of handlers is deterministic but arbitrary. void notifyDeleteHandlers(ValueBase *V); - /// \brief Get a uniqued pointer to a SIL type list. - SILTypeList *getSILTypeList(ArrayRef Types) const; - /// \brief This converts Swift types to SILTypes. mutable Lowering::TypeConverter Types; @@ -463,14 +454,16 @@ class SILModule { /// /// \arg C The protocol conformance mapped key to use to lookup the witness /// table. - /// \arg deserializeLazily If we can not find the witness table should we + /// \arg deserializeLazily If we cannot find the witness table should we /// attempt to lazily deserialize it. std::pair> + lookUpWitnessTable(ProtocolConformanceRef C, bool deserializeLazily=true); + std::pair> lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily=true); /// Attempt to lookup \p Member in the witness table for C. std::tuple> - lookUpFunctionInWitnessTable(const ProtocolConformance *C, SILDeclRef Member); + lookUpFunctionInWitnessTable(ProtocolConformanceRef C, SILDeclRef Member); /// Look up the VTable mapped to the given ClassDecl. Returns null on failure. SILVTable *lookUpVTable(const ClassDecl *C); @@ -493,12 +486,6 @@ class SILModule { Stage = s; } - SILExternalSource *getExternalSource() const { return ExternalSource; } - void setExternalSource(SILExternalSource *S) { - assert(!ExternalSource && "External source already set"); - ExternalSource = S; - } - /// \brief Run the SIL verifier to make sure that all Functions follow /// invariants. void verify() const; diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index c18cc92671d70..bd83cc31ddae1 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -104,7 +104,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase) INST(CopyAddrInst, SILInstruction, MayHaveSideEffects, MayRelease) INST(DestroyAddrInst, SILInstruction, MayHaveSideEffects, MayRelease) INST(ProjectValueBufferInst, SILInstruction, MayRead, DoesNotRelease) - INST(ProjectBoxInst, SILInstruction, MayRead, DoesNotRelease) + INST(ProjectBoxInst, SILInstruction, None, DoesNotRelease) + INST(ProjectExistentialBoxInst, SILInstruction, None, DoesNotRelease) ABSTRACT_VALUE(IndexingInst, SILInstruction) INST(IndexAddrInst, IndexingInst, None, DoesNotRelease) INST(IndexRawPointerInst, IndexingInst, None, DoesNotRelease) @@ -138,6 +139,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase) INST(IsUniqueInst, SILInstruction, MayHaveSideEffects, DoesNotRelease) INST(IsUniqueOrPinnedInst, SILInstruction, MayHaveSideEffects, DoesNotRelease) + INST(AllocGlobalInst, SILInstruction, MayHaveSideEffects, DoesNotRelease) + // Literals ABSTRACT_VALUE(LiteralInst, SILInstruction) INST(FunctionRefInst, LiteralInst, None, DoesNotRelease) diff --git a/include/swift/SIL/SILSuccessor.h b/include/swift/SIL/SILSuccessor.h index 4f566b815c1fa..4d002f7660e9f 100644 --- a/include/swift/SIL/SILSuccessor.h +++ b/include/swift/SIL/SILSuccessor.h @@ -1,8 +1,8 @@ -//===--- SILSuccessor.h - Terminator Instruction Successor -------*- C++ -*-==// +//===--- SILSuccessor.h - Terminator Instruction Successor ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index cdec383bacb1d..abdd6807915c6 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -74,13 +74,6 @@ enum class SILValueCategory { /// An address is a pointer to an allocated variable of the type /// (possibly uninitialized). Address, - - /// Local storage is the container for a local allocation. For - /// statically-sized types, this is just the allocation itself. - /// However, for dynamically-sized types (like archetypes or - /// resilient structs), it may be some sort of fixed-size buffer, - /// stack depth, or the like. - LocalStorage }; /// SILType - A Swift type that has been lowered to a SIL representation type. @@ -133,13 +126,6 @@ class SILType { return SILType(T, SILValueCategory::Address); } - /// Form the type for the backing storage of a locally-allocated - /// object, given a Swift type that either does not require any - /// special handling or has already been appropriately lowered. - static SILType getPrimitiveLocalStorageType(CanType T) { - return SILType(T, SILValueCategory::LocalStorage); - } - /// Apply a substitution to the type to produce another lowered SIL type. static SILType substType(SILModule &silModule, ModuleDecl *astModule, TypeSubstitutionMap &subs, SILType SrcTy); @@ -157,7 +143,17 @@ class SILType { SILValueCategory getCategory() const { return SILValueCategory(value.getInt()); } - + + /// Returns the \p Category variant of this type. + SILType getCategoryType(SILValueCategory Category) const { + return SILType(getSwiftRValueType(), Category); + } + + /// Returns the variant of this type that matches \p Ty.getCategory() + SILType copyCategory(SILType Ty) const { + return getCategoryType(Ty.getCategory()); + } + /// Returns the address variant of this type. Instructions which /// manipulate memory will generally work with object addresses. SILType getAddressType() const { @@ -170,13 +166,6 @@ class SILType { return SILType(getSwiftRValueType(), SILValueCategory::Object); } - /// Returns the local storage variant of this type. Local - /// allocations of dynamically-sized types generally require some - /// sort of buffer. - SILType getLocalStorageType() const { - return SILType(getSwiftRValueType(), SILValueCategory::LocalStorage); - } - /// Returns the Swift type referenced by this SIL type. CanType getSwiftRValueType() const { return CanType(value.getPointer()); @@ -258,41 +247,36 @@ class SILType { /// True if the type is an object type. bool isObject() const { return getCategory() == SILValueCategory::Object; } - /// True if the type is a local-storage type. - bool isLocalStorage() const { - return getCategory() == SILValueCategory::LocalStorage; - } - /// isAddressOnly - True if the type, or the referenced type of an address /// type, is address-only. For example, it could be a resilient struct or /// something of unknown size. /// /// This is equivalent to, but possibly faster than, calling /// M.Types.getTypeLowering(type).isAddressOnly(). - static bool isAddressOnly(CanType T, SILModule &M); + static bool isAddressOnly(CanType T, SILModule &M, + CanGenericSignature Sig, + ResilienceExpansion Expansion); /// Return true if this type must be returned indirectly. /// /// This is equivalent to, but possibly faster than, calling /// M.Types.getTypeLowering(type).isReturnedIndirectly(). - static bool isReturnedIndirectly(CanType type, SILModule &M) { - return isAddressOnly(type, M); + static bool isReturnedIndirectly(CanType type, SILModule &M, + CanGenericSignature Sig, + ResilienceExpansion Expansion) { + return isAddressOnly(type, M, Sig, Expansion); } /// Return true if this type must be passed indirectly. /// /// This is equivalent to, but possibly faster than, calling /// M.Types.getTypeLowering(type).isPassedIndirectly(). - static bool isPassedIndirectly(CanType type, SILModule &M) { - return isAddressOnly(type, M); + static bool isPassedIndirectly(CanType type, SILModule &M, + CanGenericSignature Sig, + ResilienceExpansion Expansion) { + return isAddressOnly(type, M, Sig, Expansion); } - /// Returns true if this type exposes a fixed layout to the given module's - /// resilience domain. - /// - /// This is currently only implemented for nominal types. - bool hasFixedLayout(SILModule &M) const; - /// True if the type, or the referenced type of an address type, is loadable. /// This is the opposite of isAddressOnly. bool isLoadable(SILModule &M) const { @@ -564,7 +548,6 @@ NON_SIL_TYPE(LValue) CanSILFunctionType getNativeSILFunctionType(SILModule &M, Lowering::AbstractionPattern orig, - CanAnyFunctionType subst, CanAnyFunctionType substInterface, SILDeclRef::Kind kind = SILDeclRef::Kind::Func); diff --git a/include/swift/SIL/SILUndef.h b/include/swift/SIL/SILUndef.h index 50722089a868a..a23c604c842d3 100644 --- a/include/swift/SIL/SILUndef.h +++ b/include/swift/SIL/SILUndef.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,9 +31,6 @@ class SILUndef : public ValueBase { template static SILUndef *getSentinelValue(SILType Ty, OwnerTy Owner) { return new (*Owner) SILUndef(Ty); } - /// getType() is ok since this is known to only have one type. - SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } - static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::SILUndef; } diff --git a/include/swift/SIL/SILVTable.h b/include/swift/SIL/SILVTable.h index 1d31ceee37cbe..ac590dbec3d7c 100644 --- a/include/swift/SIL/SILVTable.h +++ b/include/swift/SIL/SILVTable.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index b809b3b1517a9..4b4986c16c802 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,9 +25,7 @@ #include "llvm/Support/raw_ostream.h" namespace swift { - class SILTypeList; class Operand; - class SILValue; class ValueBaseUseIterator; class ValueUseIterator; class SILBasicBlock; @@ -51,10 +49,9 @@ namespace swift { /// represents a runtime computed value. Things like SILInstruction derive /// from this. class alignas(8) ValueBase : public SILAllocated { - PointerUnion TypeOrTypeList; + SILType Type; Operand *FirstUse = nullptr; friend class Operand; - friend class SILValue; const ValueKind Kind; @@ -62,10 +59,8 @@ class alignas(8) ValueBase : public SILAllocated { ValueBase &operator=(const ValueBase &) = delete; protected: - ValueBase(ValueKind Kind, SILTypeList *TypeList = 0) - : TypeOrTypeList(TypeList), Kind(Kind) {} ValueBase(ValueKind Kind, SILType Ty) - : TypeOrTypeList(Ty), Kind(Kind) {} + : Type(Ty), Kind(Kind) {} public: ~ValueBase() { @@ -75,26 +70,12 @@ class alignas(8) ValueBase : public SILAllocated { ValueKind getKind() const { return Kind; } - ArrayRef getTypes() const; - /// True if the "value" is actually a value that can be used by other /// instructions. - bool hasValue() const { return !TypeOrTypeList.isNull(); } - - SILType getType(unsigned i) const { - if (TypeOrTypeList.is()) { - assert(i == 0); - return TypeOrTypeList.get(); - } - return getTypes()[i]; - } + bool hasValue() const { return !Type.isNull(); } - unsigned getNumTypes() const { - if (TypeOrTypeList.isNull()) - return 0; - if (TypeOrTypeList.is()) - return 1; - return getTypes().size(); + SILType getType() const { + return Type; } /// Replace every use of a result of this instruction with the corresponding @@ -165,137 +146,43 @@ class PointerLikeTypeTraits { namespace swift { -enum { - /// The number of bits required to store a ResultNumber. - /// This is primarily here as a way to allow everything that - /// depends on it to be easily grepped. - ValueResultNumberBits = 2 -}; - -/// SILValue - A SILValue is a use of a specific result of an ValueBase. As -/// such, it is a pair of the ValueBase and the result number being referenced. +/// SILValue - A SILValue is a wrapper around a ValueBase pointer. class SILValue { - llvm::PointerIntPair ValueAndResultNumber; - - explicit SILValue(void *p) { - ValueAndResultNumber = - decltype(ValueAndResultNumber)::getFromOpaqueValue(p); - } + ValueBase *Value; public: - SILValue(const ValueBase *V = 0, unsigned ResultNumber = 0) - : ValueAndResultNumber((ValueBase *)V, ResultNumber) { - assert(ResultNumber == getResultNumber() && "Overflow"); - } - - ValueBase *getDef() const { - return ValueAndResultNumber.getPointer(); - } - ValueBase *operator->() const { return getDef(); } - ValueBase &operator*() const { return *getDef(); } - unsigned getResultNumber() const { return ValueAndResultNumber.getInt(); } + SILValue(const ValueBase *V = nullptr) + : Value((ValueBase *)V) { } - SILType getType() const { - return getDef()->getType(getResultNumber()); - } + ValueBase *operator->() const { return Value; } + ValueBase &operator*() const { return *Value; } + operator ValueBase *() const { return Value; } // Comparison. - bool operator==(SILValue RHS) const { - return ValueAndResultNumber == RHS.ValueAndResultNumber; - } + bool operator==(SILValue RHS) const { return Value == RHS.Value; } + bool operator==(ValueBase *RHS) const { return Value == RHS; } bool operator!=(SILValue RHS) const { return !(*this == RHS); } - // Ordering (for std::map). - bool operator<(SILValue RHS) const { - return ValueAndResultNumber.getOpaqueValue() < - RHS.ValueAndResultNumber.getOpaqueValue(); - } - - using use_iterator = ValueUseIterator; - - /// Returns true if this value has no uses. - /// To ignore debug-info instructions use swift::hasNoUsesExceptDebug instead - /// (see comment in DebugUtils.h). - inline bool use_empty() const; - - inline use_iterator use_begin() const; - inline use_iterator use_end() const; - - /// Returns a range of all uses, which is useful for iterating over all uses. - /// To ignore debug-info instructions use swift::getNonDebugUses instead - /// (see comment in DebugUtils.h). - inline iterator_range getUses() const; - - /// Returns true if this value has exactly one use. - /// To ignore debug-info instructions use swift::hasOneNonDebugUse instead - /// (see comment in DebugUtils.h). - inline bool hasOneUse() const; - - /// Return the underlying SILValue after stripping off all casts from the - /// current SILValue. - SILValue stripCasts(); - - /// Return the underlying SILValue after stripping off all upcasts from the - /// current SILValue. - SILValue stripUpCasts(); - - /// Return the underlying SILValue after stripping off all - /// upcasts and downcasts. - SILValue stripClassCasts(); - - /// Return the underlying SILValue after stripping off all casts and - /// address projection instructions. - /// - /// An address projection instruction is one of one of ref_element_addr, - /// struct_element_addr, tuple_element_addr. - SILValue stripAddressProjections(); - - /// Return the underlying SILValue after stripping off all aggregate projection - /// instructions. - /// - /// An aggregate projection instruction is either a struct_extract or a - /// tuple_extract instruction. - SILValue stripValueProjections(); - - /// Return the underlying SILValue after stripping off all indexing - /// instructions. - /// - /// An indexing inst is either index_addr or index_raw_pointer. - SILValue stripIndexingInsts(); - - /// Returns the underlying value after stripping off a builtin expect - /// intrinsic call. - SILValue stripExpectIntrinsic(); - - void replaceAllUsesWith(SILValue V); - - void dump() const; - void print(raw_ostream &os) const; + bool operator!=(ValueBase *RHS) const { return Value != RHS; } /// Return true if underlying ValueBase of this SILValue is non-null. Return /// false otherwise. - bool isValid() const { return getDef() != nullptr; } - /// Return true if underlying ValueBase of this SILValue is non-null. Return - /// false otherwise. - explicit operator bool() const { return getDef() != nullptr; } + explicit operator bool() const { return Value != nullptr; } /// Convert this SILValue into an opaque pointer like type. For use with /// PointerLikeTypeTraits. void *getOpaqueValue() const { - return ValueAndResultNumber.getOpaqueValue(); + return (void *)Value; } /// Convert the given opaque pointer into a SILValue. For use with /// PointerLikeTypeTraits. static SILValue getFromOpaqueValue(void *p) { - return SILValue(p); + return SILValue((ValueBase *)p); } - /// Get the SILLocation associated with the value, if it has any. - Optional getLoc() const; - enum { NumLowBitsAvailable = - llvm::PointerLikeTypeTraits:: + llvm::PointerLikeTypeTraits:: NumLowBitsAvailable }; }; @@ -340,7 +227,7 @@ class Operand { // It's probably not worth optimizing for the case of switching // operands on a single value. removeFromCurrent(); - assert(reinterpret_cast(Owner) != newValue.getDef() && + assert(reinterpret_cast(Owner) != newValue && "Cannot add a value as an operand of the instruction that defines it!"); TheValue = newValue; insertIntoCurrent(); @@ -374,13 +261,6 @@ class Operand { /// using instruction. unsigned getOperandNumber() const; - /// Hoist the address projection rooted in this operand to \p InsertBefore. - /// Requires the projected value to dominate the insertion point. - /// - /// Will look through single basic block predeccessor arguments. - void hoistAddressProjections(SILInstruction *InsertBefore, - DominanceInfo *DomTree); - private: void removeFromCurrent() { if (!Back) return; @@ -512,72 +392,6 @@ inline bool ValueBase::hasOneUse() const { return ++I == E; } -/// An iterator over all uses of a specific result of a ValueBase. -class ValueUseIterator : public std::iterator -{ - llvm::PointerIntPair CurAndResultNumber; -public: - ValueUseIterator() = default; - explicit ValueUseIterator(Operand *cur, unsigned resultNumber) { - // Skip past uses with different result numbers. - while (cur && cur->get().getResultNumber() != resultNumber) - cur = cur->NextUse; - - CurAndResultNumber.setPointerAndInt(cur, resultNumber); - } - - Operand *operator*() const { return CurAndResultNumber.getPointer(); } - Operand *operator->() const { return operator*(); } - - SILInstruction *getUser() const { - return CurAndResultNumber.getPointer()->getUser(); - } - - ValueUseIterator &operator++() { - Operand *next = CurAndResultNumber.getPointer(); - assert(next && "incrementing past end()!"); - - // Skip past uses with different result numbers. - while ((next = next->NextUse)) { - if (next->get().getResultNumber() == CurAndResultNumber.getInt()) - break; - } - - CurAndResultNumber.setPointer(next); - return *this; - } - - ValueUseIterator operator++(int unused) { - ValueUseIterator copy = *this; - ++*this; - return copy; - } - - friend bool operator==(ValueUseIterator lhs, ValueUseIterator rhs) { - return lhs.CurAndResultNumber.getPointer() - == rhs.CurAndResultNumber.getPointer(); - } - friend bool operator!=(ValueUseIterator lhs, ValueUseIterator rhs) { - return !(lhs == rhs); - } -}; -inline SILValue::use_iterator SILValue::use_begin() const { - return SILValue::use_iterator((*this)->FirstUse, getResultNumber()); -} -inline SILValue::use_iterator SILValue::use_end() const { - return SILValue::use_iterator(nullptr, 0); -} -inline iterator_range SILValue::getUses() const { - return { use_begin(), use_end() }; -} -inline bool SILValue::use_empty() const { return use_begin() == use_end(); } -inline bool SILValue::hasOneUse() const { - auto I = use_begin(), E = use_end(); - if (I == E) return false; - return ++I == E; -} - /// A constant-size list of the operands of an instruction. template class FixedOperandList { Operand Buffer[N]; @@ -756,12 +570,11 @@ template<> class TailAllocatedOperandList<0> { /// SILValue hashes just like a pointer. static inline llvm::hash_code hash_value(SILValue V) { - return llvm::hash_value(V.getDef()); + return llvm::hash_value((ValueBase *)V); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SILValue V) { - OS << "(" << V.getResultNumber() << "): "; - V.print(OS); + V->print(OS); return OS; } @@ -773,7 +586,7 @@ namespace llvm { template<> struct simplify_type { typedef ::swift::ValueBase *SimpleType; static SimpleType getSimplifiedValue(::swift::SILValue Val) { - return Val.getDef(); + return Val; } }; template<> struct simplify_type< ::swift::SILValue> @@ -790,11 +603,7 @@ namespace llvm { llvm::DenseMapInfo::getTombstoneKey()); } static unsigned getHashValue(swift::SILValue V) { - auto ResultNumHash = - DenseMapInfo::getHashValue(V.getResultNumber()); - auto ValueBaseHash = - DenseMapInfo::getHashValue(V.getDef()); - return hash_combine(ResultNumHash, ValueBaseHash); + return DenseMapInfo::getHashValue(V); } static bool isEqual(swift::SILValue LHS, swift::SILValue RHS) { return LHS == RHS; diff --git a/include/swift/SIL/SILValueProjection.h b/include/swift/SIL/SILValueProjection.h index da14601523d27..f8e5533442e64 100644 --- a/include/swift/SIL/SILValueProjection.h +++ b/include/swift/SIL/SILValueProjection.h @@ -1,8 +1,8 @@ -//===------------------------ SILValueProjection.h ---------------------- -===// +//===--- SILValueProjection.h -----------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,24 +11,26 @@ //===----------------------------------------------------------------------===// /// /// This file defines SILValueProjection, a class containing a SILValue base -/// and a ProjectionPath. It is used as the base class for LSLocation and +/// and a NewProjectionPath. It is used as the base class for LSLocation and /// LSValue. /// /// In the case of LSLocation, the base represents the base of the allocated -/// objects and the ProjectionPath tells which field in the object the +/// objects and the NewProjectionPath tells which field in the object the /// LSLocation represents. /// -/// In the case of LSValue, the base represents the root of loaded or -/// stored value it represents. And the ProjectionPath represents the field in -/// the loaded/store value the LSValue represents. +/// In the case of LSValue, the base represents the root of loaded or stored +/// value it represents. And the NewProjectionPath represents the field in the +/// loaded/store value the LSValue represents. /// //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_VALUEPROJECTION_H #define SWIFT_SIL_VALUEPROJECTION_H +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/Utils/Local.h" @@ -51,7 +53,7 @@ class LSValue; class SILValueProjection { public: - enum KeyKind : uint8_t { EmptyKey = 0, TombstoneKey, NormalKey }; + enum KeyKind : uint8_t { Empty = 0, Tombstone, Normal }; protected: /// The base of the object. @@ -59,79 +61,66 @@ class SILValueProjection { /// Empty key, tombstone key or normal key. KeyKind Kind; /// The path to reach the accessed field of the object. - Optional Path; + Optional Path; public: /// Constructors. - SILValueProjection() : Base(), Kind(NormalKey) {} + SILValueProjection() : Base(), Kind(Normal) {} SILValueProjection(KeyKind Kind) : Base(), Kind(Kind) {} - SILValueProjection(SILValue B) : Base(B), Kind(NormalKey) {} - SILValueProjection(SILValue B, const ProjectionPath &P, - KeyKind Kind = NormalKey) - : Base(B), Kind(Kind) { - ProjectionPath T; - T.append(P); - Path = std::move(T); - } + SILValueProjection(SILValue B) : Base(B), Kind(Normal) {} + SILValueProjection(SILValue B, const Optional &P, + KeyKind Kind = Normal) + : Base(B), Kind(Kind), Path(P) {} - /// Destructors. + /// Virtual destructor. virtual ~SILValueProjection() {} /// Copy constructor. SILValueProjection(const SILValueProjection &RHS) { Base = RHS.Base; - Path.reset(); Kind = RHS.Kind; - if (!RHS.Path.hasValue()) - return; - ProjectionPath X; - X.append(RHS.Path.getValue()); - Path = std::move(X); + Path = RHS.Path; } + /// Assignment operator. SILValueProjection &operator=(const SILValueProjection &RHS) { Base = RHS.Base; - Path.reset(); Kind = RHS.Kind; - if (!RHS.Path.hasValue()) - return *this; - ProjectionPath X; - X.append(RHS.Path.getValue()); - Path = std::move(X); + Path = RHS.Path; return *this; } - /// Getters and setters for SILValueProjection. + /// Getters for SILValueProjection. KeyKind getKind() const { return Kind; } - void setKind(KeyKind K) { Kind = K; } SILValue getBase() const { return Base; } - Optional &getPath() { return Path; } + const Optional &getPath() const { return Path; } /// Reset the SILValueProjection, i.e. clear base and path. void reset() { Base = SILValue(); + Kind = Normal; Path.reset(); - Kind = NormalKey; } /// Returns whether the SILValueProjection has been initialized properly. virtual bool isValid() const { return Base && Path.hasValue(); } - /// Returns true if the LSValue has a non-empty projection path. - bool hasEmptyProjectionPath() const { return !Path.getValue().size(); } + /// Returns true if the SILValueProjection has a non-empty projection path. + bool hasEmptyNewProjectionPath() const { return !Path.getValue().size(); } - /// Return false if one projection path is a prefix of another. false - /// otherwise. + /// return true if that the two objects have the same base but access different + /// fields of the base object. bool hasNonEmptySymmetricPathDifference(const SILValueProjection &RHS) const { - const ProjectionPath &P = RHS.Path.getValue(); + const NewProjectionPath &P = RHS.Path.getValue(); return Path.getValue().hasNonEmptySymmetricDifference(P); } - /// Substract the given path from the ProjectionPath. - void subtractPaths(Optional &P) { + /// Subtract the given path from the NewProjectionPath. + void removePathPrefix(Optional &P) { if (!P.hasValue()) return; - ProjectionPath::subtractPaths(Path.getValue(), P.getValue()); + // Remove prefix does not modify the Path in-place. + Path = NewProjectionPath::removePrefix(Path.getValue(), P.getValue()); } /// Return true if the RHS have identical projection paths. @@ -153,6 +142,7 @@ class SILValueProjection { // different. if (Path.getValue() != RHS.Path.getValue()) return false; + // Otherwise, the 2 SILValueProjections are the same. return true; } @@ -164,8 +154,8 @@ class SILValueProjection { // If type is not the same, then SILValueProjections different. if (Kind != RHS.Kind) return false; - // Return true if this is a TombstoneKey or EmptyKey. - if (Kind == EmptyKey || Kind == TombstoneKey) + // Return true if this is a Tombstone or Empty. + if (Kind == Empty || Kind == Tombstone) return true; // If Base is different, then SILValueProjections different. if (Base != RHS.Base) @@ -178,37 +168,34 @@ class SILValueProjection { return true; } - /// Returns the hashcode for the location. - llvm::hash_code getHashCode() const { - llvm::hash_code HC = llvm::hash_combine( - Base.getDef(), Base.getResultNumber(), Base.getType()); - if (!Path.hasValue()) - return HC; - HC = llvm::hash_combine(HC, hash_value(Path.getValue())); - return HC; - } - - virtual void print() const; + /// Print the SILValueProjection. + virtual void print(SILModule *Mod); - /// Create a path of ValueProjection with the given VA and Path. - static SILValue createExtract(SILValue VA, Optional &Path, + /// Create a path of AddrProjection or ValueProjection with the given VA + /// and Path. + static SILValue createExtract(SILValue VA, + const Optional &Path, SILInstruction *Inst, bool IsValExt); }; +static inline llvm::hash_code hash_value(const SILValueProjection &S) { + const SILValue Base = S.getBase(); + const Optional &Path = S.getPath(); + llvm::hash_code HC = llvm::hash_combine(Base.getOpaqueValue()); + if (!Path.hasValue()) + return HC; + return llvm::hash_combine(HC, hash_value(Path.getValue())); +} + //===----------------------------------------------------------------------===// // Load Store Value //===----------------------------------------------------------------------===// using LSLocationValueMap = llvm::DenseMap; using LSValueList = llvm::SmallVector; -using LSValueIndexMap = llvm::DenseMap; +using LSValueIndexMap = llvm::SmallDenseMap; using ValueTableMap = llvm::SmallMapVector; -/// This class represents either a single SILValue or a covering of values that -/// we can forward from via the introduction of a SILArgument. This enables us -/// to treat the case of having one value or multiple values and load and store -/// cases all at once abstractly and cleanly. -/// /// A LSValue is an abstraction of an object field value in program. It /// consists of a base that is the tracked SILValue, and a projection path to /// the represented field. @@ -225,11 +212,11 @@ using ValueTableMap = llvm::SmallMapVector; /// %0 = alloc_stack $A // var x // users: %4, %7 /// %5 = integer_literal $Builtin.Int64, 19 // user: %6 /// %6 = struct $Int (%5 : $Builtin.Int64) // user: %8 -/// %7 = struct_element_addr %0#1 : $*A, #A.a // user: %8 +/// %7 = struct_element_addr %0 : $*A, #A.a // user: %8 /// store %6 to %7 : $*Int // id: %8 /// %9 = integer_literal $Builtin.Int64, 20 // user: %10 /// %10 = struct $Int (%9 : $Builtin.Int64) // user: %12 -/// %11 = struct_element_addr %0#1 : $*A, #A.b // user: %12 +/// %11 = struct_element_addr %0 : $*A, #A.b // user: %12 /// store %10 to %11 : $*Int // id: %12 /// } /// @@ -242,12 +229,12 @@ using ValueTableMap = llvm::SmallMapVector; /// %1 = function_ref @a.A.init : $@convention(thin) (@thin A.Type) -> A /// %2 = metatype $@thin A.Type // user: %3 /// %3 = apply %1(%2) : $@convention(thin) (@thin A.Type) -> A // user: %4 -/// store %3 to %0#1 : $*A // id: %4 +/// store %3 to %0 : $*A // id: %4 /// } /// -/// NOTE: LSValue can take 2 forms. +/// LSValue can take 2 forms. /// -/// 1. It can take a concrete value, i.e. with a valid Base and ProjectionPath. +/// 1. It can take a concrete value, i.e. with a valid Base and NewProjectionPath. /// using the extract function, it can be materialized in IR. /// /// 2. It can represent a covering set of LSValues from all predecessor @@ -259,9 +246,9 @@ using ValueTableMap = llvm::SmallMapVector; /// reduce will create the forwarding SILValue by merging them while /// creating as few value extraction and aggregation as possible. /// -/// NOTE: ProjectionPath in LSValue could be replaced by the -/// ProjectionPath in the LSLocation, but that would require we break the -/// ProjectionPath into 2 parts, 1 for the Base to the accessed (aggregate) node +/// NOTE: NewProjectionPath in LSValue could be replaced by the +/// NewProjectionPath in the LSLocation, but that would require we break the +/// NewProjectionPath into 2 parts, 1 for the Base to the accessed (aggregate) node /// and another 1 for the accessed (aggregate) node to the leaf node the /// LSLocation represents. /// @@ -273,15 +260,15 @@ class LSValue : public SILValueProjection { /// If this is a covering value, we need to go to each predecessor to /// materialize the value. bool IsCoveringValue; - public: /// Constructors. LSValue() : SILValueProjection(), IsCoveringValue(false) {} - LSValue(SILValue B) : SILValueProjection(B), IsCoveringValue(false) {} - LSValue(SILValue B, const ProjectionPath &P) - : SILValueProjection(B, P), IsCoveringValue(false) {} + LSValue(SILValue B, const NewProjectionPath &P) + : SILValueProjection(B, P), IsCoveringValue(false) { + assert(isValid() && "Trying to create invalid LSValue"); + } LSValue(KeyKind Kind) : SILValueProjection(Kind), IsCoveringValue(false) {} - LSValue(bool CSVal) : SILValueProjection(NormalKey), IsCoveringValue(CSVal) {} + LSValue(bool CSVal) : SILValueProjection(Normal), IsCoveringValue(CSVal) {} /// Copy constructor. LSValue(const LSValue &RHS) : SILValueProjection(RHS) { @@ -302,7 +289,6 @@ class LSValue : public SILValueProjection { return true; if (IsCoveringValue != RHS.isCoveringValue()) return false; - return SILValueProjection::operator==(RHS); } @@ -310,44 +296,34 @@ class LSValue : public SILValueProjection { bool isValid() const { if (IsCoveringValue) return true; - return Base && Path.hasValue(); + return SILValueProjection::isValid(); } /// Take the last level projection off. Return the modified LSValue. LSValue &stripLastLevelProjection() { - Path.getValue().remove_front(); + Path.getValue().pop_back(); return *this; } /// Returns true if this LSValue is a covering value. bool isCoveringValue() const { return IsCoveringValue; } - /// Mark this LSValue as a covering value. - void setCoveringValue() { - Base = SILValue(); - Path.reset(); - IsCoveringValue = true; - } /// Materialize the SILValue that this LSValue represents. /// /// In the case where we have a single value this can be materialized by /// applying Path to the Base. - /// - /// In the case where we are handling a covering set, this is initially null - /// and when we insert the PHI node, this is set to the SILArgument which - /// represents the PHI node. SILValue materialize(SILInstruction *Inst) { if (IsCoveringValue) return SILValue(); return SILValueProjection::createExtract(Base, Path, Inst, true); } - void print() const { + void print(SILModule *Mod) { if (IsCoveringValue) { llvm::outs() << "Covering Value"; return; } - SILValueProjection::print(); + SILValueProjection::print(Mod); } //============================// @@ -363,36 +339,25 @@ class LSValue : public SILValueProjection { /// location holds. This may involve extracting and aggregating available /// values. /// - /// NOTE: reduce assumes that every component of the location has an concrete + /// NOTE: reduce assumes that every component of the location has a concrete /// (i.e. not coverings set) available value in LocAndVal. /// /// TODO: we do not really need the llvm::DenseMap here /// we only need a map between the projection tree of a SILType and the value - /// each leaf node takes. This will be implemented once ProjectionPath memory + /// each leaf node takes. This will be implemented once NewProjectionPath memory /// cost is reduced and made copyable (its copy constructor is deleted at the - /// momemt). + /// moment). static SILValue reduce(LSLocation &Base, SILModule *Mod, LSLocationValueMap &LocAndVal, SILInstruction *InsertPt, TypeExpansionAnalysis *TE); - - /// Enumerate the given LSValue. - static void enumerateLSValue(SILModule *M, SILValue Val, - std::vector &Vault, - LSValueIndexMap &ValToBit, - TypeExpansionAnalysis *TE); - - /// Enumerate all the LSValues in the function. - static void enumerateLSValues(SILFunction &F, std::vector &Vault, - LSValueIndexMap &ValToBit, - TypeExpansionAnalysis *TE); }; static inline llvm::hash_code hash_value(const LSValue &V) { + llvm::hash_code HC = llvm::hash_combine(V.isCoveringValue()); if (V.isCoveringValue()) - return llvm::hash_combine(V.isCoveringValue()); - return llvm::hash_combine(V.getBase().getDef(), V.getBase().getResultNumber(), - V.getBase().getType()); + return HC; + return llvm::hash_combine(HC, hash_value((SILValueProjection)V)); } //===----------------------------------------------------------------------===// @@ -401,7 +366,8 @@ static inline llvm::hash_code hash_value(const LSValue &V) { /// Type declarations. using LSLocationSet = llvm::DenseSet; using LSLocationList = llvm::SmallVector; -using LSLocationIndexMap = llvm::DenseMap; +using LSLocationIndexMap = llvm::SmallDenseMap; +using LSLocationBaseMap = llvm::DenseMap; /// This class represents a field in an allocated object. It consists of a /// base that is the tracked SILValue, and a projection path to the @@ -438,17 +404,23 @@ class LSLocation : public SILValueProjection { public: /// Constructors. LSLocation() {} - LSLocation(SILValue B) : SILValueProjection(B) { initialize(B); } - LSLocation(SILValue B, ProjectionPath &P, KeyKind Kind = NormalKey) - : SILValueProjection(B, P, Kind) {} + LSLocation(SILValue B, const Optional &P, KeyKind K = Normal) + : SILValueProjection(B, P, K) {} LSLocation(KeyKind Kind) : SILValueProjection(Kind) {} - /// Use the concatenation of the 2 ProjectionPaths as the Path. - LSLocation(SILValue B, const ProjectionPath &P1, const ProjectionPath &P2) + /// Use the concatenation of the 2 NewProjectionPaths as the Path. + LSLocation(SILValue B, const NewProjectionPath &BP, const NewProjectionPath &AP) : SILValueProjection(B) { - ProjectionPath T; - T.append(P1); - T.append(P2); - Path = std::move(T); + NewProjectionPath P((*Base).getType()); + P.append(BP); + P.append(AP); + Path = P; + } + + /// Initialize a location with a new set of base, projectionpath and kind. + void init(SILValue B, const Optional &P, KeyKind K= Normal) { + Base = B; + Path = P; + Kind = K; } /// Copy constructor. @@ -461,40 +433,23 @@ class LSLocation : public SILValueProjection { } /// Returns the type of the object the LSLocation represents. - SILType getType() const { - // Base might be a address type, e.g. from alloc_stack of struct, - // enum or tuples. - if (Path.getValue().empty()) - return Base.getType().getObjectType(); - return Path.getValue().front().getType().getObjectType(); + SILType getType(SILModule *M) { + return Path.getValue().getMostDerivedType(*M); } - /// Trace the given SILValue till the base of the accessed object. Also - /// construct the projection path to the field accessed. - void initialize(SILValue val); - /// Get the first level locations based on this location's first level /// projection. void getFirstLevelLSLocations(LSLocationList &Locs, SILModule *Mod); - /// Returns true if the LSLocation is local to this function, i.e. - /// does not escape. - /// - /// TODO: we should look at the projection path as well. i.e. one field - /// might escape but the object itself does not. - /// - bool isNonEscapingLocalLSLocation() { - assert(isValid() && "Invalid memory location"); - // TODO: this does not have to be limited to allocstack. - return isa(Base) && isNonEscapingLocalObject(Base); - } - /// Check whether the 2 LSLocations may alias each other or not. bool isMayAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA); /// Check whether the 2 LSLocations must alias each other or not. bool isMustAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA); + /// Check whether the LSLocation can escape the current function. + bool isNonEscapingLocalLSLocation(SILFunction *Fn, EscapeAnalysis *EA); + //============================// // static functions. // //============================// @@ -504,70 +459,71 @@ class LSLocation : public SILValueProjection { /// In SIL, we can have a store to an aggregate and loads from its individual /// fields. Therefore, we expand all the operations on aggregates onto /// individual fields and process them separately. - static void expand(LSLocation &Base, SILModule *Mod, LSLocationList &Locs, + static void expand(LSLocation Base, SILModule *Mod, LSLocationList &Locs, TypeExpansionAnalysis *TE); /// Given a set of locations derived from the same base, try to merge/reduce /// them into smallest number of LSLocations possible. - static void reduce(LSLocation &Base, SILModule *Mod, LSLocationSet &Locs, + static void reduce(LSLocation Base, SILModule *Mod, LSLocationSet &Locs, TypeExpansionAnalysis *TE); /// Enumerate the given Mem LSLocation. static void enumerateLSLocation(SILModule *M, SILValue Mem, std::vector &LSLocationVault, LSLocationIndexMap &LocToBit, + LSLocationBaseMap &BaseToLoc, TypeExpansionAnalysis *TE); /// Enumerate all the locations in the function. static void enumerateLSLocations(SILFunction &F, std::vector &LSLocationVault, LSLocationIndexMap &LocToBit, + LSLocationBaseMap &BaseToLoc, TypeExpansionAnalysis *TE); }; static inline llvm::hash_code hash_value(const LSLocation &L) { - return llvm::hash_combine(L.getBase().getDef(), L.getBase().getResultNumber(), - L.getBase().getType()); + return llvm::hash_combine(hash_value((SILValueProjection)L)); } } // end swift namespace -/// LSLocation is used in DenseMap, define functions required by DenseMap. +/// LSLocation and LSValue are used in DenseMap. namespace llvm { using swift::SILValueProjection; using swift::LSLocation; using swift::LSValue; -template <> struct DenseMapInfo { - static inline LSLocation getEmptyKey() { - return LSLocation(SILValueProjection::EmptyKey); +template <> struct DenseMapInfo { + static inline LSValue getEmptyKey() { + return LSValue(SILValueProjection::Empty); } - static inline LSLocation getTombstoneKey() { - return LSLocation(SILValueProjection::TombstoneKey); + static inline LSValue getTombstoneKey() { + return LSValue(SILValueProjection::Tombstone); } - static inline unsigned getHashValue(const LSLocation &Loc) { - return hash_value(Loc); + static inline unsigned getHashValue(const LSValue &Val) { + return hash_value(Val); } - static bool isEqual(const LSLocation &LHS, const LSLocation &RHS) { + static bool isEqual(const LSValue &LHS, const LSValue &RHS) { return LHS == RHS; } }; -template <> struct DenseMapInfo { - static inline LSValue getEmptyKey() { - return LSValue(SILValueProjection::EmptyKey); +template <> struct DenseMapInfo { + static inline LSLocation getEmptyKey() { + return LSLocation(SILValueProjection::Empty); } - static inline LSValue getTombstoneKey() { - return LSValue(SILValueProjection::TombstoneKey); + static inline LSLocation getTombstoneKey() { + return LSLocation(SILValueProjection::Tombstone); } - static inline unsigned getHashValue(const LSValue &Val) { - return hash_value(Val); + static inline unsigned getHashValue(const LSLocation &Loc) { + return hash_value(Loc); } - static bool isEqual(const LSValue &LHS, const LSValue &RHS) { + static bool isEqual(const LSLocation &LHS, const LSLocation &RHS) { return LHS == RHS; } }; } // namespace llvm -#endif // SWIFT_SIL_MEMLOCATION_H +#endif // SWIFT_SIL_VALUEPROJECTION_H diff --git a/include/swift/SIL/SILVisitor.h b/include/swift/SIL/SILVisitor.h index a8c19e646bb3f..e9366a2c89b55 100644 --- a/include/swift/SIL/SILVisitor.h +++ b/include/swift/SIL/SILVisitor.h @@ -1,8 +1,8 @@ -//===--- SILVisitor.h - Defines the SILVisitor class -------------*- C++ -*-==// +//===--- SILVisitor.h - Defines the SILVisitor class ------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -41,10 +41,6 @@ class SILVisitor { llvm_unreachable("Not reachable, all cases handled"); } - ValueRetTy visit(SILValue V) { - return asImpl().visit(V.getDef()); - } - // Define default dispatcher implementations chain to parent nodes. #define VALUE(CLASS, PARENT) \ ValueRetTy visit##CLASS(CLASS *I) { \ diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h index e50f631a91359..ed372e97c0c93 100644 --- a/include/swift/SIL/SILWitnessTable.h +++ b/include/swift/SIL/SILWitnessTable.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,7 @@ #include "swift/SIL/SILAllocated.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" +#include "swift/AST/ProtocolConformanceRef.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/ilist.h" #include @@ -68,7 +69,7 @@ class SILWitnessTable : public llvm::ilist_node, ProtocolDecl *Protocol; /// The ProtocolConformance satisfying the requirement. Null if the /// conformance is dependent. - ProtocolConformance *Witness; + ProtocolConformanceRef Witness; }; /// A witness table entry referencing the protocol conformance for a refined diff --git a/include/swift/SIL/SILWitnessVisitor.h b/include/swift/SIL/SILWitnessVisitor.h index 88026463b0d9e..9ec75c00de85a 100644 --- a/include/swift/SIL/SILWitnessVisitor.h +++ b/include/swift/SIL/SILWitnessVisitor.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 62fb7adeab987..1b28fcb176495 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,7 +37,6 @@ namespace swift { class SILBuilder; class SILLocation; class SILModule; - class SILValue; class ValueDecl; namespace Lowering { @@ -193,7 +192,7 @@ class TypeLowering { /// Return the lowering for the semantic type. inline const TypeLowering &getSemanticTypeLowering(TypeConverter &TC) const; - /// Produce a exact copy of the value in the given address as a + /// Produce an exact copy of the value in the given address as a /// scalar. The caller is responsible for destroying this value, /// e.g. by releasing it. /// @@ -232,7 +231,7 @@ class TypeLowering { virtual void emitDestroyAddress(SILBuilder &B, SILLocation loc, SILValue value) const = 0; - /// Given a +1 r-value which are are claiming ownership of, destroy it. + /// Given a +1 r-value which we are claiming ownership of, destroy it. /// /// Note that an r-value might be an address. virtual void emitDestroyRValue(SILBuilder &B, SILLocation loc, @@ -366,11 +365,9 @@ struct SILConstantInfo { /// The formal type of the constant, still curried. For a normal /// function, this is just its declared type; for a getter or /// setter, computing this can be more involved. - CanAnyFunctionType FormalType SIL_FUNCTION_TYPE_DEPRECATED; CanAnyFunctionType FormalInterfaceType; /// The uncurried and bridged type of the constant. - CanAnyFunctionType LoweredType SIL_FUNCTION_TYPE_DEPRECATED; CanAnyFunctionType LoweredInterfaceType; /// The SIL function type of the constant. @@ -397,9 +394,7 @@ struct SILConstantInfo { } friend bool operator==(SILConstantInfo lhs, SILConstantInfo rhs) { - return lhs.FormalType == rhs.FormalType && - lhs.FormalInterfaceType == rhs.FormalInterfaceType && - lhs.LoweredType == rhs.LoweredType && + return lhs.FormalInterfaceType == rhs.FormalInterfaceType && lhs.LoweredInterfaceType == rhs.LoweredInterfaceType && lhs.SILFnType == rhs.SILFnType && lhs.ContextGenericParams == rhs.ContextGenericParams && @@ -420,7 +415,7 @@ enum class CaptureKind { /// A local value captured as a single pointer to storage (formed with /// @noescape closures). StorageAddress, - // A local value captures as a constant. + /// A local value captured as a constant. Constant, }; @@ -442,13 +437,15 @@ class TypeConverter { }; struct CachingTypeKey { + GenericSignature *Sig; AbstractionPattern::CachingKey OrigType; CanType SubstType; unsigned UncurryLevel; friend bool operator==(const CachingTypeKey &lhs, const CachingTypeKey &rhs) { - return lhs.OrigType == rhs.OrigType + return lhs.Sig == rhs.Sig + && lhs.OrigType == rhs.OrigType && lhs.SubstType == rhs.SubstType && lhs.UncurryLevel == rhs.UncurryLevel; } @@ -471,7 +468,12 @@ class TypeConverter { CachingTypeKey getCachingKey() const { assert(isCacheable()); - return { OrigType.getCachingKey(), SubstType, UncurryLevel }; + return { (OrigType.hasGenericSignature() + ? OrigType.getGenericSignature() + : nullptr), + OrigType.getCachingKey(), + SubstType, + UncurryLevel }; } bool isCacheable() const { @@ -481,8 +483,6 @@ class TypeConverter { IsDependent_t isDependent() const { if (SubstType->hasTypeParameter()) return IsDependent; - if (!OrigType.isOpaque() && OrigType.getType()->hasTypeParameter()) - return IsDependent; return IsNotDependent; } }; @@ -511,7 +511,7 @@ class TypeConverter { friend struct llvm::DenseMapInfo; - /// Find an cached TypeLowering by TypeKey, or return null if one doesn't + /// Find a cached TypeLowering by TypeKey, or return null if one doesn't /// exist. const TypeLowering *find(TypeKey k); /// Insert a mapping into the cache. @@ -532,14 +532,10 @@ class TypeConverter { /// The set of recursive types we've already diagnosed. llvm::DenseSet RecursiveNominalTypes; - - /// ArchetypeBuilder used for lowering types in generic function contexts. - Optional GenericArchetypes; /// The current generic context signature. CanGenericSignature CurGenericContext; - CanAnyFunctionType makeConstantType(SILDeclRef constant); CanAnyFunctionType makeConstantInterfaceType(SILDeclRef constant); /// Get the context parameters for a constant. Returns a pair of the innermost @@ -617,7 +613,8 @@ class TypeConverter { /// Lowers a Swift type to a SILType, and returns the SIL TypeLowering /// for that type. const TypeLowering &getTypeLowering(Type t, unsigned uncurryLevel = 0) { - return getTypeLowering(AbstractionPattern(t), t, uncurryLevel); + AbstractionPattern pattern(CurGenericContext, t->getCanonicalType()); + return getTypeLowering(pattern, t, uncurryLevel); } /// Lowers a Swift type to a SILType according to the abstraction @@ -671,20 +668,6 @@ class TypeConverter { return getConstantInfo(constant).getSILType(); } - /// Returns the formal AST type of a constant reference. - /// Parameters remain uncurried and unbridged. - CanAnyFunctionType getConstantFormalType(SILDeclRef constant) - SIL_FUNCTION_TYPE_DEPRECATED { - return getConstantInfo(constant).FormalType; - } - - /// Returns the lowered AST type of a constant reference. - /// Parameters have been uncurried and bridged. - CanAnyFunctionType getConstantLoweredType(SILDeclRef constant) - SIL_FUNCTION_TYPE_DEPRECATED { - return getConstantInfo(constant).LoweredType; - } - /// Returns the SILFunctionType for the given declaration. CanSILFunctionType getConstantFunctionType(SILDeclRef constant) { return getConstantInfo(constant).SILFnType; @@ -716,7 +699,6 @@ class TypeConverter { /// given substituted type. CanSILFunctionType substFunctionType(CanSILFunctionType origFnType, CanAnyFunctionType origLoweredType, - CanAnyFunctionType substLoweredType, CanAnyFunctionType substLoweredInterfaceType, const Optional &foreignError); @@ -726,8 +708,6 @@ class TypeConverter { } /// Get a function type curried with its capture context. - CanAnyFunctionType getFunctionTypeWithCaptures(CanAnyFunctionType funcType, - AnyFunctionRef closure); CanAnyFunctionType getFunctionInterfaceTypeWithCaptures( CanAnyFunctionType funcType, AnyFunctionRef closure); @@ -770,9 +750,6 @@ class TypeConverter { SILType getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType); - /// Retrieve the set of archetypes open in the given context. - GenericParamList *getEffectiveGenericParamsForContext(DeclContext *dc); - /// Retrieve the set of archetypes closed over by the given function. GenericParamList *getEffectiveGenericParams(AnyFunctionRef fn, CaptureInfo captureInfo); @@ -799,12 +776,6 @@ class TypeConverter { /// interface to this function. There must be an active generic context. void popGenericContext(CanGenericSignature sig); - /// Return the archetype builder for the current generic context. Fails if no - /// generic context has been pushed. - ArchetypeBuilder &getArchetypes() { - return *GenericArchetypes; - } - // Map a type involving context archetypes out of its context into a // dependent type. CanType getInterfaceTypeOutOfContext(CanType contextTy, @@ -915,17 +886,19 @@ namespace llvm { // Use the second field because the first field can validly be null. static CachingTypeKey getEmptyKey() { - return {APCachingKey(), CanTypeInfo::getEmptyKey(), 0}; + return {nullptr, APCachingKey(), CanTypeInfo::getEmptyKey(), 0}; } static CachingTypeKey getTombstoneKey() { - return {APCachingKey(), CanTypeInfo::getTombstoneKey(), 0}; + return {nullptr, APCachingKey(), CanTypeInfo::getTombstoneKey(), 0}; } static unsigned getHashValue(CachingTypeKey val) { + auto hashSig = + DenseMapInfo::getHashValue(val.Sig); auto hashOrig = CachingKeyInfo::getHashValue(val.OrigType); auto hashSubst = DenseMapInfo::getHashValue(val.SubstType); - return hash_combine(hashOrig, hashSubst, val.UncurryLevel); + return hash_combine(hashSig, hashOrig, hashSubst, val.UncurryLevel); } static bool isEqual(CachingTypeKey LHS, CachingTypeKey RHS) { return LHS == RHS; diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index 2b4d9178d2d97..955989ba9e437 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -1,8 +1,8 @@ -//===--- TypeSubstCloner.h - Clones code and substitutes types ---*- C++ -*-==// +//===--- TypeSubstCloner.h - Clones code and substitutes types --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -78,17 +78,15 @@ class TypeSubstCloner : public SILClonerWithScopes { Original.getContextGenericParams(), ApplySubs); // Remap opened archetypes into the cloned context. - newSub = Substitution(newSub.getArchetype(), - getASTTypeInClonedContext(newSub.getReplacement() + newSub = Substitution(getASTTypeInClonedContext(newSub.getReplacement() ->getCanonicalType()), newSub.getConformances()); return newSub; } - ProtocolConformance *remapConformance(ArchetypeType *archetype, - CanType type, - ProtocolConformance *conf) { - Substitution sub(archetype, type, conf); + ProtocolConformanceRef remapConformance(CanType type, + ProtocolConformanceRef conf) { + Substitution sub(type, conf); return remapSubstitution(sub).getConformances()[0]; } @@ -206,8 +204,8 @@ class TypeSubstCloner : public SILClonerWithScopes { auto Conformance = sub.getConformances()[0]; auto newLookupType = getOpASTType(Inst->getLookupType()); - if (Conformance) { - CanType Ty = Conformance->getType()->getCanonicalType(); + if (Conformance.isConcrete()) { + CanType Ty = Conformance.getConcrete()->getType()->getCanonicalType(); if (Ty != newLookupType) { assert(Ty->isSuperclassOf(newLookupType, nullptr) && @@ -265,7 +263,7 @@ class TypeSubstCloner : public SILClonerWithScopes { // If the type substituted type of the operand type and result types match // there is no need for an upcast and we can just use the operand. if (getOpType(Upcast->getType()) == - getOpValue(Upcast->getOperand()).getType()) { + getOpValue(Upcast->getOperand())->getType()) { ValueMap.insert({SILValue(Upcast), getOpValue(Upcast->getOperand())}); return; } @@ -278,7 +276,7 @@ class TypeSubstCloner : public SILClonerWithScopes { TypeSubstitutionMap &SubsMap; /// The original function to specialize. SILFunction &Original; - /// The substiutions used at the call site. + /// The substitutions used at the call site. ArrayRef ApplySubs; /// True, if used for inlining. bool Inlining; diff --git a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h index 4f44883ce2b20..4b18ec22719e9 100644 --- a/include/swift/SILOptimizer/Analysis/ARCAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/ARCAnalysis.h @@ -1,8 +1,8 @@ -//===--------------- ARCAnalysis.h - SIL ARC Analysis ----*- C++ -*--------===// +//===--- ARCAnalysis.h - SIL ARC Analysis -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,7 +23,6 @@ namespace swift { -class SILValue; class SILInstruction; class AliasAnalysis; class PostOrderAnalysis; diff --git a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h index e18255c9066a0..e090abf3ca6c8 100644 --- a/include/swift/SILOptimizer/Analysis/AliasAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/AliasAnalysis.h @@ -1,8 +1,8 @@ -//===-------------- AliasAnalysis.h - SIL Alias Analysis -*- C++ -*--------===// +//===--- AliasAnalysis.h - SIL Alias Analysis -------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,7 +31,6 @@ namespace { struct AliasKeyTy { // The SILValue pair: size_t V1, V2; - unsigned ResultNo1, ResultNo2; // The TBAAType pair: void *T1, *T2; }; @@ -44,18 +43,16 @@ namespace { struct MemBehaviorKeyTy { // The SILValue pair: size_t V1, V2; - // V1 is a SILInstruction and therefore ResultNo is always 0. - unsigned ResultNo2; RetainObserveKind InspectionMode; }; } namespace swift { -class SILValue; class SILInstruction; class ValueBase; class SideEffectAnalysis; +class EscapeAnalysis; /// This class is a simple wrapper around an alias analysis cache. This is /// needed since we do not have an "analysis" infrastructure. @@ -82,7 +79,7 @@ class AliasAnalysis : public SILAnalysis { enum class AliasResult : unsigned { NoAlias=0, ///< The two values have no dependencies on each /// other. - MayAlias, ///< The two values can not be proven to alias or + MayAlias, ///< The two values cannot be proven to alias or /// not alias. Anything could happen. PartialAlias, ///< The two values overlap in a partial manner. MustAlias, ///< The two values are equal. @@ -91,6 +88,7 @@ class AliasAnalysis : public SILAnalysis { private: SILModule *Mod; SideEffectAnalysis *SEA; + EscapeAnalysis *EA; using TBAACacheKey = std::pair; @@ -110,12 +108,19 @@ class AliasAnalysis : public SILAnalysis { /// The computeMemoryBehavior() method uses this map to cache queries. llvm::DenseMap MemoryBehaviorCache; - /// The AliasAnalysis/MemoryBehavior cache can't directly map a pair of - /// ValueBase pointers to alias/memorybehavior results because we'd like to - /// be able to remove deleted pointers without having to scan the whole map. - /// So, instead of storing pointers we map pointers to indices and store the - /// indices. - ValueEnumerator ValueBaseToIndex; + /// The AliasAnalysis cache can't directly map a pair of ValueBase pointers + /// to alias results because we'd like to be able to remove deleted pointers + /// without having to scan the whole map. So, instead of storing pointers we + /// map pointers to indices and store the indices. + ValueEnumerator AliasValueBaseToIndex; + + /// Same as AliasValueBaseToIndex, map a pointer to the indices for + /// MemoryBehaviorCache. + /// + /// NOTE: we do not use the same ValueEnumerator for the alias cache, + /// as when either cache is cleared, we can not clear the ValueEnumerator + /// because doing so could give rise to collisions in the other cache. + ValueEnumerator MemoryBehaviorValueBaseToIndex; AliasResult aliasAddressProjection(SILValue V1, SILValue V2, SILValue O1, SILValue O2); @@ -132,7 +137,8 @@ class AliasAnalysis : public SILAnalysis { // The pointer I is going away. We can't scan the whole cache and remove // all of the occurrences of the pointer. Instead we remove the pointer // from the cache the translates pointers to indices. - ValueBaseToIndex.invalidateValue(I); + AliasValueBaseToIndex.invalidateValue(I); + MemoryBehaviorValueBaseToIndex.invalidateValue(I); } virtual bool needsNotifications() override { return true; } @@ -140,7 +146,7 @@ class AliasAnalysis : public SILAnalysis { public: AliasAnalysis(SILModule *M) : - SILAnalysis(AnalysisKind::Alias), Mod(M), SEA(nullptr) {} + SILAnalysis(AnalysisKind::Alias), Mod(M), SEA(nullptr), EA(nullptr) {} static bool classof(const SILAnalysis *S) { return S->getKind() == AnalysisKind::Alias; @@ -164,7 +170,7 @@ class AliasAnalysis : public SILAnalysis { return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::PartialAlias; } - /// Convenience method that returns true if V1, V2 can not alias. + /// Convenience method that returns true if V1, V2 cannot alias. bool isNoAlias(SILValue V1, SILValue V2, SILType TBAAType1 = SILType(), SILType TBAAType2 = SILType()) { return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::NoAlias; @@ -233,6 +239,12 @@ class AliasAnalysis : public SILAnalysis { return MemoryBehavior::MayHaveSideEffects == B; } + /// Returns true if \p Ptr may be released in the function call \p FAS. + bool canApplyDecrementRefCount(FullApplySite FAS, SILValue Ptr); + + /// Returns true if \p Ptr may be released by the builtin \p BI. + bool canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr); + /// Encodes the alias query as a AliasKeyTy. /// The parameters to this function are identical to the parameters of alias() /// and this method serializes them into a key for the alias analysis cache. @@ -270,18 +282,16 @@ namespace llvm { template <> struct llvm::DenseMapInfo { static inline AliasKeyTy getEmptyKey() { auto Allone = std::numeric_limits::max(); - return {Allone, Allone, 0xffff, 0xffff, nullptr, nullptr}; + return {0, Allone, nullptr, nullptr}; } static inline AliasKeyTy getTombstoneKey() { auto Allone = std::numeric_limits::max(); - return {Allone, Allone, 0xff, 0xff, nullptr, nullptr}; + return {Allone, 0, nullptr, nullptr}; } static unsigned getHashValue(const AliasKeyTy Val) { unsigned H = 0; H ^= DenseMapInfo::getHashValue(Val.V1); H ^= DenseMapInfo::getHashValue(Val.V2); - H ^= DenseMapInfo::getHashValue(Val.ResultNo1); - H ^= DenseMapInfo::getHashValue(Val.ResultNo2); H ^= DenseMapInfo::getHashValue(Val.T1); H ^= DenseMapInfo::getHashValue(Val.T2); return H; @@ -289,8 +299,6 @@ namespace llvm { static bool isEqual(const AliasKeyTy LHS, const AliasKeyTy RHS) { return LHS.V1 == RHS.V1 && LHS.V2 == RHS.V2 && - LHS.ResultNo1 == RHS.ResultNo1 && - LHS.ResultNo2 == RHS.ResultNo2 && LHS.T1 == RHS.T1 && LHS.T2 == RHS.T2; } @@ -299,17 +307,16 @@ namespace llvm { template <> struct llvm::DenseMapInfo { static inline MemBehaviorKeyTy getEmptyKey() { auto Allone = std::numeric_limits::max(); - return {Allone, Allone, 0xffff, RetainObserveKind::RetainObserveKindEnd}; + return {0, Allone, RetainObserveKind::RetainObserveKindEnd}; } static inline MemBehaviorKeyTy getTombstoneKey() { auto Allone = std::numeric_limits::max(); - return {Allone, Allone, 0xff, RetainObserveKind::RetainObserveKindEnd}; + return {Allone, 0, RetainObserveKind::RetainObserveKindEnd}; } static unsigned getHashValue(const MemBehaviorKeyTy V) { unsigned H = 0; H ^= DenseMapInfo::getHashValue(V.V1); H ^= DenseMapInfo::getHashValue(V.V2); - H ^= DenseMapInfo::getHashValue(V.ResultNo2); H ^= DenseMapInfo::getHashValue(static_cast(V.InspectionMode)); return H; } @@ -317,7 +324,6 @@ namespace llvm { const MemBehaviorKeyTy RHS) { return LHS.V1 == RHS.V1 && LHS.V2 == RHS.V2 && - LHS.ResultNo2 == RHS.ResultNo2 && LHS.InspectionMode == RHS.InspectionMode; } }; diff --git a/include/swift/SILOptimizer/Analysis/Analysis.def b/include/swift/SILOptimizer/Analysis/Analysis.def index 9367ddce5976b..5961180cb5bde 100644 --- a/include/swift/SILOptimizer/Analysis/Analysis.def +++ b/include/swift/SILOptimizer/Analysis/Analysis.def @@ -1,8 +1,8 @@ -//===--- Analysis.def ----------------------------------------*- C++ -*----===// +//===--- Analysis.def -------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/Analysis.h b/include/swift/SILOptimizer/Analysis/Analysis.h index f90ed07447596..63d2975e4de74 100644 --- a/include/swift/SILOptimizer/Analysis/Analysis.h +++ b/include/swift/SILOptimizer/Analysis/Analysis.h @@ -1,8 +1,8 @@ -//===-- Analysis.h - Swift Analysis ----------------------------*- C++ -*-===// +//===--- Analysis.h - Swift Analysis ---------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/ArraySemantic.h b/include/swift/SILOptimizer/Analysis/ArraySemantic.h index c8d097b003472..31a7f6935a9f9 100644 --- a/include/swift/SILOptimizer/Analysis/ArraySemantic.h +++ b/include/swift/SILOptimizer/Analysis/ArraySemantic.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -131,7 +131,7 @@ class ArraySemanticsCall { /// Get the semantics call as an ApplyInst. operator ApplyInst *() const { return SemanticsCall; } - /// Is this an semantics call. + /// Is this a semantics call. operator bool() const { return SemanticsCall != nullptr; } /// Could this array be backed by an NSArray. diff --git a/include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h b/include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h index 95247e0d8d910..51cd5d8417f88 100644 --- a/include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h @@ -1,8 +1,8 @@ -//===- BasicCalleeAnalysis.h - Determine callees per call site -*- C++ -*--===// +//===- BasicCalleeAnalysis.h - Determine callees per call site --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h b/include/swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h index dc065ed0adc9d..dac6473ab2e01 100644 --- a/include/swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h @@ -1,8 +1,8 @@ -//===- BottomUpIPAnalysis.h - Bottom-up IP analysis base-class -*- C++ -*--===// +//===- BottomUpIPAnalysis.h - Bottom-up IP analysis base-class --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -71,7 +71,7 @@ class BottomUpIPAnalysis : public SILAnalysis { private: /// The list of callers which must be invalidated if this function gets - /// invalidated. Note that the list may contain invlid entries for already + /// invalidated. Note that the list may contain invalid entries for already /// invalidated callers. Those entries are removed lazily in /// removeInvalidCallers(). /// The lazy removal of invalid entries avoids that we additionally need to @@ -232,7 +232,7 @@ class BottomUpIPAnalysis : public SILAnalysis { /// Should be called after visiting \p FInfo during recomputation. void tryToSchedule(FunctionInfo *FInfo) { assert(FInfo->isVisited() && - "tryied to schedule function which was not visited"); + "tried to schedule function which was not visited"); assert(!FInfo->isScheduled() && "function scheduled multiple times"); if (FInfo->numUnscheduledCallees == 0) { diff --git a/include/swift/SILOptimizer/Analysis/CFG.h b/include/swift/SILOptimizer/Analysis/CFG.h index ce513ee7771d1..6e3c3cc38e772 100644 --- a/include/swift/SILOptimizer/Analysis/CFG.h +++ b/include/swift/SILOptimizer/Analysis/CFG.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h b/include/swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h index fd90e13f75b50..602ad92687c81 100644 --- a/include/swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h @@ -1,8 +1,8 @@ -//===-- ClassHierarchyAnalysis.h - Analysis of Class Hierarchy --*- C++ -*-===// +//===--- ClassHierarchyAnalysis.h - Analysis of Class Hierarchy -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/ColdBlockInfo.h b/include/swift/SILOptimizer/Analysis/ColdBlockInfo.h index fb6806d9c5226..e75f53f8f1cb2 100644 --- a/include/swift/SILOptimizer/Analysis/ColdBlockInfo.h +++ b/include/swift/SILOptimizer/Analysis/ColdBlockInfo.h @@ -1,8 +1,8 @@ -//===-- ColdBlocks.h - Fast/slow path analysis for the SIL CFG -*- C++ -*--===// +//===--- ColdBlockInfo.h - Fast/slow path analysis for SIL CFG --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h b/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h index b96e5795120bf..9eaa92270cfad 100644 --- a/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DestructorAnalysis.h @@ -1,8 +1,8 @@ -//===--- DestructorAnalysis.h ------------------------------*- C++ -*------===// +//===--- DestructorAnalysis.h -----------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -36,9 +36,9 @@ class DestructorAnalysis : public SILAnalysis { protected: bool cacheResult(CanType Type, bool Result); - bool isSafeType(Type); - bool implementsDestructorSafeContainerProtocol(NominalTypeDecl *); - bool areTypeParametersSafe(CanType); + bool isSafeType(Type Ty); + bool implementsDestructorSafeContainerProtocol(NominalTypeDecl *NomDecl); + bool areTypeParametersSafe(CanType Ty); ASTContext &getASTContext(); }; } diff --git a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h index b7a4d3007d905..331f3a34db4a9 100644 --- a/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/DominanceAnalysis.h @@ -1,8 +1,8 @@ -//===--- DominanceAnalysis.h - SIL Dominance Analysis -*- C++ -*-----------===// +//===--- DominanceAnalysis.h - SIL Dominance Analysis -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,7 +20,6 @@ namespace swift { class SILModule; -class SILValue; class SILInstruction; class DominanceAnalysis : public FunctionAnalysisBase { diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h index 8b45fad3e72a8..1b6083ee4d7e2 100644 --- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h @@ -1,8 +1,8 @@ -//===----------- EscapeAnalysis.h - SIL Escape Analysis -*- C++ -*---------===// +//===--- EscapeAnalysis.h - SIL Escape Analysis -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -66,7 +66,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Represents the "memory content" to which a pointer points to. /// The "content" represents all stored properties of the referenced object. - /// We also treat the elements of a referece-counted object as a "content" + /// We also treat the elements of a reference-counted object as a "content" /// of that object. Although ref_element_addr is just a pointer addition, we /// treat it as a "pointer" pointing to the elements. Having this additional /// indirection in the graph, we avoid letting a reference escape just @@ -118,7 +118,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// pointer points to (see NodeType). class CGNode { - /// The associated value in the functino. It is only used for debug printing. + /// The associated value in the function. It is only used for debug printing. /// There may be multiple nodes associated to the same value, e.g. a Content /// node has the same V as its points-to predecessor. ValueBase *V; @@ -192,7 +192,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { } /// Finds a successor node in the outgoing defer edges. - llvm::SmallVectorImpl::iterator findDefered(CGNode *Def) { + llvm::SmallVectorImpl::iterator findDeferred(CGNode *Def) { return std::find(defersTo.begin(), defersTo.end(), Def); } @@ -209,7 +209,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { } /// Adds a defer-edge to another node \p To. Not done if \p To is this node. - bool addDefered(CGNode *To) { + bool addDeferred(CGNode *To) { assert(!To->isMerged); if (To == this) return false; @@ -286,10 +286,23 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// the node's value. /// Note that in the false-case the node's value can still escape via /// the return instruction. - bool escapesInsideFunction() const { - return getEscapeState() > EscapeState::Return; + bool escapesInsideFunction(bool isNotAliasingArgument) const { + switch (getEscapeState()) { + case EscapeState::None: + case EscapeState::Return: + return false; + case EscapeState::Arguments: + return !isNotAliasingArgument; + case EscapeState::Global: + return true; + } } - }; + + /// Returns the content node if of this node if it exists in the graph. + CGNode *getContentNodeOrNull() const { + return pointsTo; + } +}; /// Mapping from nodes in a callee-graph to nodes in a caller-graph. class CGNodeMap { @@ -333,7 +346,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// 2) A node can only have a single outgoing points-to edge (is enforced by /// CGNode::pointsTo being a single pointer and not a vector). /// 3) The target of a points-to edge must be a Content node. - /// 4) For any node N, all pathes starting at N which consist of only + /// 4) For any node N, all paths starting at N which consist of only /// defer-edges and a single trailing points-to edge must lead to the same /// Content node. class ConnectionGraph { @@ -363,8 +376,12 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// The allocator for nodes. llvm::SpecificBumpPtrAllocator NodeAllocator; + /// True if this is a summary graph. + bool isSummaryGraph; + /// Constructs a connection graph for a function. - ConnectionGraph(SILFunction *F) : F(F) { + ConnectionGraph(SILFunction *F, bool isSummaryGraph) : + F(F), isSummaryGraph(isSummaryGraph) { } /// Returns true if the connection graph is empty. @@ -423,7 +440,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// taken. This means the node is always created for the "outermost" value /// where V is contained. /// Returns null, if V is not a "pointer". - CGNode *getOrCreateNode(ValueBase *V); + CGNode *getNode(ValueBase *V, EscapeAnalysis *EA, bool createIfNeeded = true); /// Gets or creates a content node to which \a AddrNode points to. CGNode *getContentNode(CGNode *AddrNode); @@ -432,7 +449,8 @@ class EscapeAnalysis : public BottomUpIPAnalysis { CGNode *getReturnNode() { if (!ReturnNode) { ReturnNode = allocNode(nullptr, NodeType::Return); - ReturnNode->mergeEscapeState(EscapeState::Return); + if (!isSummaryGraph) + ReturnNode->mergeEscapeState(EscapeState::Return); } return ReturnNode; } @@ -444,7 +462,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Returns the node of the "exact" value \p V (no projections are skipped) /// if one exists. - CGNode *getNodeOrNull(ValueBase *V) { + CGNode *lookupNode(ValueBase *V) { CGNode *Node = Values2Nodes.lookup(V); if (Node) return Node->getMergeTarget(); @@ -502,6 +520,9 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// lookup-up with getNode() anymore. void removeFromGraph(ValueBase *V) { Values2Nodes.erase(V); } + /// Returns true if there is a path from \p From to \p To. + bool isReachable(CGNode *From, CGNode *To); + public: /// Gets or creates a node for a value \p V. @@ -509,11 +530,8 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// taken. This means the node is always created for the "outermost" value /// where V is contained. /// Returns null, if V is not a "pointer". - CGNode *getNode(ValueBase *V, EscapeAnalysis *EA); - - /// Gets or creates a node for a SILValue (same as above). - CGNode *getNode(SILValue V, EscapeAnalysis *EA) { - return getNode(V.getDef(), EA); + CGNode *getNodeOrNull(ValueBase *V, EscapeAnalysis *EA) { + return getNode(V, EA, false); } /// Returns the number of use-points of a node. @@ -529,9 +547,6 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// e.g. release or apply instructions. bool isUsePoint(ValueBase *V, CGNode *Node); - /// Returns true if there is a path from \p From to \p To. - bool canEscapeTo(CGNode *From, CGNode *To); - /// Computes the use point information. void computeUsePoints(); @@ -566,7 +581,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// All the information we keep for a function. struct FunctionInfo : public FunctionInfoBase { - FunctionInfo(SILFunction *F) : Graph(F), SummaryGraph(F) { } + FunctionInfo(SILFunction *F) : Graph(F, false), SummaryGraph(F, true) { } /// The connection graph for the function. This is what clients of the /// analysis will see. @@ -627,7 +642,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { bool isPointer(ValueBase *V); /// If V is a pointer, set it to global escaping. - void setEscapesGlobal(ConnectionGraph *ConGraph, SILValue V) { + void setEscapesGlobal(ConnectionGraph *ConGraph, ValueBase *V) { if (CGNode *Node = ConGraph->getNode(V, this)) ConGraph->setEscapesGlobal(Node); } @@ -658,13 +673,13 @@ class EscapeAnalysis : public BottomUpIPAnalysis { template void analyzeSelectInst(SelectInst *SI, ConnectionGraph *ConGraph); - /// Returns true if \p V is an Array or the storage reference of an array. - bool isArrayOrArrayStorage(SILValue V); + /// Returns true if a release of \p V is known to not capture its content. + bool deinitIsKnownToNotCapture(SILValue V); /// Sets all operands and results of \p I as global escaping. void setAllEscaping(SILInstruction *I, ConnectionGraph *ConGraph); - /// Recomputes the connection grpah for the function \p Initial and + /// Recomputes the connection graph for the function \p Initial and /// all called functions, up to a recursion depth of MaxRecursionDepth. void recompute(FunctionInfo *Initial); @@ -704,19 +719,41 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Returns true if the value \p V can escape to the function call \p FAS. /// This means that the called function may access the value \p V. - bool canEscapeTo(SILValue V, FullApplySite FAS, ConnectionGraph *ConGraph) { - return canEscapeToUsePoint(V, FAS.getInstruction(), ConGraph); - } + /// If \p V has reference semantics, this function returns false if only the + /// address of a contained property escapes, but not the object itself. + bool canEscapeTo(SILValue V, FullApplySite FAS); + + /// Returns true if the value \p V or its content can escape to the + /// function call \p FAS. + /// This is the same as above, except that it returns true if an address of + /// a contained property escapes. + bool canObjectOrContentEscapeTo(SILValue V, FullApplySite FAS); /// Returns true if the value \p V can escape to the release-instruction \p /// RI. This means that \p RI may release \p V or any called destructor may /// access (or release) \p V. /// Note that if \p RI is a retain-instruction always false is returned. - bool canEscapeTo(SILValue V, RefCountingInst *RI, ConnectionGraph *ConGraph) { - return canEscapeToUsePoint(V, RI, ConGraph); - } - - bool canPointToSameMemory(SILValue V1, SILValue V2, ConnectionGraph *ConGraph); + bool canEscapeTo(SILValue V, RefCountingInst *RI); + + /// Returns true if the value \p V can escape to any other pointer \p To. + /// This means that either \p To is the same as \p V or contains a reference + /// to \p V. + bool canEscapeToValue(SILValue V, SILValue To); + + /// Returns true if the parameter with index \p ParamIdx can escape in the + /// called function of apply site \p FAS. + /// If it is an indirect parameter and \p checkContentOfIndirectParam is true + /// then the escape status is not checked for the address itself but for the + /// referenced pointer (if the referenced type is a pointer). + bool canParameterEscape(FullApplySite FAS, int ParamIdx, + bool checkContentOfIndirectParam); + + /// Returns true if the pointers \p V1 and \p V2 can possibly point to the + /// same memory. + /// If at least one of the pointers refers to a local object and the + /// connection-graph-nodes of both pointers do not point to the same content + /// node, the pointers do not alias. + bool canPointToSameMemory(SILValue V1, SILValue V2); virtual void invalidate(InvalidationKind K) override; diff --git a/include/swift/SILOptimizer/Analysis/FunctionOrder.h b/include/swift/SILOptimizer/Analysis/FunctionOrder.h index b9b6dbaaad634..ab86c5e3a23fc 100644 --- a/include/swift/SILOptimizer/Analysis/FunctionOrder.h +++ b/include/swift/SILOptimizer/Analysis/FunctionOrder.h @@ -1,8 +1,8 @@ -//===--- FunctionOrder.h - Utilities for function ordering ----*- C++ -*--===// +//===--- FunctionOrder.h - Utilities for function ordering -----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/IVAnalysis.h b/include/swift/SILOptimizer/Analysis/IVAnalysis.h index 69dccbe5c70e8..3cbb8cb415937 100644 --- a/include/swift/SILOptimizer/Analysis/IVAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/IVAnalysis.h @@ -1,8 +1,8 @@ -//===------------------- IVAnalysis.h - SIL IV Analysis -------*- C++ -*---===// +//===--- IVAnalysis.h - SIL IV Analysis -------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,7 +30,7 @@ class IVInfo : public SCCVisitor { public: - /// A descriptor for an induction variable comprised of an header argument + /// A descriptor for an induction variable comprised of a header argument /// (phi node) and an increment by an integer literal. class IVDesc { public: diff --git a/include/swift/SILOptimizer/Analysis/LoopAnalysis.h b/include/swift/SILOptimizer/Analysis/LoopAnalysis.h index f49099c9847fb..3b4adbbbc2db1 100644 --- a/include/swift/SILOptimizer/Analysis/LoopAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/LoopAnalysis.h @@ -1,8 +1,8 @@ -//===-------------- LoopAnalysis.h - SIL Loop Analysis -*- C++ -*----------===// +//===--- LoopAnalysis.h - SIL Loop Analysis ---------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h index 645d1964fbf26..3f9a80a0c707a 100644 --- a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h @@ -1,8 +1,8 @@ -//===--- LoopRegionAnalysis.h ---------------------------------------------===// +//===--- LoopRegionAnalysis.h -----------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -61,7 +61,7 @@ /// /// Then we perform a postorder DFS of the loop nest. The postorder provides the /// inductive rule that all loops will be visited after all of their subloops -/// hae been visited. If a Loop has no subloops (i.e. all subregions are +/// have been visited. If a Loop has no subloops (i.e. all subregions are /// blocks), we do nothing. Otherwise, if the loop does have subloops, we visit /// each subloop and do the following: /// @@ -130,8 +130,6 @@ namespace swift { -class LoopRegionFunctionInfo; - /// A loop region is a data structure which represents one of a basic block, /// loop, or function. In the case of a loop, function, it contains an internal /// data structure that represents the subregions of the loop/function. This @@ -245,7 +243,7 @@ class LoopRegion { /// a basic block. The iterator can only be compared against another invalid /// iterator. Any other use causes an unreachable being hit. /// - /// The reason this is needed is because basic blocks can not have + /// The reason this is needed is because basic blocks cannot have /// subregions, yet many graph algorithms want to be able to iterate over /// the subregions of a region regardless of whether it is a basic block, /// loop, or function. By allowing for invalid iterators for basic blocks, @@ -346,7 +344,7 @@ class LoopRegion { /// this BB, we can represent each jump as individual non-local edges in /// between loops. /// - /// *NOTE* This list is not sorted, but can not have any duplicate + /// *NOTE* This list is not sorted, but cannot have any duplicate /// elements. We have a check in LoopRegionFunctionInfo::verify to make sure /// that this stays true. The reason why this is necessary is that subregions /// of a loop, may have a non-local successor edge pointed at this region's @@ -600,20 +598,20 @@ class LoopRegion { IsUnknownControlFlowEdgeTail(false) {} void setParent(LoopRegion *PR) { - assert(!isFunction() && "Functions can not be subregions"); - assert(!PR->isBlock() && "BB regions can not be parents of a region"); + assert(!isFunction() && "Functions cannot be subregions"); + assert(!PR->isBlock() && "BB regions cannot be parents of a region"); ParentID = PR->getID(); } void addPred(LoopRegion *LNR) { - assert(!isFunction() && "Functions can not have predecessors"); + assert(!isFunction() && "Functions cannot have predecessors"); if (std::count(pred_begin(), pred_end(), LNR->getID())) return; Preds.push_back(LNR->ID); } unsigned addSucc(LoopRegion *Successor) { - assert(!isFunction() && "Functions can not have successors"); + assert(!isFunction() && "Functions cannot have successors"); return Succs.insert(SuccessorID(Successor->getID(), false)); } @@ -644,14 +642,14 @@ class LoopRegion { void removeLocalSucc(unsigned ID) { Succs.erase(SuccessorID(ID, false)); } void addBlockSubregion(LoopRegion *R) { - assert(!isBlock() && "Blocks can not have subregions"); + assert(!isBlock() && "Blocks cannot have subregions"); assert(R->isBlock() && "Assumed R was a basic block"); R->setParent(this); getSubregionData().addBlockSubregion(R); } void addLoopSubregion(LoopRegion *L, LoopRegion *Header) { - assert(!isBlock() && "Blocks can not have subregions"); + assert(!isBlock() && "Blocks cannot have subregions"); assert(L->isLoop() && "Assumed L was a loop"); assert(Header->isBlock() && "Assumed Header was a loop"); L->setParent(this); diff --git a/include/swift/SILOptimizer/Analysis/PostOrderAnalysis.h b/include/swift/SILOptimizer/Analysis/PostOrderAnalysis.h index f0305e76e6962..bbb89ea5442db 100644 --- a/include/swift/SILOptimizer/Analysis/PostOrderAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/PostOrderAnalysis.h @@ -1,8 +1,8 @@ -//===--- PostOrderAnalysis.h - SIL POT and RPOT Analysis -------*- C++ -*--===// +//===--- PostOrderAnalysis.h - SIL POT and RPOT Analysis --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/ARC/ProgramTerminationAnalysis.h b/include/swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h similarity index 95% rename from lib/SILOptimizer/ARC/ProgramTerminationAnalysis.h rename to include/swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h index 808c843150929..a903ae2237888 100644 --- a/lib/SILOptimizer/ARC/ProgramTerminationAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h @@ -1,8 +1,8 @@ -//===--- ProgramTerminationAnalysis.h -------------------------------------===// +//===--- ProgramTerminationAnalysis.h ---------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h index 48ad53c4500dd..9d3b30f52dbe6 100644 --- a/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RCIdentityAnalysis.h @@ -1,8 +1,8 @@ -//===--- RCIdentityAnalysis.h ------------------------------*- C++ -*------===// +//===--- RCIdentityAnalysis.h -----------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/SideEffectAnalysis.h b/include/swift/SILOptimizer/Analysis/SideEffectAnalysis.h index 828515e946140..e2a8adacf48be 100644 --- a/include/swift/SILOptimizer/Analysis/SideEffectAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/SideEffectAnalysis.h @@ -1,8 +1,8 @@ -//===------ SideEffectAnalysis.h - SIL Side Effect Analysis -*- C++ -*-----===// +//===--- SideEffectAnalysis.h - SIL Side Effect Analysis --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -177,12 +177,12 @@ class SideEffectAnalysis : public BottomUpIPAnalysis { /// Can this function trap or exit the program in any way? bool Traps = false; - /// Does this function read a refernce count other than with retain or + /// Does this function read a reference count other than with retain or /// release instructions, e.g. isUnique? bool ReadsRC = false; - /// Returns the effecs for an address or reference. This might be a - /// parameter, the LocalEffects or, if the value can not be associated to one + /// Returns the effects for an address or reference. This might be a + /// parameter, the LocalEffects or, if the value cannot be associated to one /// of them, the GlobalEffects. Effects *getEffectsOn(SILValue Addr); @@ -230,7 +230,7 @@ class SideEffectAnalysis : public BottomUpIPAnalysis { /// Can this function trap or exit the program in any way? bool mayTrap() const { return Traps; } - /// Does this function read a refernce count other than with retain or + /// Does this function read a reference count other than with retain or /// release instructions, e.g. isUnique? bool mayReadRC() const { return ReadsRC; } diff --git a/include/swift/SILOptimizer/Analysis/SimplifyInstruction.h b/include/swift/SILOptimizer/Analysis/SimplifyInstruction.h index 3a205159f0da5..b0f81db2cb3a1 100644 --- a/include/swift/SILOptimizer/Analysis/SimplifyInstruction.h +++ b/include/swift/SILOptimizer/Analysis/SimplifyInstruction.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h b/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h index a1f150d5059ae..2ddbbcc83eaad 100644 --- a/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h @@ -1,8 +1,8 @@ -//===--- TypeExpansionAnalysis.h ------------------------------*- C++ -*------===// +//===--- TypeExpansionAnalysis.h --------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,7 +26,7 @@ enum class TEKind { TENode // Intermediate and leaf nodes expansion. }; -using TypeExpansionMap = llvm::DenseMap; +using TypeExpansionMap = llvm::DenseMap; /// This analysis determines memory effects during destruction. class TypeExpansionAnalysis : public SILAnalysis { @@ -45,9 +45,8 @@ class TypeExpansionAnalysis : public SILAnalysis { } /// Return ProjectionPath to every leaf or intermediate node of the given type. - const ProjectionPathList &getTypeExpansionProjectionPaths(SILType B, - SILModule *Mod, - TEKind K); + const NewProjectionPathList &getTypeExpansion(SILType B, SILModule *Mod, + TEKind K); }; } #endif diff --git a/include/swift/SILOptimizer/Analysis/ValueTracking.h b/include/swift/SILOptimizer/Analysis/ValueTracking.h index 7096d572d75e0..de54163790377 100644 --- a/include/swift/SILOptimizer/Analysis/ValueTracking.h +++ b/include/swift/SILOptimizer/Analysis/ValueTracking.h @@ -1,8 +1,8 @@ -//===-- ValueTracking.h - SIL Value Tracking Analysis ----------*- C++ -*--===// +//===--- ValueTracking.h - SIL Value Tracking Analysis ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,19 +21,20 @@ namespace swift { -class SILValue; - -/// Strip off casts/indexing insts/address projections from V until there is -/// nothing left to strip. -SILValue getUnderlyingObject(SILValue V); - /// Returns true if \p V is a function argument which may not alias to /// any other pointer in the function. -bool isNotAliasingArgument(SILValue V); - -/// Return true if the pointer is to a function-local object that never escapes -/// from the function. -bool isNonEscapingLocalObject(SILValue V); +/// The \p assumeInoutIsNotAliasing specifies in no-aliasing is assumed for +/// the @inout convention. See swift::isNotAliasedIndirectParameter(). +bool isNotAliasingArgument(SILValue V, InoutAliasingAssumption isInoutAliasing = + InoutAliasingAssumption::Aliasing); + +/// Returns true if \p V is local inside its function. This means its underlying +/// object either is a non-aliasing function argument or a locally allocated +/// object. +/// The \p assumeInoutIsNotAliasing specifies in no-aliasing is assumed for +/// the @inout convention. See swift::isNotAliasedIndirectParameter(). + bool pointsToLocalObject(SILValue V, InoutAliasingAssumption isInoutAliasing = + InoutAliasingAssumption::Aliasing); enum class IsZeroKind { Zero, diff --git a/include/swift/SILOptimizer/PassManager/PassManager.h b/include/swift/SILOptimizer/PassManager/PassManager.h index 5e67b96301b00..65e9718174403 100644 --- a/include/swift/SILOptimizer/PassManager/PassManager.h +++ b/include/swift/SILOptimizer/PassManager/PassManager.h @@ -1,8 +1,8 @@ -//===-- PassManager.h - Swift Pass Manager ---------------------*- C++ -*-===// +//===--- PassManager.h - Swift Pass Manager --------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" +#include #ifndef SWIFT_SILOPTIMIZER_PASSMANAGER_PASSMANAGER_H #define SWIFT_SILOPTIMIZER_PASSMANAGER_PASSMANAGER_H @@ -41,6 +42,9 @@ class SILPassManager { /// A list of registered analysis. llvm::SmallVector Analysis; + /// The worklist of functions to be processed by function passes. + std::vector FunctionWorklist; + // Name of the current optimization stage for diagnostics. std::string StageName; @@ -59,8 +63,8 @@ class SILPassManager { llvm::DenseMap CompletedPassesMap; /// Set to true when a pass invalidates an analysis. - bool currentPassHasInvalidated = false; - + bool CurrentPassHasInvalidated = false; + public: /// C'tor. It creates and registers all analysis passes, which are defined /// in Analysis.def. @@ -88,6 +92,13 @@ class SILPassManager { /// \brief Run one iteration of the optimization pipeline. void runOneIteration(); + /// \brief Add a function to the function pass worklist. + void addFunctionToWorklist(SILFunction *F) { + assert(F && F->isDefinition() && F->shouldOptimize() && + "Expected optimizable function definition!"); + FunctionWorklist.push_back(F); + } + /// \brief Broadcast the invalidation of the module to all analysis. void invalidateAnalysis(SILAnalysis::InvalidationKind K) { assert(K != SILAnalysis::InvalidationKind::Nothing && @@ -97,7 +108,7 @@ class SILPassManager { if (!AP->isLocked()) AP->invalidate(K); - currentPassHasInvalidated = true; + CurrentPassHasInvalidated = true; // Assume that all functions have changed. Clear all masks of all functions. CompletedPassesMap.clear(); @@ -111,13 +122,13 @@ class SILPassManager { if (!AP->isLocked()) AP->invalidate(F, K); - currentPassHasInvalidated = true; + CurrentPassHasInvalidated = true; // Any change let all passes run again. CompletedPassesMap[F].reset(); } /// \brief Reset the state of the pass manager and remove all transformation - /// owned by the pass manager. Anaysis passes will be kept. + /// owned by the pass manager. Analysis passes will be kept. void resetAndRemoveTransformations(); // Sets the name of the current optimization stage used for debugging. @@ -161,6 +172,9 @@ class SILPassManager { /// the module. void runModulePass(SILModuleTransform *SMT); + /// Run the passes in \p FuncTransforms on the function \p F. + void runPassesOnFunction(PassList FuncTransforms, SILFunction *F); + /// Run the passes in \p FuncTransforms. Return true /// if the pass manager requested to stop the execution /// of the optimization cycle (this is a debug feature). diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index d19d0bc0d6384..1809285e8367b 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -57,6 +57,12 @@ PASS(ClosureSpecializer, "closure-specialize", "Specialize functions passed a closure to call the closure directly") PASS(CodeSinking, "code-sinking", "Sinks code closer to users") +PASS(ComputeDominanceInfo, "compute-dominance-info", + "Utility pass that computes (post-)dominance info for all functions in " + "order to help test dominanceinfo updating") +PASS(ComputeLoopInfo, "compute-loop-info", + "Utility pass that computes loop info for all functions in order to help " + "test loop info updating") PASS(CopyForwarding, "copy-forwarding", "Eliminate redundant copies") PASS(RedundantOverflowCheckRemoval, "remove-redundant-overflow-checks", @@ -69,6 +75,7 @@ PASS(DeadObjectElimination, "deadobject-elim", "Eliminate unused objects that do not have destructors with side effects") PASS(DefiniteInitialization, "definite-init", "Definite Initialization") +PASS(Devirtualizer, "devirtualizer", "Devirtualize indirect calls") PASS(DiagnoseUnreachable, "diagnose-unreachable", "Diagnose Unreachable Code") PASS(DiagnosticConstantPropagation, "diagnostic-constant-propagation", @@ -91,13 +98,15 @@ PASS(FunctionSignatureOpts, "function-signature-opts", "Optimize Function Signatures") PASS(ARCSequenceOpts, "arc-sequence-opts", "Optimize sequences of retain/release opts by removing redundant inner " - "retain/release sqeuences") + "retain/release sequences") PASS(ARCLoopOpts, "arc-loop-opts", "Run all arc loop passes") PASS(RedundantLoadElimination, "redundant-load-elim", "Multiple basic block redundant load elimination") PASS(DeadStoreElimination, "dead-store-elim", "Multiple basic block dead store elimination") +PASS(GenericSpecializer, "generic-specializer", + "Specialization of generic functions by static types") PASS(GlobalOpt, "global-opt", "Global variable optimizations") PASS(GlobalPropertyOpt, "global-property-opt", @@ -148,6 +157,8 @@ PASS(MergeCondFails, "merge-cond_fails", "Remove redundant overflow checks") PASS(NoReturnFolding, "noreturn-folding", "Add 'unreachable' after noreturn calls") +PASS(RCIdentityDumper, "rc-id-dumper", + "Dump the RCIdentity of all values in a function") // TODO: It makes no sense to have early inliner, late inliner, and // perf inliner in terms of names. PASS(PerfInliner, "inline", diff --git a/include/swift/SILOptimizer/PassManager/Passes.h b/include/swift/SILOptimizer/PassManager/Passes.h index b8bd24f3b872b..4dc2f5fa1c399 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.h +++ b/include/swift/SILOptimizer/PassManager/Passes.h @@ -1,8 +1,8 @@ -//===-------- Passes.h - Swift Compiler SIL Pass Entrypoints ----*- C++ -*-===// +//===--- Passes.h - Swift Compiler SIL Pass Entrypoints ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h index 029d28cc4e9cb..f2449c927344e 100644 --- a/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h +++ b/include/swift/SILOptimizer/PassManager/PrettyStackTrace.h @@ -1,8 +1,8 @@ -//===--- PrettyStackTrace.h - PrettyStackTrace for Transforms -*- C++ -*---===// +//===--- PrettyStackTrace.h - PrettyStackTrace for Transforms ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/PassManager/Transforms.h b/include/swift/SILOptimizer/PassManager/Transforms.h index f73818a053478..455b3ecb433b0 100644 --- a/include/swift/SILOptimizer/PassManager/Transforms.h +++ b/include/swift/SILOptimizer/PassManager/Transforms.h @@ -1,8 +1,8 @@ -//===-- Transforms.h - Swift Transformations -------------------*- C++ -*-===// +//===--- Transforms.h - Swift Transformations ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -96,6 +96,12 @@ namespace swift { void injectFunction(SILFunction *Func) { F = Func; } + /// \brief Notify the pass manager of a function that needs to be + /// processed by the function passes. + void notifyPassManagerOfFunction(SILFunction *F) { + PM->addFunctionToWorklist(F); + } + protected: SILFunction *getFunction() { return F; } @@ -139,4 +145,3 @@ namespace swift { } // end namespace swift #endif - diff --git a/include/swift/SILOptimizer/Utils/CFG.h b/include/swift/SILOptimizer/Utils/CFG.h index 7a183c5151659..7e86832e00b43 100644 --- a/include/swift/SILOptimizer/Utils/CFG.h +++ b/include/swift/SILOptimizer/Utils/CFG.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/ConstantFolding.h b/include/swift/SILOptimizer/Utils/ConstantFolding.h index a5ad216cc1369..4e90407b7073b 100644 --- a/include/swift/SILOptimizer/Utils/ConstantFolding.h +++ b/include/swift/SILOptimizer/Utils/ConstantFolding.h @@ -1,8 +1,8 @@ -//===-- ConstantFolding.h - Utilities for SIL constant folding --*- C++ -*-===// +//===--- ConstantFolding.h - Utilities for SIL constant folding -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/Devirtualize.h b/include/swift/SILOptimizer/Utils/Devirtualize.h index f4f28e47bb25e..ede616148a8c7 100644 --- a/include/swift/SILOptimizer/Utils/Devirtualize.h +++ b/include/swift/SILOptimizer/Utils/Devirtualize.h @@ -1,8 +1,8 @@ -//===-- Devirtualize.h - Helper for devirtualizing apply --------*- C++ -*-===// +//===--- Devirtualize.h - Helper for devirtualizing apply -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/GenericCloner.h b/include/swift/SILOptimizer/Utils/GenericCloner.h index fe95b30d20425..19950dec2e244 100644 --- a/include/swift/SILOptimizer/Utils/GenericCloner.h +++ b/include/swift/SILOptimizer/Utils/GenericCloner.h @@ -1,8 +1,8 @@ -//===-- GenericCloner.h - Specializes generic functions --------*- C++ -*-===// +//===--- GenericCloner.h - Specializes generic functions -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 9ba55a8b5b91e..9accb8cc504d6 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -1,8 +1,8 @@ -//===-- Generics.h - Utilities for transforming generics --------*- C++ -*-===// +//===--- Generics.h - Utilities for transforming generics -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h index 3982ab6275c76..54a765c68209c 100644 --- a/include/swift/SILOptimizer/Utils/Local.h +++ b/include/swift/SILOptimizer/Utils/Local.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,8 +31,6 @@ class DominanceInfo; using UserTransform = std::function; using ValueBaseUserRange = TransformRange, UserTransform>; -using ValueUserRange = - TransformRange, UserTransform>; inline ValueBaseUserRange makeUserRange( iterator_range R) { @@ -40,11 +38,6 @@ inline ValueBaseUserRange makeUserRange( return makeTransformRange(makeIteratorRange(R.begin(), R.end()), UserTransform(toUser)); } -inline ValueUserRange makeUserRange(iterator_range R) { - auto toUser = [](Operand *O) { return O->getUser(); }; - return makeTransformRange(makeIteratorRange(R.begin(), R.end()), - UserTransform(toUser)); -} /// \brief For each of the given instructions, if they are dead delete them /// along with their dead operands. @@ -111,6 +104,11 @@ Optional castValueToABICompatibleType(SILBuilder *B, SILLocation Loc, bool canCastValueToABICompatibleType(SILModule &M, SILType SrcTy, SILType DestTy); +/// Returns a project_box if it is the next instruction after \p ABI and +/// and has \p ABI as operand. Otherwise it creates a new project_box right +/// after \p ABI and returns it. +ProjectBoxInst *getOrCreateProjectBox(AllocBoxInst *ABI); + /// Replace an apply with an instruction that produces the same value, /// then delete the apply and the instructions that produce its callee /// if possible. @@ -244,7 +242,7 @@ class ValueLifetimeAnalysis { } ValueLifetime computeFromDirectUses() { - return computeFromUserList(makeUserRange(DefValue.getUses()), + return computeFromUserList(makeUserRange(DefValue->getUses()), std::false_type()); } @@ -320,7 +318,7 @@ class BaseThreadingCloner : public SILClonerWithScopes { // A terminator defines no values. Keeping terminators in the AvailVals list // is problematic because terminators get replaced during SSA update. if (!isa(Orig)) - AvailVals.push_back(std::make_pair(Orig, SILValue(Cloned, 0))); + AvailVals.push_back(std::make_pair(Orig, SILValue(Cloned))); } }; @@ -342,9 +340,9 @@ class EdgeThreadingCloner : public BaseThreadingCloner { // Create block arguments. unsigned ArgIdx = 0; for (auto Arg : BI->getArgs()) { - assert(Arg.getType() == DestBB->getBBArg(ArgIdx)->getType() && + assert(Arg->getType() == DestBB->getBBArg(ArgIdx)->getType() && "Types must match"); - auto *BlockArg = EdgeBB->createBBArg(Arg.getType()); + auto *BlockArg = EdgeBB->createBBArg(Arg->getType()); ValueMap[DestBB->getBBArg(ArgIdx)] = SILValue(BlockArg); AvailVals.push_back(std::make_pair(DestBB->getBBArg(ArgIdx), BlockArg)); ++ArgIdx; @@ -436,7 +434,7 @@ class CastOptimizer { SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB); - /// Optimize a cast from a Swift type implementing _ObjectiveCBridgeable + /// Optimize a cast from a Swift type implementing _ObjectiveCBridgeable /// into a bridged ObjC type. SILInstruction * optimizeBridgedSwiftToObjCCast(SILInstruction *Inst, @@ -485,7 +483,7 @@ class CastOptimizer { SILInstruction * optimizeUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *Inst); - /// Check if is is a bridged cast and optimize it. + /// Check if it is a bridged cast and optimize it. /// May change the control flow. SILInstruction * optimizeBridgedCasts(SILInstruction *Inst, @@ -650,6 +648,13 @@ void replaceLoadSequence(SILInstruction *I, /// be reached by calling the function represented by Decl? bool calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl); +/// Hoist the address projection rooted in \p Op to \p InsertBefore. +/// Requires the projected value to dominate the insertion point. +/// +/// Will look through single basic block predecessor arguments. +void hoistAddressProjections(Operand &Op, SILInstruction *InsertBefore, + DominanceInfo *DomTree); + } // end namespace swift #endif diff --git a/include/swift/SILOptimizer/Utils/LoopUtils.h b/include/swift/SILOptimizer/Utils/LoopUtils.h index 0a63e7d96c30e..286ad9b30ea0a 100644 --- a/include/swift/SILOptimizer/Utils/LoopUtils.h +++ b/include/swift/SILOptimizer/Utils/LoopUtils.h @@ -1,8 +1,8 @@ -//===--- LoopUtils.h ------------------------------------------------------===// +//===--- LoopUtils.h --------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/SCCVisitor.h b/include/swift/SILOptimizer/Utils/SCCVisitor.h index 9f984af9ee438..6ab4ee1e638d1 100644 --- a/include/swift/SILOptimizer/Utils/SCCVisitor.h +++ b/include/swift/SILOptimizer/Utils/SCCVisitor.h @@ -1,8 +1,8 @@ -//===------------------- SCCVisitor.h - SIL SCC Visitor -------*- C++ -*---===// +//===--- SCCVisitor.h - SIL SCC Visitor -------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -107,41 +107,38 @@ class SCCVisitor { void getArgsForTerminator(TermInst *Term, SILBasicBlock *SuccBB, int Index, llvm::SmallVectorImpl &Operands) { - switch (Term->getKind()) { - case ValueKind::BranchInst: - return Operands.push_back(cast(Term)->getArg(Index).getDef()); + switch (Term->getTermKind()) { + case TermKind::BranchInst: + return Operands.push_back(cast(Term)->getArg(Index)); - case ValueKind::CondBranchInst: { + case TermKind::CondBranchInst: { auto *CBI = cast(Term); if (SuccBB == CBI->getTrueBB()) - return Operands.push_back(CBI->getTrueArgs()[Index].getDef()); + return Operands.push_back(CBI->getTrueArgs()[Index]); assert(SuccBB == CBI->getFalseBB() && "Block is not a successor of terminator!"); - Operands.push_back(CBI->getFalseArgs()[Index].getDef()); + Operands.push_back(CBI->getFalseArgs()[Index]); return; } - case ValueKind::SwitchEnumInst: - case ValueKind::SwitchEnumAddrInst: - case ValueKind::CheckedCastBranchInst: - case ValueKind::CheckedCastAddrBranchInst: - case ValueKind::DynamicMethodBranchInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastAddrBranchInst: + case TermKind::DynamicMethodBranchInst: assert(Index == 0 && "Expected argument index to always be zero!"); - return Operands.push_back(Term->getOperand(0).getDef()); + return Operands.push_back(Term->getOperand(0)); - case ValueKind::UnreachableInst: - case ValueKind::ReturnInst: - case ValueKind::SwitchValueInst: - case ValueKind::ThrowInst: + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::SwitchValueInst: + case TermKind::ThrowInst: llvm_unreachable("Did not expect terminator that does not have args!"); - case ValueKind::TryApplyInst: + case TermKind::TryApplyInst: for (auto &O : cast(Term)->getAllOperands()) - Operands.push_back(O.get().getDef()); + Operands.push_back(O.get()); return; - - default: - llvm_unreachable("Unhandled terminator kind!"); } } @@ -149,7 +146,7 @@ class SCCVisitor { llvm::SmallVectorImpl &Operands) { if (auto *I = dyn_cast(User)) { for (auto &O : I->getAllOperands()) - Operands.push_back(O.get().getDef()); + Operands.push_back(O.get()); return; } diff --git a/include/swift/SILOptimizer/Utils/SILInliner.h b/include/swift/SILOptimizer/Utils/SILInliner.h index 1ae2ab1146598..ac0495470057b 100644 --- a/include/swift/SILOptimizer/Utils/SILInliner.h +++ b/include/swift/SILOptimizer/Utils/SILInliner.h @@ -1,8 +1,8 @@ -//===--- SILInliner.h - Inlines SIL functions --------------------*- C++ -*-==// +//===--- SILInliner.h - Inlines SIL functions -------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h index 15491c1ce59d2..a16217ea28f89 100644 --- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h +++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h @@ -1,8 +1,8 @@ -//===------ SILSSAUpdater.h - Unstructured SSA Update Tool ------*- C++ -*-===// +//===--- SILSSAUpdater.h - Unstructured SSA Update Tool ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Sema/CodeCompletionTypeChecking.h b/include/swift/Sema/CodeCompletionTypeChecking.h index c0c512df439e3..272b576c7d2d4 100644 --- a/include/swift/Sema/CodeCompletionTypeChecking.h +++ b/include/swift/Sema/CodeCompletionTypeChecking.h @@ -1,8 +1,8 @@ -//===--- CodeCompletionTypeChecking.h - Type-check entry points -*- c++ -*-===// +//===--- CodeCompletionTypeChecking.h - Type-check entry points -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Sema/IterativeTypeChecker.h b/include/swift/Sema/IterativeTypeChecker.h index fbaafa2ea670c..64e53a6ebd214 100644 --- a/include/swift/Sema/IterativeTypeChecker.h +++ b/include/swift/Sema/IterativeTypeChecker.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,7 +33,7 @@ class TypeChecker; /// An iterative type checker that processes type check requests to /// ensure that the AST has the information needed by the client. class IterativeTypeChecker { - /// The underyling (non-iterative) type checker on which this iterative + /// The underlying (non-iterative) type checker on which this iterative /// type checker depends. /// /// Each dependency on the non-iterative type checker potentially diff --git a/include/swift/Sema/SourceLoader.h b/include/swift/Sema/SourceLoader.h index c0b63c6432b4b..edfa15c9ee9e4 100644 --- a/include/swift/Sema/SourceLoader.h +++ b/include/swift/Sema/SourceLoader.h @@ -1,8 +1,8 @@ -//===--- SourceLoader.h - Import .swift files as modules --------*- c++ -*-===// +//===--- SourceLoader.h - Import .swift files as modules --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,16 +25,21 @@ class SourceLoader : public ModuleLoader { private: ASTContext &Ctx; bool SkipBodies; + bool EnableResilience; - explicit SourceLoader(ASTContext &ctx, bool skipBodies, DependencyTracker *tracker) - : ModuleLoader(tracker), Ctx(ctx), SkipBodies(skipBodies) {} + explicit SourceLoader(ASTContext &ctx, + bool skipBodies, + bool enableResilience, + DependencyTracker *tracker) + : ModuleLoader(tracker), Ctx(ctx), + SkipBodies(skipBodies), EnableResilience(enableResilience) {} public: static std::unique_ptr - create(ASTContext &ctx, bool skipBodies, + create(ASTContext &ctx, bool skipBodies, bool enableResilience, DependencyTracker *tracker = nullptr) { return std::unique_ptr{ - new SourceLoader(ctx, skipBodies, tracker) + new SourceLoader(ctx, skipBodies, enableResilience, tracker) }; } diff --git a/include/swift/Sema/TypeCheckRequest.h b/include/swift/Sema/TypeCheckRequest.h index b5767e54cf93b..a4f6957b8ed91 100644 --- a/include/swift/Sema/TypeCheckRequest.h +++ b/include/swift/Sema/TypeCheckRequest.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -114,7 +114,42 @@ class TypeCheckRequest { } #include "swift/Sema/TypeCheckRequestPayloads.def" - + + TypeCheckRequest(const TypeCheckRequest &T) { *this = T; } + + TypeCheckRequest& operator=(const TypeCheckRequest &T) { + TheKind = T.getKind(); + switch (getPayloadKind(TheKind)) { + case PayloadKind::Class: + Payload.Class = T.Payload.Class; + break; + case PayloadKind::Enum: + Payload.Enum = T.Payload.Enum; + break; + case PayloadKind::InheritedClauseEntry: + new (&Payload.InheritedClauseEntry) + std::pair, unsigned>(); + Payload.InheritedClauseEntry = T.Payload.InheritedClauseEntry; + break; + case PayloadKind::Protocol: + Payload.Protocol = T.Payload.Protocol; + break; + case PayloadKind::DeclContextLookup: + new (&Payload.DeclContextLookup) DeclContextLookupInfo(); + Payload.DeclContextLookup = T.Payload.DeclContextLookup; + break; + case PayloadKind::TypeResolution: + new (&Payload.InheritedClauseEntry) + std::tuple(); + Payload.TypeResolution = T.Payload.TypeResolution; + break; + case PayloadKind::TypeDeclResolution: + Payload.TypeDeclResolution = T.Payload.TypeDeclResolution; + break; + } + return *this; + } + /// Determine the kind of type check request. Kind getKind() const { return TheKind; } diff --git a/include/swift/Sema/TypeCheckRequestKinds.def b/include/swift/Sema/TypeCheckRequestKinds.def index e90e6db7fc5b5..e64b81b3bf353 100644 --- a/include/swift/Sema/TypeCheckRequestKinds.def +++ b/include/swift/Sema/TypeCheckRequestKinds.def @@ -1,8 +1,8 @@ -//===-- TypeCheckRequestKinds.def - Type Checking Request Kinds -*- C++ -*-===// +//===--- TypeCheckRequestKinds.def - Type Check Request Kinds ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Sema/TypeCheckRequestPayloads.def b/include/swift/Sema/TypeCheckRequestPayloads.def index ab5444e1375ba..53a7eedf5fe0d 100644 --- a/include/swift/Sema/TypeCheckRequestPayloads.def +++ b/include/swift/Sema/TypeCheckRequestPayloads.def @@ -1,8 +1,8 @@ -//===-- TypeCheckRequestPayloads.def - Type Checking Payloads ---*- C++ -*-===// +//===--- TypeCheckRequestPayloads.def - Type Checking Payloads --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Serialization/BCReadingExtras.h b/include/swift/Serialization/BCReadingExtras.h index b4dca346de4be..3607ddd7b86db 100644 --- a/include/swift/Serialization/BCReadingExtras.h +++ b/include/swift/Serialization/BCReadingExtras.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Serialization/DeclTypeRecordNodes.def b/include/swift/Serialization/DeclTypeRecordNodes.def index bfcec568401d1..ec28ac158de41 100644 --- a/include/swift/Serialization/DeclTypeRecordNodes.def +++ b/include/swift/Serialization/DeclTypeRecordNodes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -149,6 +149,8 @@ PATTERN(NOMINAL_TYPE) TRAILING_INFO(NOMINAL_TYPE_PATTERN_ELT) PATTERN(VAR) +OTHER(PARAMETERLIST, 226) +OTHER(PARAMETERLIST_ELT, 227) OTHER(FOREIGN_ERROR_CONVENTION, 228) OTHER(DECL_CONTEXT, 229) OTHER(XREF_TYPE_PATH_PIECE, 230) @@ -171,7 +173,7 @@ TRAILING_INFO(LAST_GENERIC_REQUIREMENT) OTHER(LOCAL_DISCRIMINATOR, 248) OTHER(PRIVATE_DISCRIMINATOR, 249) -OTHER(NO_CONFORMANCE, 250) +OTHER(ABSTRACT_PROTOCOL_CONFORMANCE, 250) OTHER(NORMAL_PROTOCOL_CONFORMANCE, 251) OTHER(SPECIALIZED_PROTOCOL_CONFORMANCE, 252) OTHER(INHERITED_PROTOCOL_CONFORMANCE, 253) diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h index 601b4c6063db0..fbf4181f38bca 100644 --- a/include/swift/Serialization/ModuleFile.h +++ b/include/swift/Serialization/ModuleFile.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -341,7 +341,7 @@ class ModuleFile : public LazyMemberLoader { template T *createDecl(Args &&... args); - /// Constructs an new module and validates it. + /// Constructs a new module and validates it. ModuleFile(std::unique_ptr moduleInputBuffer, std::unique_ptr moduleDocInputBuffer, bool isFramework, serialization::ExtendedValidationInfo *extInfo); @@ -408,6 +408,8 @@ class ModuleFile : public LazyMemberLoader { /// If the record at the cursor is not a pattern, returns null. Pattern *maybeReadPattern(); + ParameterList *readParameterList(); + GenericParamList *maybeGetOrReadGenericParams(serialization::DeclID contextID, DeclContext *DC, llvm::BitstreamCursor &Cursor); @@ -519,7 +521,7 @@ class ModuleFile : public LazyMemberLoader { /// Note that this may cause other decls to load as well. void loadExtensions(NominalTypeDecl *nominal); - /// \brief Load the methods within the given class that that produce + /// \brief Load the methods within the given class that produce /// Objective-C class or instance methods with the given selector. /// /// \param classDecl The class in which we are searching for @objc methods. @@ -551,6 +553,11 @@ class ModuleFile : public LazyMemberLoader { DeclName name, SmallVectorImpl &results); + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results); + /// Reports all link-time dependencies. void collectLinkLibraries(Module::LinkLibraryCallback callback) const; @@ -589,12 +596,11 @@ class ModuleFile : public LazyMemberLoader { void verify() const; virtual void loadAllMembers(Decl *D, - uint64_t contextData, - bool *ignored) override; + uint64_t contextData) override; virtual void loadAllConformances(const Decl *D, uint64_t contextData, - SmallVectorImpl &Conforms) override; + SmallVectorImpl &Conforms) override; virtual TypeLoc loadAssociatedTypeDefault(const AssociatedTypeDecl *ATD, uint64_t contextData) override; @@ -652,9 +658,7 @@ class ModuleFile : public LazyMemberLoader { Optional maybeReadSubstitution(llvm::BitstreamCursor &Cursor); /// Recursively reads a protocol conformance from the given cursor. - /// - /// Note that a null conformance is valid for archetypes. - ProtocolConformance *readConformance(llvm::BitstreamCursor &Cursor); + ProtocolConformanceRef readConformance(llvm::BitstreamCursor &Cursor); /// Read the given normal conformance from the current module file. NormalProtocolConformance * diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 69e91a4c81d29..7193dc4d266cd 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,8 +50,9 @@ const uint16_t VERSION_MAJOR = 0; /// When the format changes IN ANY WAY, this number should be incremented. /// To ensure that two separate changes don't silently get merged into one /// in source control, you should also update the comment to briefly -/// describe what change you made. -const uint16_t VERSION_MINOR = 223; // Last change: SIL @inout_aliasable +/// describe what change you made. The content of this comment isn't important; +/// it just ensures a conflict if two people change the module format. +const uint16_t VERSION_MINOR = 238; // SILValue changes using DeclID = Fixnum<31>; using DeclIDField = BCFixed<31>; @@ -232,7 +233,8 @@ static inline OperatorKind getStableFixity(DeclKind kind) { enum GenericRequirementKind : uint8_t { Conformance = 0, SameType, - WitnessMarker + WitnessMarker, + Superclass }; using GenericRequirementKindField = BCFixed<2>; @@ -266,8 +268,11 @@ enum class DefaultArgumentKind : uint8_t { Function, Inherited, DSOHandle, + Nil, + EmptyArray, + EmptyDictionary, }; -using DefaultArgumentField = BCFixed<3>; +using DefaultArgumentField = BCFixed<4>; // These IDs must \em not be renumbered or reordered without incrementing // VERSION_MAJOR. @@ -434,7 +439,8 @@ namespace options_block { SDK_PATH = 1, XCC, IS_SIB, - IS_TESTABLE + IS_TESTABLE, + IS_RESILIENT }; using SDKPathLayout = BCRecordLayout< @@ -455,6 +461,10 @@ namespace options_block { using IsTestableLayout = BCRecordLayout< IS_TESTABLE >; + + using IsResilientLayout = BCRecordLayout< + IS_RESILIENT + >; } /// The record types within the input block. @@ -657,7 +667,6 @@ namespace decls_block { using BoundGenericSubstitutionLayout = BCRecordLayout< BOUND_GENERIC_SUBSTITUTION, - TypeIDField, // archetype TypeIDField, // replacement BCVBR<5> // Trailed by protocol conformance info (if any) @@ -990,6 +999,17 @@ namespace decls_block { // Trailed by a pattern for self. >; + using ParameterListLayout = BCRecordLayout< + PARAMETERLIST, + BCVBR<5> // numparams + >; + + using ParameterListEltLayout = BCRecordLayout< + PARAMETERLIST_ELT, + DeclIDField, // ParamDecl + BCFixed<1>, // isVariadic? + DefaultArgumentField // default argument + >; using ParenPatternLayout = BCRecordLayout< PAREN_PATTERN, @@ -1007,9 +1027,7 @@ namespace decls_block { using TuplePatternEltLayout = BCRecordLayout< TUPLE_PATTERN_ELT, - IdentifierIDField, // label - BCFixed<1>, // has ellipsis? - DefaultArgumentField // default argument + IdentifierIDField // label // The element pattern trails the record. >; @@ -1102,10 +1120,10 @@ namespace decls_block { BCVBR<2> // context-scoped discriminator counter >; - /// A placeholder for lack of conformance information. Conformances are - /// indexed, so simply omitting one would be incorrect. - using NoConformanceLayout = BCRecordLayout< - NO_CONFORMANCE + /// A placeholder for lack of concrete conformance information. + using AbstractProtocolConformanceLayout = BCRecordLayout< + ABSTRACT_PROTOCOL_CONFORMANCE, + DeclIDField // the protocol >; using NormalProtocolConformanceLayout = BCRecordLayout< @@ -1117,15 +1135,15 @@ namespace decls_block { BCVBR<5>, // inherited conformances count BCVBR<5>, // defaulted definitions count BCArray - // The array contains value-value-substitutionCount triplets, + // The array contains archetype-value pairs, // then type declarations, then defaulted definitions. // Inherited conformances follow, then the substitution records for the - // values and then types. + // associated types. >; using SpecializedProtocolConformanceLayout = BCRecordLayout< SPECIALIZED_PROTOCOL_CONFORMANCE, - TypeIDField, // conforming type + TypeIDField, // conforming type BCVBR<5> // # of substitutions for the conformance // followed by substitution records for the conformance >; @@ -1331,6 +1349,14 @@ namespace decls_block { BCArray >; + using Swift3MigrationDeclAttrLayout = BCRecordLayout< + Swift3Migration_DECL_ATTR, + BCFixed<1>, // implicit flag + BCVBR<5>, // number of bytes in rename string + BCVBR<5>, // number of bytes in message string + BCBlob // rename, followed by message + >; + using WarnUnusedResultDeclAttrLayout = BCRecordLayout< WarnUnusedResult_DECL_ATTR, BCFixed<1>, // implicit flag diff --git a/include/swift/Serialization/SerializationOptions.h b/include/swift/Serialization/SerializationOptions.h index 8321f273aaa98..c96c280ea429c 100644 --- a/include/swift/Serialization/SerializationOptions.h +++ b/include/swift/Serialization/SerializationOptions.h @@ -1,8 +1,8 @@ -//===--- SerializationOptions.h - Control swiftmodule emission --*- c++ -*-===// +//===--- SerializationOptions.h - Control swiftmodule emission --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index a97a130bdecae..174e2c4109129 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -1,8 +1,8 @@ -//===--- SerializedModuleLoader.h - Import Swift modules --------*- c++ -*-===// +//===--- SerializedModuleLoader.h - Import Swift modules --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -131,6 +131,11 @@ class SerializedASTFile final : public LoadedFile { lookupClassMember(Module::AccessPathTy accessPath, DeclName name, SmallVectorImpl &decls) const override; + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + Optional getCommentForDecl(const Decl *D) const override; virtual void getTopLevelDecls(SmallVectorImpl &results) const override; diff --git a/include/swift/Serialization/SerializedSILLoader.h b/include/swift/Serialization/SerializedSILLoader.h index 190b48825d3b6..77781da5da405 100644 --- a/include/swift/Serialization/SerializedSILLoader.h +++ b/include/swift/Serialization/SerializedSILLoader.h @@ -1,8 +1,8 @@ -//===--- SerializedSILLoader.h - Handle SIL section in modules --*- c++ -*-===// +//===--- SerializedSILLoader.h - Handle SIL section in modules --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -43,7 +43,7 @@ class SerializedSILLoader { /// Observe that we successfully deserialized a function body. virtual void didDeserializeFunctionBody(ModuleDecl *M, SILFunction *fn) {} - /// Oberve that we successfully deserialized a witness table's entries. + /// Observe that we successfully deserialized a witness table's entries. virtual void didDeserializeWitnessTableEntries(ModuleDecl *M, SILWitnessTable *wt) {} diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index 3869ab2492e33..4108837c81684 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -1,8 +1,8 @@ -//===--- Validation.h - Validation / errors for serialization ---*- c++ -*-===// +//===--- Validation.h - Validation / errors for serialization ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -84,6 +84,7 @@ namespace serialization { struct { unsigned IsSIB : 1; unsigned IsTestable : 1; + unsigned IsResilient : 1; } Bits; public: ExtendedValidationInfo() : Bits() {} @@ -109,6 +110,10 @@ namespace serialization { void setIsTestable(bool val) { Bits.IsTestable = val; } + bool isResilient() const { return Bits.IsResilient; } + void setIsResilient(bool val) { + Bits.IsResilient = val; + } }; /// Returns info about the serialized AST in the given data. diff --git a/include/swift/Strings.h b/include/swift/Strings.h index b377513b3b73e..6beae5727b808 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 9b5b4cd8e6736..58a72e5ca1bca 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -123,7 +123,8 @@ namespace swift { const SourceManager &SM, unsigned BufferID, unsigned Offset = 0, unsigned EndOffset = 0, bool KeepComments = true, - bool TokenizeInterpolatedString = true); + bool TokenizeInterpolatedString = true, + ArrayRef SplitTokens = ArrayRef()); /// Once parsing is complete, this walks the AST to resolve imports, record /// operators, and do other top-level validation. diff --git a/include/swift/SwiftDemangle/MangleHack.h b/include/swift/SwiftDemangle/MangleHack.h index a0d447546ed21..79c6eb00120aa 100644 --- a/include/swift/SwiftDemangle/MangleHack.h +++ b/include/swift/SwiftDemangle/MangleHack.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/include/swift/SwiftDemangle/SwiftDemangle.h b/include/swift/SwiftDemangle/SwiftDemangle.h index c3c0d71d1e0c2..166ce942221b3 100644 --- a/include/swift/SwiftDemangle/SwiftDemangle.h +++ b/include/swift/SwiftDemangle/SwiftDemangle.h @@ -1,8 +1,8 @@ -//===--- SwiftDemangle.h - Public demangling interface -----------*- C -*--===// +//===--- SwiftDemangle.h - Public demangling interface ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 111d5b31cb611..a54f86243a700 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,6 +37,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSwitch.h" #include #include @@ -1181,7 +1182,7 @@ bool ASTContext::hasArrayLiteralIntrinsics(LazyResolver *resolver) const { && getDeallocateUninitializedArray(resolver); } -void ASTContext::addedExternalDecl(Decl *decl) { +void ASTContext::addExternalDecl(Decl *decl) { ExternalDefinitions.insert(decl); } @@ -1209,7 +1210,8 @@ ASTContext::createTrivialSubstitutions(BoundGenericType *BGT, assert(Params.size() == 1); auto Param = Params[0]; assert(Param->getArchetype() && "Not type-checked yet"); - Substitution Subst(Param->getArchetype(), BGT->getGenericArgs()[0], {}); + (void) Param; + Substitution Subst(BGT->getGenericArgs()[0], {}); auto Substitutions = AllocateCopy(llvm::makeArrayRef(Subst)); auto arena = getArena(BGT->getRecursiveProperties()); Impl.getArena(arena).BoundGenericSubstitutions @@ -1353,7 +1355,7 @@ Module *ASTContext::getLoadedModule(Identifier ModuleName) const { return LoadedModules.lookup(ModuleName); } -void ASTContext::getVisibleTopLevelClangeModules( +void ASTContext::getVisibleTopLevelClangModules( SmallVectorImpl &Modules) const { getClangModuleLoader()->getClangPreprocessor().getHeaderSearchInfo(). collectAllModules(Modules); @@ -2276,6 +2278,54 @@ bool ASTContext::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) { return anyDiagnosed; } +Optional swift::getKnownFoundationEntity(StringRef name){ + return llvm::StringSwitch>(name) +#define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name) +#include "swift/AST/KnownFoundationEntities.def" + .Default(None); +} + +bool swift::nameConflictsWithStandardLibrary(KnownFoundationEntity entity) { + switch (entity) { + case KnownFoundationEntity::NSArray: + case KnownFoundationEntity::NSDictionary: + case KnownFoundationEntity::NSInteger: + case KnownFoundationEntity::NSRange: + case KnownFoundationEntity::NSSet: + case KnownFoundationEntity::NSString: + return true; + + case KnownFoundationEntity::NSCopying: + case KnownFoundationEntity::NSError: + case KnownFoundationEntity::NSErrorPointer: + case KnownFoundationEntity::NSNumber: + case KnownFoundationEntity::NSObject: + case KnownFoundationEntity::NSStringEncoding: + case KnownFoundationEntity::NSUInteger: + case KnownFoundationEntity::NSURL: + case KnownFoundationEntity::NSZone: + return false; + } +} + +StringRef ASTContext::getSwiftName(KnownFoundationEntity kind) { + StringRef objcName; + switch (kind) { +#define FOUNDATION_ENTITY(Name) case KnownFoundationEntity::Name: \ + objcName = #Name; \ + break; +#include "swift/AST/KnownFoundationEntities.def" + } + + // If we're omitting needless words and the name won't conflict with + // something in the standard library, strip the prefix off the Swift + // name. + if (LangOpts.OmitNeedlessWords && !nameConflictsWithStandardLibrary(kind)) + return objcName.substr(2); + + return objcName; +} + void ASTContext::dumpArchetypeContext(ArchetypeType *archetype, unsigned indent) const { dumpArchetypeContext(archetype, llvm::errs(), indent); @@ -2343,7 +2393,8 @@ void TupleType::Profile(llvm::FoldingSetNodeID &ID, ID.AddInteger(Fields.size()); for (const TupleTypeElt &Elt : Fields) { ID.AddPointer(Elt.NameAndVariadic.getOpaqueValue()); - ID.AddPointer(Elt.TyAndDefaultArg.getOpaqueValue()); + ID.AddPointer(Elt.getType().getPointer()); + ID.AddInteger(static_cast(Elt.getDefaultArgKind())); } } @@ -3163,9 +3214,9 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, const ASTContext &Ctx) LValueType *LValueType::get(Type objectTy) { assert(!objectTy->is() && - "can not have ErrorType wrapped inside LValueType"); + "cannot have ErrorType wrapped inside LValueType"); assert(!objectTy->is() && !objectTy->is() && - "can not have 'inout' or @lvalue wrapped inside an @lvalue"); + "cannot have 'inout' or @lvalue wrapped inside an @lvalue"); auto properties = objectTy->getRecursiveProperties() | RecursiveTypeProperties::IsLValue; @@ -3183,9 +3234,9 @@ LValueType *LValueType::get(Type objectTy) { InOutType *InOutType::get(Type objectTy) { assert(!objectTy->is() && - "can not have ErrorType wrapped inside InOutType"); + "cannot have ErrorType wrapped inside InOutType"); assert(!objectTy->is() && !objectTy->is() && - "can not have 'inout' or @lvalue wrapped inside an 'inout'"); + "cannot have 'inout' or @lvalue wrapped inside an 'inout'"); auto properties = objectTy->getRecursiveProperties() | RecursiveTypeProperties::HasInOut; @@ -3410,8 +3461,8 @@ void DeclName::CompoundDeclName::Profile(llvm::FoldingSetNodeID &id, id.AddPointer(arg.get()); } -DeclName::DeclName(ASTContext &C, Identifier baseName, - ArrayRef argumentNames) { +void DeclName::initialize(ASTContext &C, Identifier baseName, + ArrayRef argumentNames) { if (argumentNames.size() == 0) { SimpleOrCompound = IdentifierAndCompound(baseName, true); return; @@ -3437,6 +3488,17 @@ DeclName::DeclName(ASTContext &C, Identifier baseName, C.Impl.CompoundNames.InsertNode(compoundName, insert); } +/// Build a compound value name given a base name and a set of argument names +/// extracted from a parameter list. +DeclName::DeclName(ASTContext &C, Identifier baseName, + ParameterList *paramList) { + SmallVector names; + + for (auto P : *paramList) + names.push_back(P->getArgumentName()); + initialize(C, baseName, names); +} + Optional ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, LazyResolver *resolver) const { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index e3bddad92fff3..e89527e91a10e 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1,8 +1,8 @@ -//===--- ASTDumper.cpp - Swift Language AST Dumper-------------------------===// +//===--- ASTDumper.cpp - Swift Language AST Dumper ------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ForeignErrorConvention.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/STLExtras.h" #include "llvm/ADT/APFloat.h" @@ -43,6 +44,42 @@ DEF_COLOR(TypeField, CYAN) #undef DEF_COLOR +namespace { + /// RAII object that prints with the given color, if color is supported on the + /// given stream. + class PrintWithColorRAII { + raw_ostream &OS; + bool ShowColors; + + public: + PrintWithColorRAII(raw_ostream &os, llvm::raw_ostream::Colors color) + : OS(os), ShowColors(false) + { + if (&os == &llvm::errs() || &os == &llvm::outs()) + ShowColors = llvm::errs().has_colors() && llvm::outs().has_colors(); + + if (ShowColors) { + if (auto str = llvm::sys::Process::OutputColor(color, false, false)) { + OS << str; + } + } + } + + ~PrintWithColorRAII() { + if (ShowColors) { + OS << llvm::sys::Process::ResetColor(); + } + } + + template + friend raw_ostream &operator<<(PrintWithColorRAII &&printer, + const T &value){ + printer.OS << value; + return printer.OS; + } + }; +} // end anonymous namespace + //===----------------------------------------------------------------------===// // Generic param list printing. //===----------------------------------------------------------------------===// @@ -52,6 +89,20 @@ void RequirementRepr::dump() const { llvm::errs() << "\n"; } +Optional> +RequirementRepr::getAsAnalyzedWrittenString() const { + if(AsWrittenString.empty()) + return None; + auto Pair = AsWrittenString.split("=="); + auto Kind = RequirementReprKind::SameType; + if (Pair.second.empty()) { + Pair = AsWrittenString.split(":"); + Kind = RequirementReprKind::TypeConstraint; + } + assert(!Pair.second.empty() && "cannot get second type."); + return std::make_tuple(Pair.first.trim(), Pair.second.trim(), Kind); +} + void RequirementRepr::printImpl(raw_ostream &out, bool AsWritten) const { auto printTy = [&](const TypeLoc &TyLoc) { if (AsWritten && TyLoc.getTypeRepr()) { @@ -62,22 +113,17 @@ void RequirementRepr::printImpl(raw_ostream &out, bool AsWritten) const { }; switch (getKind()) { - case RequirementKind::Conformance: + case RequirementReprKind::TypeConstraint: printTy(getSubjectLoc()); out << " : "; printTy(getConstraintLoc()); break; - case RequirementKind::SameType: + case RequirementReprKind::SameType: printTy(getFirstTypeLoc()); out << " == "; printTy(getSecondTypeLoc()); break; - - case RequirementKind::WitnessMarker: - out << "witness marker for "; - printTy(getFirstTypeLoc()); - break; } } @@ -235,12 +281,6 @@ namespace { for (auto &elt : P->getElements()) { OS << '\n'; printRec(elt.getPattern()); - if (elt.hasEllipsis()) - OS << " ellipsis"; - if (elt.getInit()) { - OS << '\n'; - printRec(elt.getInit()->getExpr()); - } } OS << ')'; } @@ -339,6 +379,15 @@ namespace { void printRec(Pattern *P) { PrintPattern(OS, Indent+2).visit(P); } void printRec(TypeRepr *T); + // Print a field with a value. + template + raw_ostream &printField(StringRef name, const T &value) { + OS << " "; + PrintWithColorRAII(OS, TypeFieldColor) << name; + OS << "=" << value; + return OS; + } + void printCommon(Decl *D, const char *Name, llvm::Optional Color = llvm::Optional()) { @@ -433,7 +482,7 @@ namespace { OS << ")"; } - void printDeclName(ValueDecl *D) { + void printDeclName(const ValueDecl *D) { if (D->getFullName()) OS << '\"' << D->getFullName() << '\"'; else @@ -471,6 +520,10 @@ namespace { OS << " default="; defaultDef.print(OS); } + + if (decl->isRecursive()) + OS << " <>"; + OS << ")"; } @@ -613,15 +666,8 @@ namespace { } } - void visitParamDecl(ParamDecl *VD) { - printCommon(VD, "param_decl"); - if (!VD->isLet()) - OS << " var"; - if (VD->getName() != VD->getArgumentName()) { - OS << " argument_name="; - printName(OS, VD->getArgumentName()); - } - OS << ')'; + void visitParamDecl(ParamDecl *PD) { + printParameter(PD); } void visitEnumCaseDecl(EnumCaseDecl *ECD) { @@ -732,27 +778,88 @@ namespace { OS << ",resulttype=" << fec->getResultType().getString(); } } + + void printParameter(const ParamDecl *P) { + OS.indent(Indent) << "(parameter "; + printDeclName(P); + if (!P->getArgumentName().empty()) + OS << " apiName=" << P->getArgumentName(); + + OS << " type="; + if (P->hasType()) { + OS << '\''; + P->getType().print(OS); + OS << '\''; + } else + OS << ""; + + if (!P->isLet()) + OS << " mutable"; + + if (P->isVariadic()) + OS << " variadic"; - void printPatterns(StringRef Text, ArrayRef Pats) { - if (Pats.empty()) - return; - if (!Text.empty()) { - OS << '\n'; - Indent += 2; - OS.indent(Indent) << '(' << Text; + switch (P->getDefaultArgumentKind()) { + case DefaultArgumentKind::None: break; + case DefaultArgumentKind::Column: + printField("default_arg", "__COLUMN__"); + break; + case DefaultArgumentKind::DSOHandle: + printField("default_arg", "__DSO_HANDLE__"); + break; + case DefaultArgumentKind::File: + printField("default_arg", "__FILE__"); + break; + case DefaultArgumentKind::Function: + printField("default_arg", "__FUNCTION__"); + break; + case DefaultArgumentKind::Inherited: + printField("default_arg", "inherited"); + break; + case DefaultArgumentKind::Line: + printField("default_arg", "__LINE__"); + break; + case DefaultArgumentKind::Nil: + printField("default_arg", "nil"); + break; + case DefaultArgumentKind::EmptyArray: + printField("default_arg", "[]"); + break; + case DefaultArgumentKind::EmptyDictionary: + printField("default_arg", "[:]"); + break; + case DefaultArgumentKind::Normal: + printField("default_arg", "normal"); + break; } - for (auto P : Pats) { - OS << '\n'; - printRec(P); + + if (auto init = P->getDefaultValue()) { + OS << " expression=\n"; + printRec(init->getExpr()); } - if (!Text.empty()) { - OS << ')'; - Indent -= 2; + + OS << ')'; + } + + + void printParameterList(const ParameterList *params) { + OS.indent(Indent) << "(parameter_list"; + Indent += 2; + for (auto P : *params) { + OS << '\n'; + printParameter(P); } + OS << ')'; + Indent -= 2; } void printAbstractFunctionDecl(AbstractFunctionDecl *D) { - printPatterns("body_params", D->getBodyParamPatterns()); + for (auto pl : D->getParameterLists()) { + OS << '\n'; + Indent += 2; + printParameterList(pl); + Indent -= 2; + } if (auto FD = dyn_cast(D)) { if (FD->getBodyResultTypeLoc().getTypeRepr()) { OS << '\n'; @@ -859,7 +966,7 @@ namespace { OS.indent(Indent) << "(#if_decl\n"; Indent += 2; for (auto &Clause : ICD->getClauses()) { - OS.indent(Indent) << (Clause.Cond ? "(#if:\n" : "#else"); + OS.indent(Indent) << (Clause.Cond ? "(#if:\n" : "\n(#else:\n"); if (Clause.Cond) printRec(Clause.Cond); @@ -867,6 +974,8 @@ namespace { OS << '\n'; printRec(D); } + + OS << ')'; } Indent -= 2; @@ -904,6 +1013,26 @@ namespace { }; } // end anonymous namespace. +void ParameterList::dump() const { + dump(llvm::errs(), 0); +} + +void ParameterList::dump(raw_ostream &OS, unsigned Indent) const { + llvm::Optional> X; + + // Make sure to print type variables if we can get to ASTContext. + if (size() != 0 && get(0)) { + auto &ctx = get(0)->getASTContext(); + X.emplace(llvm::SaveAndRestore(ctx.LangOpts.DebugConstraintSolver, + true)); + } + + PrintDecl(OS, Indent).printParameterList(this); + llvm::errs() << '\n'; +} + + + void Decl::dump() const { dump(llvm::errs(), 0); } @@ -913,7 +1042,7 @@ void Decl::dump(raw_ostream &OS, unsigned Indent) const { llvm::SaveAndRestore X(getASTContext().LangOpts.DebugConstraintSolver, true); PrintDecl(OS, Indent).visit(const_cast(this)); - llvm::errs() << '\n'; + OS << '\n'; } /// Print the given declaration context (with its parents). @@ -986,6 +1115,9 @@ static void printContext(raw_ostream &os, DeclContext *dc) { os << "deinit"; break; } + case DeclContextKind::SubscriptDecl: + os << "subscript decl"; + break; } } @@ -1489,7 +1621,7 @@ class PrintExpr : public ExprVisitor { void visitObjectLiteralExpr(ObjectLiteralExpr *E) { printCommon(E, "object_literal") - << " name=" << E->getName().str(); + << " name=" << E->getName(); OS << '\n'; printRec(E->getArg()); } @@ -1531,14 +1663,9 @@ class PrintExpr : public ExprVisitor { E->getDeclRef().dump(OS); OS << ')'; } - void visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *E) { - printCommon(E, "unresolved_constructor") << '\n'; - printRec(E->getSubExpr()); - OS << ')'; - } void visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *E) { printCommon(E, "overloaded_decl_ref_expr") - << " name=" << E->getDecls()[0]->getName().str() + << " name=" << E->getDecls()[0]->getName() << " #decls=" << E->getDecls().size() << " specialized=" << (E->isSpecialized()? "yes" : "no"); @@ -1551,7 +1678,7 @@ class PrintExpr : public ExprVisitor { } void visitOverloadedMemberRefExpr(OverloadedMemberRefExpr *E) { printCommon(E, "overloaded_member_ref_expr") - << " name=" << E->getDecls()[0]->getName().str() + << " name=" << E->getDecls()[0]->getName() << " #decls=" << E->getDecls().size() << "\n"; printRec(E->getBase()); for (ValueDecl *D : E->getDecls()) { @@ -1685,16 +1812,7 @@ class PrintExpr : public ExprVisitor { } void visitUnresolvedDotExpr(UnresolvedDotExpr *E) { printCommon(E, "unresolved_dot_expr") - << " field '" << E->getName().str() << "'"; - if (E->getBase()) { - OS << '\n'; - printRec(E->getBase()); - } - OS << ')'; - } - void visitUnresolvedSelectorExpr(UnresolvedSelectorExpr *E) { - printCommon(E, "unresolved_selector_expr") - << " selector '" << E->getName() << "'"; + << " field '" << E->getName() << "'"; if (E->getBase()) { OS << '\n'; printRec(E->getBase()); @@ -1871,6 +1989,7 @@ class PrintExpr : public ExprVisitor { void visitCaptureListExpr(CaptureListExpr *E) { printCommon(E, "capture_list"); for (auto capture : E->getCaptureList()) { + OS << '\n'; Indent += 2; printRec(capture.Var); printRec(capture.Init); @@ -1887,24 +2006,39 @@ class PrintExpr : public ExprVisitor { OS << " "; E->getCaptureInfo().print(OS); } + return OS; } - void visitClosureExpr(ClosureExpr *expr) { - printClosure(expr, "closure_expr"); - if (expr->hasSingleExpressionBody()) + void visitClosureExpr(ClosureExpr *E) { + printClosure(E, "closure_expr"); + if (E->hasSingleExpressionBody()) OS << " single-expression"; + if (E->isVoidConversionClosure()) + OS << " void-conversion"; + + if (E->getParameters()) { + OS << '\n'; + PrintDecl(OS, Indent+2).printParameterList(E->getParameters()); + } + OS << '\n'; - - if (expr->hasSingleExpressionBody()) { - printRec(expr->getSingleExpressionBody()); + if (E->hasSingleExpressionBody()) { + printRec(E->getSingleExpressionBody()); } else { - printRec(expr->getBody()); + printRec(E->getBody()); } OS << ')'; } void visitAutoClosureExpr(AutoClosureExpr *E) { printClosure(E, "autoclosure_expr") << '\n'; + + if (E->getParameters()) { + OS << '\n'; + PrintDecl(OS, Indent+2).printParameterList(E->getParameters()); + } + + OS << '\n'; printRec(E->getSingleExpressionBody()); OS << ')'; } @@ -1964,9 +2098,9 @@ class PrintExpr : public ExprVisitor { printCommon(E, name) << ' '; if (auto checkedCast = dyn_cast(E)) OS << getCheckedCastKindName(checkedCast->getCastKind()) << ' '; - OS << "writtenType="; + OS << "writtenType='"; E->getCastTypeLoc().getType().print(OS); - OS << '\n'; + OS << "'\n"; printRec(E->getSubExpr()); OS << ')'; } @@ -2050,6 +2184,16 @@ class PrintExpr : public ExprVisitor { } OS << ')'; } + void visitObjCSelectorExpr(ObjCSelectorExpr *E) { + printCommon(E, "objc_selector_expr") << " decl="; + if (auto method = E->getMethod()) + method->dumpRef(OS); + else + OS << ""; + OS << '\n'; + printRec(E->getSubExpr()); + OS << ')'; + } }; } // end anonymous namespace. @@ -2168,10 +2312,6 @@ class PrintTypeRepr : public TypeReprVisitor { void visitArrayTypeRepr(ArrayTypeRepr *T) { printCommon(T, "type_array") << '\n'; printRec(T->getBase()); - if (T->getSize()) { - OS << '\n'; - printRec(T->getSize()->getExpr()); - } OS << ')'; } @@ -2195,7 +2335,7 @@ class PrintTypeRepr : public TypeReprVisitor { void visitNamedTypeRepr(NamedTypeRepr *T) { printCommon(T, "type_named"); if (T->hasName()) - OS << " id='" << T->getName(); + OS << " id=" << T->getName(); if (T->getTypeRepr()) { OS << '\n'; printRec(T->getTypeRepr()); @@ -2253,17 +2393,27 @@ void Substitution::dump() const { if (!Conformance.size()) return; os << '['; - for (const auto *c : Conformance) { - os << ' '; - if (c) { - c->printName(os); + bool first = true; + for (auto &c : Conformance) { + if (first) { + first = false; } else { - os << "nullptr"; + os << ' '; } + c.dump(); } os << " ]"; } +void ProtocolConformanceRef::dump() const { + llvm::raw_ostream &os = llvm::errs(); + if (isConcrete()) { + getConcrete()->printName(os); + } else { + os << "abstract:" << getAbstract()->getName(); + } +} + void swift::dump(const ArrayRef &subs) { unsigned i = 0; for (const auto &s : subs) { @@ -2284,40 +2434,6 @@ void ProtocolConformance::dump() const { //===----------------------------------------------------------------------===// namespace { - /// RAII object that prints with the given color, if color is supported on the - /// given stream. - class PrintWithColorRAII { - raw_ostream &OS; - bool ShowColors; - - public: - PrintWithColorRAII(raw_ostream &os, llvm::raw_ostream::Colors color) - : OS(os), ShowColors(false) - { - if (&os == &llvm::errs() || &os == &llvm::outs()) - ShowColors = llvm::errs().has_colors() && llvm::outs().has_colors(); - - if (ShowColors) { - if (auto str = llvm::sys::Process::OutputColor(color, false, false)) { - OS << str; - } - } - } - - ~PrintWithColorRAII() { - if (ShowColors) { - OS << llvm::sys::Process::ResetColor(); - } - } - - template - friend raw_ostream &operator<<(PrintWithColorRAII &&printer, - const T &value){ - printer.OS << value; - return printer.OS; - } - }; - class PrintType : public TypeVisitor { raw_ostream &OS; unsigned Indent; @@ -2441,31 +2557,43 @@ namespace { break; case DefaultArgumentKind::Column: - printFlag("default_arg", "__COLUMN__"); + printField("default_arg", "__COLUMN__"); break; case DefaultArgumentKind::DSOHandle: - printFlag("default_arg", "__DSO_HANDLE__"); + printField("default_arg", "__DSO_HANDLE__"); break; case DefaultArgumentKind::File: - printFlag("default_arg", "__FILE__"); + printField("default_arg", "__FILE__"); break; case DefaultArgumentKind::Function: - printFlag("default_arg", "__FUNCTION__"); + printField("default_arg", "__FUNCTION__"); break; case DefaultArgumentKind::Inherited: - printFlag("default_arg", "inherited"); + printField("default_arg", "inherited"); break; case DefaultArgumentKind::Line: - printFlag("default_arg", "__LINE__"); + printField("default_arg", "__LINE__"); + break; + + case DefaultArgumentKind::Nil: + printField("default_arg", "nil"); + break; + + case DefaultArgumentKind::EmptyArray: + printField("default_arg", "[]"); + break; + + case DefaultArgumentKind::EmptyDictionary: + printField("default_arg", "[:]"); break; case DefaultArgumentKind::Normal: - printFlag("default_arg", "normal"); + printField("default_arg", "normal"); break; } diff --git a/lib/AST/ASTNode.cpp b/lib/AST/ASTNode.cpp index 55ee0acabe697..55f5d34134394 100644 --- a/lib/AST/ASTNode.cpp +++ b/lib/AST/ASTNode.cpp @@ -1,8 +1,8 @@ -//===--- ASTNode.cpp - Swift Language ASTs ----------------------*- C++ -*-===// +//===--- ASTNode.cpp - Swift Language ASTs --------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 0fc236e6d08bd..70a7513a657ef 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -1,8 +1,8 @@ -//===--- ASTPrinter.cpp - Swift Language AST Printer---------------------===// +//===--- ASTPrinter.cpp - Swift Language AST Printer ----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,6 +23,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeVisitor.h" @@ -31,6 +32,7 @@ #include "swift/Basic/Fallthrough.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/Basic/STLExtras.h" +#include "swift/Basic/StringExtras.h" #include "swift/Parse/Lexer.h" #include "swift/Config.h" #include "swift/Sema/CodeCompletionTypeChecking.h" @@ -120,7 +122,7 @@ std::string ASTPrinter::sanitizeUtf8(StringRef Text) { Builder.append(Data, Data + Step); } else { - // If malformatted, add replacement characters. + // If malformed, add replacement characters. Builder.append(Replacement); } Data += Step; @@ -135,8 +137,12 @@ bool ASTPrinter::printTypeInterface(Type Ty, DeclContext *DC, Ty = Ty->getRValueType(); PrintOptions Options = PrintOptions::printTypeInterface(Ty.getPointer(), DC); if (auto ND = Ty->getNominalOrBoundGenericNominal()) { + llvm::SmallPtrSet AllExts; + for (auto Ext : ND->getExtensions()) { + AllExts.insert(Ext); + } Options.printExtensionContentAsMembers = [&](const ExtensionDecl *ED) { - return isExtensionApplied(*ND->getDeclContext(), Ty, ED); + return AllExts.count(ED) == 1 && isExtensionApplied(*ND->getDeclContext(), Ty, ED); }; ND->print(OS, Options); return true; @@ -216,6 +222,14 @@ ASTPrinter &ASTPrinter::operator<<(UUID UU) { return *this; } +ASTPrinter &ASTPrinter::operator<<(DeclName name) { + llvm::SmallString<32> str; + llvm::raw_svector_ostream os(str); + name.print(os); + printTextImpl(os.str()); + return *this; +} + /// Determine whether to escape the given keyword in the given context. static bool escapeKeywordInContext(StringRef keyword, PrintNameContext context){ switch (context) { @@ -224,6 +238,9 @@ static bool escapeKeywordInContext(StringRef keyword, PrintNameContext context){ case PrintNameContext::GenericParameter: return keyword != "Self"; + + case PrintNameContext::FunctionParameter: + return !canBeArgumentLabel(keyword); } } @@ -424,15 +441,15 @@ class PrintAST : public ASTVisitor { // is null. if ((Options.PreferTypeRepr && TL.hasLocation()) || TL.getType().isNull()) { - TL.getTypeRepr()->print(Printer, Options); + if (auto repr = TL.getTypeRepr()) + repr->print(Printer, Options); return; } TL.getType().print(Printer, Options); } void printAttributes(const Decl *D); - void printTypedPattern(const TypedPattern *TP, - bool StripOuterSliceType = false); + void printTypedPattern(const TypedPattern *TP); public: void printPattern(const Pattern *pattern); @@ -466,10 +483,11 @@ class PrintAST : public ASTVisitor { /// \returns true if anything was printed. bool printASTNodes(const ArrayRef &Elements, bool NeedIndent = true); - void printOneParameter(const Pattern *BodyPattern, - bool ArgNameIsAPIByDefault, - bool StripOuterSliceType, - bool Curried); + void printOneParameter(const ParamDecl *param, bool Curried, + bool ArgNameIsAPIByDefault); + + void printParameterList(ParameterList *PL, bool isCurried, + std::function isAPINameByDefault); /// \brief Print the function parameters in curried or selector style, /// to match the original function declaration. @@ -507,8 +525,7 @@ void PrintAST::printAttributes(const Decl *D) { D->getAttrs().print(Printer, Options); } -void PrintAST::printTypedPattern(const TypedPattern *TP, - bool StripOuterSliceType) { +void PrintAST::printTypedPattern(const TypedPattern *TP) { auto TheTypeLoc = TP->getTypeLoc(); if (TheTypeLoc.hasLocation()) { // If the outer typeloc is an InOutTypeRepr, print the inout before the @@ -528,13 +545,6 @@ void PrintAST::printTypedPattern(const TypedPattern *TP, printPattern(TP->getSubPattern()); Printer << ": "; - if (StripOuterSliceType) { - Type T = TP->getType(); - if (auto *BGT = T->getAs()) { - BGT->getGenericArgs()[0].print(Printer, Options); - return; - } - } printTypeLoc(TheTypeLoc); return; } @@ -547,12 +557,6 @@ void PrintAST::printTypedPattern(const TypedPattern *TP, printPattern(TP->getSubPattern()); Printer << ": "; - if (StripOuterSliceType) { - if (auto *BGT = T->getAs()) { - BGT->getGenericArgs()[0].print(Printer, Options); - return; - } - } T.print(Printer, Options); } @@ -564,9 +568,8 @@ void PrintAST::printPattern(const Pattern *pattern) { case PatternKind::Named: { auto named = cast(pattern); - recordDeclLoc(named->getDecl(), - [&]{ - Printer.printName(named->getBodyName()); + recordDeclLoc(named->getDecl(), [&]{ + Printer.printName(named->getBoundName()); }); break; } @@ -585,21 +588,8 @@ void PrintAST::printPattern(const Pattern *pattern) { const auto &Elt = Fields[i]; if (i != 0) Printer << ", "; - - if (Elt.hasEllipsis()) { - printTypedPattern(cast(Elt.getPattern()), - /*StripOuterSliceType=*/true); - Printer << "..."; - } else { - printPattern(Elt.getPattern()); - } - if (Elt.getDefaultArgKind() != DefaultArgumentKind::None) { - if (Options.PrintDefaultParameterPlaceholder) - Printer << " = default"; - else if (Options.VarInitializers) { - // FIXME: Print initializer here. - } - } + + printPattern(Elt.getPattern()); } Printer << ")"; break; @@ -698,8 +688,7 @@ void PrintAST::printWhereClause(ArrayRef requirements) { bool isFirst = true; for (auto &req : requirements) { - if (req.isInvalid() || - req.getKind() == RequirementKind::WitnessMarker) + if (req.isInvalid()) continue; if (isFirst) { @@ -709,25 +698,33 @@ void PrintAST::printWhereClause(ArrayRef requirements) { Printer << ", "; } - auto asWrittenStr = req.getAsWrittenString(); - if (!asWrittenStr.empty()) { - Printer << asWrittenStr; + auto TupleOp = req.getAsAnalyzedWrittenString(); + if (TupleOp.hasValue()) { + auto Tuple = TupleOp.getValue(); + Printer << std::get<0>(Tuple); + switch(std::get<2>(Tuple)) { + case RequirementReprKind::TypeConstraint: + Printer << " : "; + break; + case RequirementReprKind::SameType: + Printer << " == "; + break; + } + Printer << std::get<1>(Tuple); continue; } switch (req.getKind()) { - case RequirementKind::Conformance: + case RequirementReprKind::TypeConstraint: printTypeLoc(req.getSubjectLoc()); Printer << " : "; printTypeLoc(req.getConstraintLoc()); break; - case RequirementKind::SameType: + case RequirementReprKind::SameType: printTypeLoc(req.getFirstTypeLoc()); Printer << " == "; printTypeLoc(req.getSecondTypeLoc()); break; - case RequirementKind::WitnessMarker: - llvm_unreachable("Handled above"); } } } @@ -1290,6 +1287,13 @@ void PrintAST::visitExtensionDecl(ExtensionDecl *decl) { Printer << "."; } } + + // Respect alias type. + if (extendedType->getKind() == TypeKind::NameAlias) { + extendedType.print(Printer, Options); + return; + } + Printer.printTypeRef(nominal, nominal->getName()); }); printInherited(decl); @@ -1399,7 +1403,7 @@ void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) { printDocumentationComment(decl); printAttributes(decl); if (!Options.SkipIntroducerKeywords) - Printer << "typealias "; + Printer << "associatedtype "; recordDeclLoc(decl, [&]{ Printer.printName(decl->getName()); @@ -1562,50 +1566,40 @@ void PrintAST::visitParamDecl(ParamDecl *decl) { return visitVarDecl(decl); } -void PrintAST::printOneParameter(const Pattern *BodyPattern, - bool ArgNameIsAPIByDefault, - bool StripOuterSliceType, - bool Curried) { +void PrintAST::printOneParameter(const ParamDecl *param, bool Curried, + bool ArgNameIsAPIByDefault) { auto printArgName = [&]() { // Print argument name. - auto ArgName = BodyPattern->getBoundName(); - auto BodyName = BodyPattern->getBodyName(); + auto ArgName = param->getArgumentName(); + auto BodyName = param->getName(); switch (Options.ArgAndParamPrinting) { case PrintOptions::ArgAndParamPrintingMode::ArgumentOnly: - Printer.printName(ArgName); + Printer.printName(ArgName, PrintNameContext::FunctionParameter); if (!ArgNameIsAPIByDefault && !ArgName.empty()) Printer << " _"; break; case PrintOptions::ArgAndParamPrintingMode::MatchSource: if (ArgName == BodyName && ArgNameIsAPIByDefault) { - Printer.printName(ArgName); + Printer.printName(ArgName, PrintNameContext::FunctionParameter); break; } if (ArgName.empty() && !ArgNameIsAPIByDefault) { - Printer.printName(BodyName); + Printer.printName(BodyName, PrintNameContext::FunctionParameter); break; } SWIFT_FALLTHROUGH; case PrintOptions::ArgAndParamPrintingMode::BothAlways: - Printer.printName(ArgName); + Printer.printName(ArgName, PrintNameContext::FunctionParameter); Printer << " "; - Printer.printName(BodyName); + Printer.printName(BodyName, PrintNameContext::FunctionParameter); break; } Printer << ": "; }; - if (auto *VP = dyn_cast(BodyPattern)) - BodyPattern = VP->getSubPattern(); - auto *TypedBodyPattern = dyn_cast(BodyPattern); - if (!TypedBodyPattern) { - // It was a syntax error. - printArgName(); - return; - } - auto TheTypeLoc = TypedBodyPattern->getTypeLoc(); - if (TheTypeLoc.hasLocation()) { + auto TheTypeLoc = param->getTypeLoc(); + if (TheTypeLoc.getTypeRepr()) { // If the outer typeloc is an InOutTypeRepr, print the 'inout' before the // subpattern. if (auto *IOTR = dyn_cast(TheTypeLoc.getTypeRepr())) { @@ -1619,6 +1613,9 @@ void PrintAST::printOneParameter(const Pattern *BodyPattern, Printer << "inout "; } } else { + if (param->hasType()) + TheTypeLoc = TypeLoc::withoutLoc(param->getType()); + if (Type T = TheTypeLoc.getType()) { if (auto *IOT = T->getAs()) { Printer << "inout "; @@ -1628,9 +1625,9 @@ void PrintAST::printOneParameter(const Pattern *BodyPattern, } // If the parameter is autoclosure, or noescape, print it. This is stored - // on the type of the pattern, not on the typerepr. - if (BodyPattern->hasType()) { - auto bodyCanType = BodyPattern->getType()->getCanonicalType(); + // on the type of the decl, not on the typerepr. + if (param->hasType()) { + auto bodyCanType = param->getType()->getCanonicalType(); if (auto patternType = dyn_cast(bodyCanType)) { switch (patternType->isAutoClosure()*2 + patternType->isNoEscape()) { case 0: break; // neither. @@ -1643,12 +1640,6 @@ void PrintAST::printOneParameter(const Pattern *BodyPattern, printArgName(); - if (StripOuterSliceType && !TheTypeLoc.hasLocation()) { - if (auto *BGT = TypedBodyPattern->getType()->getAs()) { - BGT->getGenericArgs()[0].print(Printer, Options); - return; - } - } auto ContainsFunc = [&] (DeclAttrKind Kind) { return Options.ExcludeAttrList.end() != std::find(Options.ExcludeAttrList. begin(), Options.ExcludeAttrList.end(), Kind); @@ -1667,66 +1658,64 @@ void PrintAST::printOneParameter(const Pattern *BodyPattern, Options.ExcludeAttrList.push_back(DAK_NoEscape); if (!hasAutoClosure) Options.ExcludeAttrList.push_back(DAK_AutoClosure); + + + // If the parameter is variadic, we will print the "..." after it, but we have + // to strip off the added array type. + if (param->isVariadic() && TheTypeLoc.getType()) { + if (auto *BGT = TheTypeLoc.getType()->getAs()) + TheTypeLoc.setType(BGT->getGenericArgs()[0]); + } + printTypeLoc(TheTypeLoc); + + if (param->isVariadic()) + Printer << "..."; // After printing the type, we need to restore what the option used to be. if (!hasNoEscape) RemoveFunc(DAK_NoEscape); if (!hasAutoClosure) RemoveFunc(DAK_AutoClosure); + + + if (Options.PrintDefaultParameterPlaceholder && + param->isDefaultArgument()) { + Printer << " = "; + auto defaultArgStr + = getDefaultArgumentSpelling(param->getDefaultArgumentKind()); + if (defaultArgStr.empty()) + Printer << "default"; + else + Printer << defaultArgStr; + } +} + +void PrintAST::printParameterList(ParameterList *PL, bool isCurried, + std::function isAPINameByDefault) { + Printer << "("; + for (unsigned i = 0, e = PL->size(); i != e; ++i) { + if (i > 0) + Printer << ", "; + + printOneParameter(PL->get(i), isCurried, isAPINameByDefault(i)); + } + Printer << ")"; } void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { - ArrayRef BodyPatterns = AFD->getBodyParamPatterns(); + auto BodyParams = AFD->getParameterLists(); // Skip over the implicit 'self'. - if (AFD->getImplicitSelfDecl()) { - BodyPatterns = BodyPatterns.slice(1); - } + if (AFD->getImplicitSelfDecl()) + BodyParams = BodyParams.slice(1); - for (unsigned CurrPattern = 0, NumPatterns = BodyPatterns.size(); + for (unsigned CurrPattern = 0, NumPatterns = BodyParams.size(); CurrPattern != NumPatterns; ++CurrPattern) { - if (auto *BodyTuple = dyn_cast(BodyPatterns[CurrPattern])) { - Printer << "("; - for (unsigned i = 0, e = BodyTuple->getNumElements(); i != e; ++i) { - if (i > 0) - Printer << ", "; - - // Determine whether the argument name is API by default. - bool ArgNameIsAPIByDefault - = CurrPattern > 0 || AFD->argumentNameIsAPIByDefault(i); - - printOneParameter(BodyTuple->getElement(i).getPattern(), - ArgNameIsAPIByDefault, - BodyTuple->getElement(i).hasEllipsis(), - /*Curried=*/CurrPattern > 0); - auto &CurrElt = BodyTuple->getElement(i); - if (CurrElt.hasEllipsis()) - Printer << "..."; - if (Options.PrintDefaultParameterPlaceholder && - CurrElt.getDefaultArgKind() != DefaultArgumentKind::None) { - if (AFD->getClangDecl() && CurrElt.getPattern()->hasType()) { - // For Clang declarations, figure out the default we're using. - auto CurrType = CurrElt.getPattern()->getType(); - Printer << " = " << CurrType->getInferredDefaultArgString(); - } else { - // Use placeholder anywhere else. - Printer << " = default"; - } - } - } - Printer << ")"; - continue; - } - bool ArgNameIsAPIByDefault - = CurrPattern > 0 || AFD->argumentNameIsAPIByDefault(0); - auto *BodyParen = cast(BodyPatterns[CurrPattern]); - Printer << "("; - printOneParameter(BodyParen->getSubPattern(), - ArgNameIsAPIByDefault, - /*StripOuterSliceType=*/false, - /*Curried=*/CurrPattern > 0); - Printer << ")"; + printParameterList(BodyParams[CurrPattern], /*Curried=*/CurrPattern > 0, + [&](unsigned argNo)->bool { + return CurrPattern > 0 || AFD->argumentNameIsAPIByDefault(argNo); + }); } if (AFD->isBodyThrowing()) { @@ -1797,18 +1786,13 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { Printer << "nonmutating "; Printer << (decl->isSetter() ? "set" : "willSet"); - auto BodyParams = decl->getBodyParamPatterns(); - auto ValueParam = BodyParams.back()->getSemanticsProvidingPattern(); - if (auto *TP = dyn_cast(ValueParam)) { - if (!TP->isImplicit() && TP->getNumElements() != 0) { - auto *P = TP->getElement(0).getPattern()-> - getSemanticsProvidingPattern(); - Identifier Name = P->getBodyName(); - if (!Name.empty() && !P->isImplicit()) { - Printer << "("; - Printer.printName(Name); - Printer << ")"; - } + auto params = decl->getParameterLists().back(); + if (params->size() != 0 && !params->get(0)->isImplicit()) { + auto Name = params->get(0)->getName(); + if (!Name.empty()) { + Printer << "("; + Printer.printName(Name); + Printer << ")"; } } }); @@ -1926,33 +1910,11 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccessibility(decl); - recordDeclLoc(decl, - [&]{ - Printer << "subscript "; - auto *IndicePat = decl->getIndices(); - if (auto *BodyTuple = dyn_cast(IndicePat)) { - Printer << "("; - for (unsigned i = 0, e = BodyTuple->getNumElements(); i != e; ++i) { - if (i > 0) - Printer << ", "; - - printOneParameter(BodyTuple->getElement(i).getPattern(), - /*ArgNameIsAPIByDefault=*/false, - BodyTuple->getElement(i).hasEllipsis(), - /*Curried=*/false); - if (BodyTuple->getElement(i).hasEllipsis()) - Printer << "..."; - } - } else { - auto *BodyParen = cast(IndicePat); - Printer << "("; - printOneParameter(BodyParen->getSubPattern(), - /*ArgNameIsAPIByDefault=*/false, - /*StripOuterSliceType=*/false, - /*Curried=*/false); - } - Printer << ")"; - }); + recordDeclLoc(decl, [&]{ + Printer << "subscript "; + printParameterList(decl->getIndices(), /*Curried=*/false, + /*isAPINameByDefault*/[](unsigned)->bool{return false;}); + }); Printer << " -> "; decl->getElementType().print(Printer, Options); @@ -2384,6 +2346,10 @@ class TypePrinter : public TypeVisitor { case DeclContextKind::AbstractFunctionDecl: visit(cast(DC)->getType()); return; + + case DeclContextKind::SubscriptDecl: + visit(cast(DC)->getType()); + return; } } @@ -2481,7 +2447,7 @@ class TypePrinter : public TypeVisitor { else D = T->getAnyNominal(); - // If we can not find the declaration, be extra careful and print + // If we cannot find the declaration, be extra careful and print // the type qualified. if (!D) return true; @@ -2627,7 +2593,7 @@ class TypePrinter : public TypeVisitor { } if (TD.hasName()) { - Printer.printName(TD.getName()); + Printer.printName(TD.getName(), PrintNameContext::FunctionParameter); Printer << ": "; } @@ -2882,6 +2848,7 @@ class TypePrinter : public TypeVisitor { unsigned getDepthOfRequirement(const Requirement &req) { switch (req.getKind()) { case RequirementKind::Conformance: + case RequirementKind::Superclass: case RequirementKind::WitnessMarker: return getDepthOfType(req.getFirstType()); @@ -2977,6 +2944,7 @@ class TypePrinter : public TypeVisitor { visit(req.getFirstType()); switch (req.getKind()) { case RequirementKind::Conformance: + case RequirementKind::Superclass: Printer << " : "; break; @@ -3219,21 +3187,12 @@ class TypePrinter : public TypeVisitor { } void visitTypeVariableType(TypeVariableType *T) { - auto Base = T->getBaseBeingSubstituted(); - if (T->getASTContext().LangOpts.DebugConstraintSolver) { Printer << "$T" << T->getID(); return; } - if (T->isEqual(Base) || T->isPrinting) { - Printer << "_"; - return; - } - - llvm::SaveAndRestore isPrinting(T->isPrinting, true); - - visit(Base); + Printer << "_"; } }; } // unnamed namespace @@ -3420,7 +3379,5 @@ void ProtocolConformance::printName(llvm::raw_ostream &os, void Substitution::print(llvm::raw_ostream &os, const PrintOptions &PO) const { - Archetype->print(os, PO); - os << " = "; Replacement->print(os, PO); } diff --git a/lib/AST/Verifier.cpp b/lib/AST/ASTVerifier.cpp similarity index 95% rename from lib/AST/Verifier.cpp rename to lib/AST/ASTVerifier.cpp index fadc486ffa3c1..5a23824ead868 100644 --- a/lib/AST/Verifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -64,8 +64,6 @@ struct ASTNodeBase {}; }; #include "swift/AST/PatternNodes.def" - enum ShouldHalt { Continue, Halt }; - class Verifier : public ASTWalker { PointerUnion M; ASTContext &Ctx; @@ -516,6 +514,7 @@ struct ASTNodeBase {}; case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: case DeclContextKind::SerializedLocal: + case DeclContextKind::SubscriptDecl: return nullptr; case DeclContextKind::AbstractFunctionDecl: @@ -674,8 +673,8 @@ struct ASTNodeBase {}; if (auto Overridden = D->getOverriddenDecl()) { if (D->getDeclContext() == Overridden->getDeclContext()) { - PrettyStackTraceDecl debugStack("verifying overriden", D); - Out << "can not override a decl in the same DeclContext"; + PrettyStackTraceDecl debugStack("verifying overridden", D); + Out << "cannot override a decl in the same DeclContext"; D->dump(Out); Overridden->dump(Out); abort(); @@ -1601,6 +1600,7 @@ struct ASTNodeBase {}; case DeclContextKind::Initializer: case DeclContextKind::NominalTypeDecl: case DeclContextKind::ExtensionDecl: + case DeclContextKind::SubscriptDecl: return hasEnclosingFunctionContext(dc->getParent()); } } @@ -1616,7 +1616,6 @@ struct ASTNodeBase {}; // Make sure that there are no archetypes in the interface type. if (VD->getDeclContext()->isTypeContext() && !hasEnclosingFunctionContext(VD->getDeclContext()) && - !isa(VD) && /* because of subscripts */ VD->getInterfaceType().findIf([](Type type) { return type->is(); })) { @@ -1841,11 +1840,6 @@ struct ASTNodeBase {}; void verifyParsed(ConstructorDecl *CD) { PrettyStackTraceDecl debugStack("verifying ConstructorDecl", CD); - if (CD->getBodyParamPatterns().size() != 2) { - Out << "ConstructorDecl should have exactly two parameter patterns"; - abort(); - } - auto *DC = CD->getDeclContext(); if (!isa(DC) && !isa(DC) && !CD->isInvalid()) { @@ -1914,11 +1908,7 @@ struct ASTNodeBase {}; PrettyStackTraceDecl debugStack("verifying DestructorDecl", DD); if (DD->isGeneric()) { - Out << "DestructorDecl can not be generic"; - abort(); - } - if (DD->getBodyParamPatterns().size() != 1) { - Out << "DestructorDecl should have 'self' parameter pattern only"; + Out << "DestructorDecl cannot be generic"; abort(); } @@ -1978,9 +1968,10 @@ struct ASTNodeBase {}; switch (requirements.front().getKind()) { case RequirementKind::Conformance: // If the second type is a protocol type, we're done. - if (requirements.front().getSecondType()->is()) - done = true; + done = true; + break; + case RequirementKind::Superclass: break; case RequirementKind::SameType: @@ -2125,83 +2116,32 @@ struct ASTNodeBase {}; PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD); // All of the parameter names should match. - if (!isa(AFD)) { + if (!isa(AFD)) { // Destructor has no non-self params. auto paramNames = AFD->getFullName().getArgumentNames(); bool checkParamNames = (bool)AFD->getFullName(); bool hasSelf = AFD->getDeclContext()->isTypeContext(); - const Pattern *firstParams = - AFD->getBodyParamPatterns()[hasSelf ? 1 : 0]; - - if (auto *paramTuple = dyn_cast(firstParams)) { - if (checkParamNames && - paramNames.size() != paramTuple->getNumElements()) { - Out << "Function name does not match its argument pattern (" - << paramNames.size() << " elements instead of " - << paramTuple->getNumElements() << ")\n"; - AFD->dump(Out); - abort(); - } - - // This doesn't use for_each because paramNames shouldn't be checked - // when the function is anonymous. - for (size_t i = 0, e = paramTuple->getNumElements(); i < e; ++i) { - TuplePatternElt elt = paramTuple->getElement(i); - Pattern *param = elt.getPattern()->getSemanticsProvidingPattern(); - if (auto *namedParam = dyn_cast(param)) { - if (namedParam->getBoundName() != elt.getLabel()) { - Out << "Function body param tuple label " - "doesn't match variable's public name\n"; - AFD->dump(Out); - abort(); - } + auto *firstParams = AFD->getParameterList(hasSelf ? 1 : 0); + + if (checkParamNames && + paramNames.size() != firstParams->size()) { + Out << "Function name does not match its argument pattern (" + << paramNames.size() << " elements instead of " + << firstParams->size() << ")\n"; + AFD->dump(Out); + abort(); + } - if (checkParamNames && - namedParam->getBoundName() != paramNames[i]) { - Out << "Function full name doesn't match variable name\n"; - AFD->dump(Out); - abort(); - } - } else { - assert(isa(param)); - if (!elt.getLabel().empty()) { - Out << "Function body param tuple has a label, " - "but there's no variable\n"; - AFD->dump(Out); - abort(); - } + // This doesn't use for_each because paramNames shouldn't be checked + // when the function is anonymous. + for (size_t i = 0, e = firstParams->size(); i < e; ++i) { + auto ¶m = firstParams->get(i); - if (checkParamNames && !paramNames[i].empty()) { - Out << "Function full name doesn't match variable name\n"; - AFD->dump(Out); - abort(); - } - } - } - } else { - if (checkParamNames && paramNames.size() != 1) { - Out << "Function name does not match its non-tuple argument pattern (" - << paramNames.size() << " elements instead of 1)\n"; + if (checkParamNames && + param->getArgumentName() != paramNames[i]) { + Out << "Function full name doesn't match variable name\n"; AFD->dump(Out); abort(); } - - firstParams = firstParams->getSemanticsProvidingPattern(); - if (auto *namedParam = dyn_cast(firstParams)) { - if (checkParamNames && - namedParam->getBoundName() != paramNames.front()) { - Out << "Function full name doesn't match variable name\n"; - AFD->dump(Out); - abort(); - } - } else { - assert(isa(firstParams)); - if (checkParamNames && !paramNames.front().empty()) { - Out << "Function full name has an argument name, " - "but there's no variable\n"; - AFD->dump(Out); - abort(); - } - } } } @@ -2334,7 +2274,7 @@ struct ASTNodeBase {}; PrettyStackTraceDecl debugStack("verifying FuncDecl", FD); unsigned MinParamPatterns = FD->getImplicitSelfDecl() ? 2 : 1; - if (FD->getBodyParamPatterns().size() < MinParamPatterns) { + if (FD->getParameterLists().size() < MinParamPatterns) { Out << "should have at least " << MinParamPatterns << " parameter patterns"; abort(); @@ -2344,7 +2284,7 @@ struct ASTNodeBase {}; unsigned NumExpectedParamPatterns = 1; if (FD->getImplicitSelfDecl()) NumExpectedParamPatterns++; - if (FD->getBodyParamPatterns().size() != NumExpectedParamPatterns) { + if (FD->getParameterLists().size() != NumExpectedParamPatterns) { Out << "accessors should not be curried"; abort(); } @@ -2400,36 +2340,11 @@ struct ASTNodeBase {}; void verifyParsed(TuplePattern *TP) { PrettyStackTracePattern debugStack(Ctx, "verifying TuplePattern", TP); - - for (const auto &elt : TP->getElements()) { - if (elt.hasEllipsis()) { - if (!isa(elt.getPattern())) { - Out << "a vararg subpattern of a TuplePattern should be " - "a TypedPattern\n"; - abort(); - } - } - } - verifyParsedBase(TP); } void verifyChecked(TuplePattern *TP) { PrettyStackTracePattern debugStack(Ctx, "verifying TuplePattern", TP); - - for (const auto &elt : TP->getElements()) { - if (elt.hasEllipsis()) { - Type T = cast(elt.getPattern())->getType() - ->getCanonicalType(); - if (auto *BGT = T->getAs()) { - if (BGT->getDecl() == Ctx.getArrayDecl()) - continue; - } - Out << "a vararg subpattern of a TuplePattern has wrong type"; - abort(); - } - } - verifyCheckedBase(TP); } @@ -2603,11 +2518,9 @@ struct ASTNodeBase {}; } void checkMangling(ValueDecl *D) { - llvm::SmallString<32> Buf; - llvm::raw_svector_ostream OS(Buf); - Mangle::Mangler Mangler(OS); + Mangle::Mangler Mangler; Mangler.mangleDeclName(D); - if (OS.str().empty()) { + if (Mangler.finalize().empty()) { Out << "Mangler gave empty string for a ValueDecl"; abort(); } @@ -2762,6 +2675,20 @@ struct ASTNodeBase {}; [&]{ P->print(Out); }); } + void assertValidRegion(Decl *D) { + auto R = D->getSourceRange(); + if (R.isValid() && Ctx.SourceMgr.isBeforeInBuffer(R.End, R.Start)) { + Out << "invalid type source range for decl: "; + D->print(Out); + Out << "\n"; + abort(); + } + } + + void checkSourceRanges(ParamDecl *PD) { + assertValidRegion(PD); + } + void checkSourceRanges(Decl *D) { PrettyStackTraceDecl debugStack("verifying ranges", D); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 6994ebca1c778..5ee65cf88f35c 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -56,6 +56,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ExprHandle.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" using namespace swift; @@ -117,10 +118,14 @@ class Traversal : public ASTVisitorgetIndices())) - SD->setIndices(NewPattern); - else - return true; + visit(SD->getIndices()); return doIt(SD->getElementTypeLoc()); } @@ -231,8 +233,8 @@ class Traversal : public ASTVisitorgetGenericParams()) { + if (AFD->getGenericParams() && + Walker.shouldWalkIntoFunctionGenericParams()) { // Visit generic params for (auto &P : AFD->getGenericParams()->getParams()) { @@ -247,25 +249,20 @@ class Traversal : public ASTVisitorgetGenericParams()->getRequirements()) { switch (Req.getKind()) { - case RequirementKind::SameType: + case RequirementReprKind::SameType: if (doIt(Req.getFirstTypeLoc()) || doIt(Req.getSecondTypeLoc())) return true; break; - case RequirementKind::Conformance: - if (doIt(Req.getSubjectLoc())) + case RequirementReprKind::TypeConstraint: + if (doIt(Req.getSubjectLoc()) || doIt(Req.getConstraintLoc())) return true; break; - case RequirementKind::WitnessMarker: - break; } } } - for (auto &P : AFD->getBodyParamPatterns()) { - if (Pattern *NewPattern = doIt(P)) - P = NewPattern; - else - return true; + for (auto PL : AFD->getParameterLists()) { + visit(PL); } if (auto *FD = dyn_cast(AFD)) @@ -294,6 +291,14 @@ class Traversal : public ASTVisitorhasArgumentType()) { + if (auto TR = ED->getArgumentTypeLoc().getTypeRepr()) { + if (doIt(TR)) { + return true; + } + } + } + // The getRawValueExpr should remain the untouched original LiteralExpr for // serialization and validation purposes. We only traverse the type-checked // form, unless we haven't populated it yet. @@ -312,9 +317,9 @@ class Traversal : public ASTVisitorgetSubExpr())) { - E->setSubExpr(sub); - return E; - } - - return nullptr; - } - Expr *visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *E) { return E; } Expr *visitOverloadedMemberRefExpr(OverloadedMemberRefExpr *E) { if (auto base = doIt(E->getBase())) { @@ -505,16 +501,6 @@ class Traversal : public ASTVisitorgetBase()) - return E; - - if (Expr *E2 = doIt(E->getBase())) { - E->setBase(E2); - return E; - } - return nullptr; - } Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *E) { if (!E->getSubExpr()) return E; @@ -631,10 +617,7 @@ class Traversal : public ASTVisitorgetParams())) - expr->setParams(Pat); - else - return nullptr; + visit(expr->getParameters()); if (expr->hasExplicitResultType()) if (doIt(expr->getExplicitResultTypeLoc())) @@ -828,9 +811,17 @@ class Traversal : public ASTVisitorgetSubExpr()); + if (!sub) return nullptr; + + E->setSubExpr(sub); + return E; + } + + //===--------------------------------------------------------------------===// + // Everything Else + //===--------------------------------------------------------------------===// #define STMT(Id, Parent) Stmt *visit##Id##Stmt(Id##Stmt *S); #include "swift/AST/StmtNodes.def" @@ -840,7 +831,32 @@ class Traversal : public ASTVisitorisImplicit() && !P->isTypeLocImplicit() && + doIt(P->getTypeLoc())) + return true; + + if (auto *E = P->getDefaultValue()) { + auto res = doIt(E->getExpr()); + if (!res) return true; + E->setExpr(res, E->alreadyChecked()); + } + } + + return Walker.walkToParameterListPost(PL); + } + public: Traversal(ASTWalker &walker) : Walker(walker) {} @@ -1307,14 +1323,6 @@ Pattern *Traversal::visitTuplePattern(TuplePattern *P) { element.setPattern(newField); else return nullptr; - - if (auto handle = element.getInit()) { - if (auto init = doIt(handle->getExpr())) { - handle->setExpr(init, handle->alreadyChecked()); - } else { - return nullptr; - } - } } return P; } diff --git a/lib/AST/ArchetypeBuilder.cpp b/lib/AST/ArchetypeBuilder.cpp index cf1b1446d2dcf..02ce7cc0825dc 100644 --- a/lib/AST/ArchetypeBuilder.cpp +++ b/lib/AST/ArchetypeBuilder.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,7 +21,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/Module.h" -#include "swift/AST/Pattern.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/TypeWalker.h" @@ -1060,12 +1060,11 @@ bool ArchetypeBuilder::addAbstractTypeParamRequirements( // diagnosing it if this is the first such occurrence. auto markRecursive = [&](AssociatedTypeDecl *assocType, ProtocolDecl *proto, - SourceLoc loc ) { - if (!pa->isRecursive() && !assocType->isRecursive()) { + SourceLoc loc) { + if (!pa->isRecursive() && !assocType->isRecursive()) Diags.diagnose(assocType->getLoc(), diag::recursive_requirement_reference); - assocType->setIsRecursive(); - } + assocType->setIsRecursive(); pa->setIsRecursive(); // FIXME: Drop this protocol. @@ -1159,7 +1158,7 @@ bool ArchetypeBuilder::visitInherited( bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) { switch (Req.getKind()) { - case RequirementKind::Conformance: { + case RequirementReprKind::TypeConstraint: { PotentialArchetype *PA = resolveArchetype(Req.getSubject()); if (!PA) { // FIXME: Poor location information. @@ -1199,14 +1198,11 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) { return false; } - case RequirementKind::SameType: + case RequirementReprKind::SameType: return addSameTypeRequirement(Req.getFirstType(), Req.getSecondType(), RequirementSource(RequirementSource::Explicit, Req.getEqualLoc())); - - case RequirementKind::WitnessMarker: - llvm_unreachable("Value witness marker in requirement"); } llvm_unreachable("Unhandled requirement?"); @@ -1215,14 +1211,18 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) { void ArchetypeBuilder::addRequirement(const Requirement &req, RequirementSource source) { switch (req.getKind()) { - case RequirementKind::Conformance: { + case RequirementKind::Superclass: { PotentialArchetype *pa = resolveArchetype(req.getFirstType()); assert(pa && "Re-introducing invalid requirement"); - if (req.getSecondType()->getClassOrBoundGenericClass()) { - addSuperclassRequirement(pa, req.getSecondType(), source); - return; - } + assert(req.getSecondType()->getClassOrBoundGenericClass()); + addSuperclassRequirement(pa, req.getSecondType(), source); + return; + } + + case RequirementKind::Conformance: { + PotentialArchetype *pa = resolveArchetype(req.getFirstType()); + assert(pa && "Re-introducing invalid requirement"); SmallVector conformsTo; bool existential = req.getSecondType()->isExistentialType(conformsTo); @@ -1338,6 +1338,7 @@ class ArchetypeBuilder::InferRequirementsWalker : public TypeWalker { break; } + case RequirementKind::Superclass: case RequirementKind::Conformance: { auto subjectType = req.getFirstType().subst( &Builder.getModule(), @@ -1354,17 +1355,19 @@ class ArchetypeBuilder::InferRequirementsWalker : public TypeWalker { if (isOuterArchetype(subjectPA)) return Action::Continue; - if (auto proto = req.getSecondType()->getAs()) { + if (req.getKind() == RequirementKind::Conformance) { + auto proto = req.getSecondType()->castTo(); if (Builder.addConformanceRequirement(subjectPA, proto->getDecl(), source)) { HadError = true; return Action::Stop; } - } else if (Builder.addSuperclassRequirement(subjectPA, - req.getSecondType(), - source)) { - HadError = true; - return Action::Stop; + } else { + if (Builder.addSuperclassRequirement(subjectPA, req.getSecondType(), + source)) { + HadError = true; + return Action::Stop; + } } break; } @@ -1388,17 +1391,15 @@ bool ArchetypeBuilder::inferRequirements(TypeLoc type, return walker.hadError(); } -bool ArchetypeBuilder::inferRequirements(Pattern *pattern, +bool ArchetypeBuilder::inferRequirements(ParameterList *params, GenericParamList *genericParams) { - if (!pattern->hasType()) - return true; if (genericParams == nullptr) return false; - // FIXME: Crummy source-location information. - InferRequirementsWalker walker(*this, pattern->getSourceRange().Start, - genericParams->getDepth()); - pattern->getType().walk(walker); - return walker.hadError(); + + bool hadError = false; + for (auto P : *params) + hadError |= inferRequirements(P->getTypeLoc(), genericParams); + return hadError; } /// Perform typo correction on the given nested type, producing the @@ -1625,9 +1626,8 @@ void ArchetypeBuilder::enumerateRequirements(llvm::function_ref< RequirementSource(RequirementSource::Protocol, SourceLoc())); // If we have a superclass, produce a superclass requirement - // (FIXME: Currently described as a conformance requirement) if (Type superclass = archetype->getSuperclass()) { - f(RequirementKind::Conformance, archetype, superclass, + f(RequirementKind::Superclass, archetype, superclass, archetype->getSuperclassSource()); } @@ -1712,6 +1712,7 @@ void ArchetypeBuilder::dump(llvm::raw_ostream &out) { RequirementSource source) { switch (kind) { case RequirementKind::Conformance: + case RequirementKind::Superclass: out << "\n "; out << archetype->getDebugName() << " : " << type.get().getString() << " ["; @@ -1845,3 +1846,168 @@ bool ArchetypeBuilder::addGenericSignature(GenericSignature *sig, Type ArchetypeBuilder::substDependentType(Type type) { return substConcreteTypesForDependentTypes(*this, type); } + +/// Add the requirements for the given potential archetype and its nested +/// potential archetypes to the set of requirements. +static void +addRequirements( + Module &mod, Type type, + ArchetypeBuilder::PotentialArchetype *pa, + llvm::SmallPtrSet &knownPAs, + SmallVectorImpl &requirements) { + // If the potential archetype has been bound away to a concrete type, + // it needs no requirements. + if (pa->isConcreteType()) + return; + + // Add a value witness marker. + requirements.push_back(Requirement(RequirementKind::WitnessMarker, + type, Type())); + + // Add superclass requirement, if needed. + if (auto superclass = pa->getSuperclass()) { + // FIXME: What if the superclass type involves a type parameter? + requirements.push_back(Requirement(RequirementKind::Superclass, + type, superclass)); + } + + // Add conformance requirements. + SmallVector protocols; + for (const auto &conforms : pa->getConformsTo()) { + protocols.push_back(conforms.first); + } + + ProtocolType::canonicalizeProtocols(protocols); + for (auto proto : protocols) { + requirements.push_back(Requirement(RequirementKind::Conformance, + type, proto->getDeclaredType())); + } +} + +static void +addNestedRequirements( + Module &mod, Type type, + ArchetypeBuilder::PotentialArchetype *pa, + llvm::SmallPtrSet &knownPAs, + SmallVectorImpl &requirements) { + using PotentialArchetype = ArchetypeBuilder::PotentialArchetype; + + // Collect the nested types, sorted by name. + // FIXME: Could collect these from the conformance requirements, above. + SmallVector, 16> nestedTypes; + for (const auto &nested : pa->getNestedTypes()) { + // FIXME: Dropping requirements among different associated types of the + // same name. + nestedTypes.push_back(std::make_pair(nested.first, nested.second.front())); + } + std::sort(nestedTypes.begin(), nestedTypes.end(), + OrderPotentialArchetypeByName()); + + // Add requirements for associated types. + for (const auto &nested : nestedTypes) { + auto rep = nested.second->getRepresentative(); + if (knownPAs.insert(rep).second) { + // Form the dependent type that refers to this archetype. + auto assocType = nested.second->getResolvedAssociatedType(); + if (!assocType) + continue; // FIXME: If we do this late enough, there will be no failure. + + // Skip nested types bound to concrete types. + if (rep->isConcreteType()) + continue; + + auto nestedType = DependentMemberType::get(type, assocType, + mod.getASTContext()); + + addRequirements(mod, nestedType, rep, knownPAs, requirements); + addNestedRequirements(mod, nestedType, rep, knownPAs, requirements); + } + } +} + + +/// Collect the set of requirements placed on the given generic parameters and +/// their associated types. +static void collectRequirements(ArchetypeBuilder &builder, + ArrayRef params, + SmallVectorImpl &requirements) { + typedef ArchetypeBuilder::PotentialArchetype PotentialArchetype; + + // Find the "primary" potential archetypes, from which we'll collect all + // of the requirements. + llvm::SmallPtrSet knownPAs; + llvm::SmallVector primary; + for (auto param : params) { + auto pa = builder.resolveArchetype(param); + assert(pa && "Missing potential archetype for generic parameter"); + + // We only care about the representative. + pa = pa->getRepresentative(); + + if (knownPAs.insert(pa).second) + primary.push_back(param); + } + + // Add all of the conformance and superclass requirements placed on the given + // generic parameters and their associated types. + unsigned primaryIdx = 0, numPrimary = primary.size(); + while (primaryIdx < numPrimary) { + unsigned depth = primary[primaryIdx]->getDepth(); + + // For each of the primary potential archetypes, add the requirements. + // Stop when we hit a parameter at a different depth. + // FIXME: This algorithm falls out from the way the "all archetypes" lists + // are structured. Once those lists no longer exist or are no longer + // "the truth", we can simplify this algorithm considerably. + unsigned lastPrimaryIdx = primaryIdx; + for (unsigned idx = primaryIdx; + idx < numPrimary && primary[idx]->getDepth() == depth; + ++idx, ++lastPrimaryIdx) { + auto param = primary[idx]; + auto pa = builder.resolveArchetype(param)->getRepresentative(); + + // Add other requirements. + addRequirements(builder.getModule(), param, pa, knownPAs, + requirements); + } + + // For each of the primary potential archetypes, add the nested requirements. + for (unsigned idx = primaryIdx; idx < lastPrimaryIdx; ++idx) { + auto param = primary[idx]; + auto pa = builder.resolveArchetype(param)->getRepresentative(); + addNestedRequirements(builder.getModule(), param, pa, knownPAs, + requirements); + } + + primaryIdx = lastPrimaryIdx; + } + + + // Add all of the same-type requirements. + for (auto req : builder.getSameTypeRequirements()) { + auto firstType = req.first->getDependentType(builder, false); + Type secondType; + if (auto concrete = req.second.dyn_cast()) + secondType = concrete; + else if (auto secondPA = req.second.dyn_cast()) + secondType = secondPA->getDependentType(builder, false); + + if (firstType->is() || secondType->is() || + firstType->isEqual(secondType)) + continue; + + requirements.push_back(Requirement(RequirementKind::SameType, + firstType, secondType)); + } +} + +GenericSignature *ArchetypeBuilder::getGenericSignature( + ArrayRef genericParamTypes) { + // Collect the requirements placed on the generic parameter types. + SmallVector requirements; + collectRequirements(*this, genericParamTypes, requirements); + + auto sig = GenericSignature::get(genericParamTypes, requirements); + return sig; +} + diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index ad6a0be0fc831..17c1e8821606a 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -358,6 +358,32 @@ void DeclAttribute::print(ASTPrinter &Printer, // Not printed. return; + case DAK_Swift3Migration: { + auto attr = cast(this); + Printer << "@swift3_migration("; + + bool printedAny = false; + auto printSeparator = [&] { + if (printedAny) Printer << ", "; + else printedAny = true; + }; + + if (attr->getRenamed()) { + printSeparator(); + Printer << "renamed=\"" << attr->getRenamed() << "\""; + } + + if (!attr->getMessage().empty()) { + printSeparator(); + Printer << "message=\""; + Printer << attr->getMessage(); + Printer << "\""; + } + + Printer << ")"; + break; + } + case DAK_SynthesizedProtocol: // Not printed. return; @@ -475,6 +501,8 @@ StringRef DeclAttribute::getAttrName() const { return "<>"; case DAK_SynthesizedProtocol: return "<>"; + case DAK_Swift3Migration: + return "swift3_migration"; case DAK_WarnUnusedResult: return "warn_unused_result"; } diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 34c864a012025..9140174ac8282 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -1,8 +1,8 @@ -//===--- Availability.cpp - Swift Availability Structures -------*- C++ -*-===// +//===--- Availability.cpp - Swift Availability Structures -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -127,7 +127,7 @@ AvailabilityInference::annotatedAvailableRange(const Decl *D, ASTContext &Ctx) { for (auto Attr : D->getAttrs()) { auto *AvailAttr = dyn_cast(Attr); - if (AvailAttr == NULL || !AvailAttr->Introduced.hasValue() || + if (AvailAttr == nullptr || !AvailAttr->Introduced.hasValue() || !AvailAttr->isActivePlatform(Ctx)) { continue; } diff --git a/lib/AST/AvailabilitySpec.cpp b/lib/AST/AvailabilitySpec.cpp index a985d5c0c8127..4d4bcc5a89de5 100644 --- a/lib/AST/AvailabilitySpec.cpp +++ b/lib/AST/AvailabilitySpec.cpp @@ -1,8 +1,8 @@ -//===--- AvailabilitySpec.cpp - Swift Availability Query ASTs ---*- C++ -*-===// +//===--- AvailabilitySpec.cpp - Swift Availability Query ASTs -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index d77f7c4a89923..fb148ab553745 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,6 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" -#include #include using namespace swift; @@ -132,43 +131,38 @@ StringRef swift::getBuiltinBaseName(ASTContext &C, StringRef Name, /// Build a builtin function declaration. static FuncDecl * -getBuiltinFunction(Identifier Id, - ArrayRef ArgTypes, - Type ResType, +getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType, FunctionType::ExtInfo Info = FunctionType::ExtInfo()) { auto &Context = ResType->getASTContext(); - Type ArgType = TupleType::get(ArgTypes, Context); + + SmallVector tupleElts; + for (Type argType : argTypes) + tupleElts.push_back(argType); + + Type ArgType = TupleType::get(tupleElts, Context); Type FnType; FnType = FunctionType::get(ArgType, ResType, Info); Module *M = Context.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); - SmallVector ParamPatternElts; - for (auto &ArgTupleElt : ArgTypes) { - auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), + SmallVector params; + for (Type argType : argTypes) { + auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), - Identifier(), ArgTupleElt.getType(), + Identifier(), argType, DC); PD->setImplicit(); - Pattern *Pat = new (Context) NamedPattern(PD, /*implicit=*/true); - Pat = new (Context) TypedPattern(Pat, - TypeLoc::withoutLoc(ArgTupleElt.getType()), /*implicit=*/true); - PD->setParamParentPattern(Pat); - - ParamPatternElts.push_back(TuplePatternElt(Pat)); + params.push_back(PD); } - Pattern *ParamPattern = TuplePattern::createSimple( - Context, SourceLoc(), ParamPatternElts, SourceLoc()); - - llvm::SmallVector ArgNames(ParamPattern->numTopLevelVariables(), - Identifier()); - DeclName Name(Context, Id, ArgNames); + auto *paramList = ParameterList::create(Context, params); + + DeclName Name(Context, Id, paramList); auto FD = FuncDecl::create(Context, SourceLoc(), StaticSpellingKind::None, SourceLoc(), Name, SourceLoc(), SourceLoc(), SourceLoc(), /*GenericParams=*/nullptr, FnType, - ParamPattern, TypeLoc::withoutLoc(ResType), DC); + paramList, TypeLoc::withoutLoc(ResType), DC); FD->setImplicit(); FD->setAccessibility(Accessibility::Public); return FD; @@ -178,20 +172,15 @@ getBuiltinFunction(Identifier Id, static FuncDecl * getBuiltinGenericFunction(Identifier Id, ArrayRef ArgParamTypes, - ArrayRef ArgBodyTypes, + ArrayRef ArgBodyTypes, Type ResType, Type ResBodyType, GenericParamList *GenericParams, - FunctionType::ExtInfo Info = FunctionType::ExtInfo()) { + FunctionType::ExtInfo Info = FunctionType::ExtInfo()){ assert(GenericParams && "Missing generic parameters"); auto &Context = ResType->getASTContext(); Type ArgParamType = TupleType::get(ArgParamTypes, Context); - Type ArgBodyType = TupleType::get(ArgBodyTypes, Context); - - // Compute the function type. - Type FnType = PolymorphicFunctionType::get(ArgBodyType, ResBodyType, - GenericParams, Info); // Compute the interface type. SmallVector GenericParamTypes; @@ -215,34 +204,31 @@ getBuiltinGenericFunction(Identifier Id, Module *M = Context.TheBuiltinModule; DeclContext *DC = &M->getMainFile(FileUnitKind::Builtin); - SmallVector ParamPatternElts; - for (auto &ArgTupleElt : ArgBodyTypes) { - auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), + SmallVector params; + for (auto paramType : ArgBodyTypes) { + auto PD = new (Context) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), - Identifier(), ArgTupleElt.getType(), - DC); + Identifier(), paramType, DC); PD->setImplicit(); - Pattern *Pat = new (Context) NamedPattern(PD, /*implicit=*/true); - Pat = new (Context) TypedPattern(Pat, - TypeLoc::withoutLoc(ArgTupleElt.getType()), /*implicit=*/true); - PD->setParamParentPattern(Pat); - - ParamPatternElts.push_back(TuplePatternElt(Pat)); + params.push_back(PD); } - Pattern *ParamPattern = TuplePattern::createSimple( - Context, SourceLoc(), ParamPatternElts, SourceLoc()); - llvm::SmallVector ArgNames( - ParamPattern->numTopLevelVariables(), - Identifier()); - DeclName Name(Context, Id, ArgNames); + + auto *paramList = ParameterList::create(Context, params); + + // Compute the function type. + Type FnType = PolymorphicFunctionType::get(paramList->getType(Context), + ResBodyType, GenericParams, Info); + + DeclName Name(Context, Id, paramList); auto func = FuncDecl::create(Context, SourceLoc(), StaticSpellingKind::None, SourceLoc(), Name, SourceLoc(), SourceLoc(), SourceLoc(), - GenericParams, FnType, ParamPattern, + GenericParams, FnType, paramList, TypeLoc::withoutLoc(ResBodyType), DC); func->setInterfaceType(InterfaceType); + func->setGenericSignature(Sig); func->setImplicit(); func->setAccessibility(Accessibility::Public); @@ -254,16 +240,14 @@ static ValueDecl *getGepOperation(Identifier Id, Type ArgType) { auto &Context = ArgType->getASTContext(); // This is always "(i8*, IntTy) -> i8*" - TupleTypeElt ArgElts[] = { Context.TheRawPointerType, ArgType }; + Type ArgElts[] = { Context.TheRawPointerType, ArgType }; Type ResultTy = Context.TheRawPointerType; return getBuiltinFunction(Id, ArgElts, ResultTy); } /// Build a binary operation declaration. static ValueDecl *getBinaryOperation(Identifier Id, Type ArgType) { - TupleTypeElt ArgElts[] = { ArgType, ArgType }; - Type ResultTy = ArgType; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { ArgType, ArgType }, ArgType); } /// Build a declaration for a binary operation with overflow. @@ -271,7 +255,7 @@ static ValueDecl *getBinaryOperationWithOverflow(Identifier Id, Type ArgType) { auto &Context = ArgType->getASTContext(); Type ShouldCheckForOverflowTy = BuiltinIntegerType::get(1, Context); - TupleTypeElt ArgElts[] = { ArgType, ArgType, ShouldCheckForOverflowTy }; + Type ArgElts[] = { ArgType, ArgType, ShouldCheckForOverflowTy }; Type OverflowBitTy = BuiltinIntegerType::get(1, Context); TupleTypeElt ResultElts[] = { ArgType, OverflowBitTy }; Type ResultTy = TupleType::get(ResultElts, Context); @@ -279,16 +263,14 @@ static ValueDecl *getBinaryOperationWithOverflow(Identifier Id, } static ValueDecl *getUnaryOperation(Identifier Id, Type ArgType) { - TupleTypeElt ArgElts[] = { ArgType }; - Type ResultTy = ArgType; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { ArgType }, ArgType); } /// Build a binary predicate declaration. static ValueDecl *getBinaryPredicate(Identifier Id, Type ArgType) { auto &Context = ArgType->getASTContext(); - TupleTypeElt ArgElts[] = { ArgType, ArgType }; + Type ArgElts[] = { ArgType, ArgType }; Type ResultTy = BuiltinIntegerType::get(1, Context); if (auto VecTy = ArgType->getAs()) { ResultTy = BuiltinVectorType::get(Context, ResultTy, @@ -425,8 +407,7 @@ static ValueDecl *getCastOperation(ASTContext &Context, Identifier Id, return nullptr; } - TupleTypeElt ArgElts[] = { Input }; - return getBuiltinFunction(Id, ArgElts, Output); + return getBuiltinFunction(Id, { Input }, Output); } static const char * const GenericParamNames[] = { @@ -481,7 +462,7 @@ namespace { SmallVector Archetypes; SmallVector InterfaceParams; - SmallVector BodyParams; + SmallVector BodyParams; Type InterfaceResult; Type BodyResult; @@ -692,14 +673,13 @@ static ValueDecl *getIsOptionalOperation(ASTContext &Context, Identifier Id) { static ValueDecl *getAllocOperation(ASTContext &Context, Identifier Id) { Type PtrSizeTy = BuiltinIntegerType::getWordType(Context); - TupleTypeElt ArgElts[] = { PtrSizeTy, PtrSizeTy }; Type ResultTy = Context.TheRawPointerType; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { PtrSizeTy, PtrSizeTy }, ResultTy); } static ValueDecl *getDeallocOperation(ASTContext &Context, Identifier Id) { auto PtrSizeTy = BuiltinIntegerType::getWordType(Context); - TupleTypeElt ArgElts[] = { Context.TheRawPointerType, PtrSizeTy, PtrSizeTy }; + Type ArgElts[] = { Context.TheRawPointerType, PtrSizeTy, PtrSizeTy }; Type ResultTy = TupleType::getEmpty(Context); return getBuiltinFunction(Id, ArgElts, ResultTy); } @@ -722,32 +702,26 @@ static ValueDecl *getUnexpectedErrorOperation(ASTContext &Context, static ValueDecl *getCmpXChgOperation(ASTContext &Context, Identifier Id, Type T) { - TupleTypeElt ArgElts[] = { Context.TheRawPointerType, T, T }; + Type ArgElts[] = { Context.TheRawPointerType, T, T }; Type BoolTy = BuiltinIntegerType::get(1, Context); - TupleTypeElt ResultElts[] = { T, BoolTy }; - Type ResultTy = TupleType::get(ResultElts, Context); + Type ResultTy = TupleType::get({ T, BoolTy }, Context); return getBuiltinFunction(Id, ArgElts, ResultTy); } static ValueDecl *getAtomicRMWOperation(ASTContext &Context, Identifier Id, Type T) { - TupleTypeElt ArgElts[] = { Context.TheRawPointerType, T }; - Type ResultTy = T; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { Context.TheRawPointerType, T }, T); } static ValueDecl *getAtomicLoadOperation(ASTContext &Context, Identifier Id, Type T) { - TupleTypeElt ArgElts[] = { Context.TheRawPointerType }; - Type ResultTy = T; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { Type(Context.TheRawPointerType) }, T); } static ValueDecl *getAtomicStoreOperation(ASTContext &Context, Identifier Id, Type T) { - TupleTypeElt ArgElts[] = { Context.TheRawPointerType, T }; - Type ResultTy = Context.TheEmptyTupleType; - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { Context.TheRawPointerType, T }, + Context.TheEmptyTupleType); } static ValueDecl *getNativeObjectCast(ASTContext &Context, Identifier Id, @@ -790,8 +764,6 @@ static ValueDecl *getCastFromBridgeObjectOperation(ASTContext &C, Identifier Id, BuiltinValueKind BV) { Type BridgeTy = C.TheBridgeObjectType; - TupleTypeElt ArgElts[] = { BridgeTy }; - switch (BV) { case BuiltinValueKind::CastReferenceFromBridgeObject: { GenericSignatureBuilder builder(C); @@ -802,7 +774,7 @@ static ValueDecl *getCastFromBridgeObjectOperation(ASTContext &C, case BuiltinValueKind::CastBitPatternFromBridgeObject: { Type WordTy = BuiltinIntegerType::get(BuiltinIntegerWidth::pointer(), C); - return getBuiltinFunction(Id, ArgElts, WordTy); + return getBuiltinFunction(Id, { BridgeTy }, WordTy); } default: @@ -830,15 +802,6 @@ static ValueDecl *getReinterpretCastOperation(ASTContext &ctx, return builder.build(name); } -static ValueDecl *getMarkDependenceOperation(ASTContext &ctx, Identifier name) { - // (T,U) -> T - GenericSignatureBuilder builder(ctx, 2); - builder.addParameter(makeGenericParam(0)); - builder.addParameter(makeGenericParam(1)); - builder.setResult(makeGenericParam(0)); - return builder.build(name); -} - static ValueDecl *getZeroInitializerOperation(ASTContext &Context, Identifier Id) { // () -> T @@ -868,16 +831,13 @@ static ValueDecl *getCondFailOperation(ASTContext &C, Identifier Id) { // Int1 -> () auto CondTy = BuiltinIntegerType::get(1, C); auto VoidTy = TupleType::getEmpty(C); - TupleTypeElt CondElt(CondTy); - return getBuiltinFunction(Id, CondElt, VoidTy); + return getBuiltinFunction(Id, {CondTy}, VoidTy); } static ValueDecl *getAssertConfOperation(ASTContext &C, Identifier Id) { // () -> Int32 auto Int32Ty = BuiltinIntegerType::get(32, C); - auto VoidTy = TupleType::getEmpty(C); - TupleTypeElt EmptyElt(VoidTy); - return getBuiltinFunction(Id, EmptyElt, Int32Ty); + return getBuiltinFunction(Id, {}, Int32Ty); } static ValueDecl *getFixLifetimeOperation(ASTContext &C, Identifier Id) { @@ -899,9 +859,8 @@ static ValueDecl *getExtractElementOperation(ASTContext &Context, Identifier Id, if (!IndexTy || !IndexTy->isFixedWidth() || IndexTy->getFixedWidth() != 32) return nullptr; - TupleTypeElt ArgElts[] = { VecTy, IndexTy }; Type ResultTy = VecTy->getElementType(); - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { VecTy, IndexTy }, ResultTy); } static ValueDecl *getInsertElementOperation(ASTContext &Context, Identifier Id, @@ -920,16 +879,15 @@ static ValueDecl *getInsertElementOperation(ASTContext &Context, Identifier Id, if (!IndexTy || !IndexTy->isFixedWidth() || IndexTy->getFixedWidth() != 32) return nullptr; - TupleTypeElt ArgElts[] = { VecTy, ElementTy, IndexTy }; - Type ResultTy = VecTy; - return getBuiltinFunction(Id, ArgElts, ResultTy); + Type ArgElts[] = { VecTy, ElementTy, IndexTy }; + return getBuiltinFunction(Id, ArgElts, VecTy); } static ValueDecl *getStaticReportOperation(ASTContext &Context, Identifier Id) { auto BoolTy = BuiltinIntegerType::get(1, Context); auto MessageTy = Context.TheRawPointerType; - TupleTypeElt ArgElts[] = { BoolTy, BoolTy, MessageTy }; + Type ArgElts[] = { BoolTy, BoolTy, MessageTy }; Type ResultTy = TupleType::getEmpty(Context); return getBuiltinFunction(Id, ArgElts, ResultTy); @@ -946,12 +904,10 @@ static ValueDecl *getCheckedTruncOperation(ASTContext &Context, if (InTy->getLeastWidth() < OutTy->getGreatestWidth()) return nullptr; - TupleTypeElt ArgElts[] = { InTy }; Type OverflowBitTy = BuiltinIntegerType::get(1, Context); TupleTypeElt ResultElts[] = { OutTy, OverflowBitTy }; Type ResultTy = TupleType::get(ResultElts, Context); - - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { InTy }, ResultTy); } static ValueDecl *getCheckedConversionOperation(ASTContext &Context, @@ -961,12 +917,10 @@ static ValueDecl *getCheckedConversionOperation(ASTContext &Context, if (!BuiltinTy) return nullptr; - TupleTypeElt ArgElts[] = { BuiltinTy }; Type SignErrorBitTy = BuiltinIntegerType::get(1, Context); TupleTypeElt ResultElts[] = { BuiltinTy, SignErrorBitTy }; Type ResultTy = TupleType::get(ResultElts, Context); - - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { BuiltinTy }, ResultTy); } static ValueDecl *getIntToFPWithOverflowOperation(ASTContext &Context, @@ -977,10 +931,7 @@ static ValueDecl *getIntToFPWithOverflowOperation(ASTContext &Context, if (!InTy || !OutTy) return nullptr; - TupleTypeElt ArgElts[] = { InTy }; - Type ResultTy = OutTy; - - return getBuiltinFunction(Id, ArgElts, ResultTy); + return getBuiltinFunction(Id, { InTy }, OutTy); } static ValueDecl *getUnreachableOperation(ASTContext &Context, @@ -1001,11 +952,7 @@ static ValueDecl *getOnceOperation(ASTContext &Context, /*noreturn*/ false, /*throws*/ false); auto BlockTy = FunctionType::get(VoidTy, VoidTy, Thin); - - TupleTypeElt InFields[] = {HandleTy, BlockTy}; - auto OutTy = VoidTy; - - return getBuiltinFunction(Id, InFields, OutTy); + return getBuiltinFunction(Id, {HandleTy, BlockTy}, VoidTy); } static ValueDecl *getTryPinOperation(ASTContext &ctx, Identifier name) { @@ -1017,59 +964,6 @@ static ValueDecl *getTryPinOperation(ASTContext &ctx, Identifier name) { return builder.build(name); } -static ValueDecl *getProjectValueBufferOperation(ASTContext &ctx, - Identifier name) { - // (inout Builtin.UnsafeValueBuffer, T.Type) -> Builtin.RawPointer - GenericSignatureBuilder builder(ctx); - builder.addParameter(makeConcrete( - InOutType::get(ctx.TheUnsafeValueBufferType))); - builder.addParameter(makeMetatype(makeGenericParam())); - builder.setResult(makeConcrete(ctx.TheRawPointerType)); - return builder.build(name); -} - -static ValueDecl *getDeallocValueBufferOperation(ASTContext &ctx, - Identifier name) { - // (inout Builtin.UnsafeValueBuffer, T.Type) -> () - GenericSignatureBuilder builder(ctx); - builder.addParameter(makeConcrete( - InOutType::get(ctx.TheUnsafeValueBufferType))); - builder.addParameter(makeMetatype(makeGenericParam())); - builder.setResult(makeConcrete(ctx.TheRawPointerType)); - return builder.build(name); -} - -static ValueDecl * -getMakeMaterializeForSetCallbackOperation(ASTContext &ctx, Identifier name) { - // ((Builtin.RawPointer, - // inout Builtin.UnsafeValueBuffer, - // inout T, - // T.Type) -> ()) - // -> - // @convention(thin) ((Builtin.RawPointer, - // inout Builtin.UnsafeValueBuffer, - // inout T, - // @thick T.Type) -> ()) - GenericSignatureBuilder builder(ctx); - builder.addParameter( - makeFunction( - makeTuple(makeConcrete(ctx.TheRawPointerType), - makeConcrete(InOutType::get(ctx.TheUnsafeValueBufferType)), - makeInOut(makeGenericParam()), - makeMetatype(makeGenericParam())), - makeConcrete(TupleType::getEmpty(ctx)))); - builder.setResult( - makeFunction( - makeTuple(makeConcrete(ctx.TheRawPointerType), - makeConcrete(InOutType::get(ctx.TheUnsafeValueBufferType)), - makeInOut(makeGenericParam()), - makeMetatype(makeGenericParam(), MetatypeRepresentation::Thick)), - makeConcrete(TupleType::getEmpty(ctx)), - FunctionType::ExtInfo() - .withRepresentation(FunctionType::Representation::Thin))); - return builder.build(name); -} - /// An array of the overloaded builtin kinds. static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::None, @@ -1232,7 +1126,7 @@ static Type DecodeIntrinsicType(ArrayRef &Table, static bool getSwiftFunctionTypeForIntrinsic(unsigned iid, ArrayRef TypeArgs, ASTContext &Context, - SmallVectorImpl &ArgElts, + SmallVectorImpl &ArgElts, Type &ResultTy, FunctionType::ExtInfo &Info) { llvm::Intrinsic::ID ID = (llvm::Intrinsic::ID)iid; @@ -1327,7 +1221,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { // If this is the name of an LLVM intrinsic, cons up a swift function with a // type that matches the IR types. if (unsigned ID = getLLVMIntrinsicID(OperationName, !Types.empty())) { - SmallVector ArgElts; + SmallVector ArgElts; Type ResultTy; FunctionType::ExtInfo Info; if (getSwiftFunctionTypeForIntrinsic(ID, Types, Context, ArgElts, ResultTy, @@ -1598,9 +1492,6 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::DeallocRaw: return getDeallocOperation(Context, Id); - case BuiltinValueKind::MarkDependence: - return getMarkDependenceOperation(Context, Id); - case BuiltinValueKind::CastToNativeObject: case BuiltinValueKind::CastFromNativeObject: case BuiltinValueKind::CastToUnknownObject: @@ -1625,19 +1516,6 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::ReinterpretCast: if (!Types.empty()) return nullptr; return getReinterpretCastOperation(Context, Id); - - case BuiltinValueKind::AllocValueBuffer: - case BuiltinValueKind::ProjectValueBuffer: - if (!Types.empty()) return nullptr; - return getProjectValueBufferOperation(Context, Id); - - case BuiltinValueKind::DeallocValueBuffer: - if (!Types.empty()) return nullptr; - return getDeallocValueBufferOperation(Context, Id); - - case BuiltinValueKind::MakeMaterializeForSetCallback: - if (!Types.empty()) return nullptr; - return getMakeMaterializeForSetCallbackOperation(Context, Id); case BuiltinValueKind::AddressOf: if (!Types.empty()) return nullptr; diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index f4f888a1e72d2..b1624ba4f6b64 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,6 +4,7 @@ add_swift_library(swiftAST ASTDumper.cpp ASTNode.cpp ASTPrinter.cpp + ASTVerifier.cpp ASTWalker.cpp Attr.cpp Availability.cpp @@ -14,6 +15,8 @@ add_swift_library(swiftAST ConformanceLookupTable.cpp Decl.cpp DeclContext.cpp + DeclNameLoc.cpp + DefaultArgumentKind.cpp DiagnosticList.cpp DiagnosticEngine.cpp DocComment.cpp @@ -25,6 +28,7 @@ add_swift_library(swiftAST Module.cpp ModuleNameLookup.cpp NameLookup.cpp + Parameter.cpp Pattern.cpp PlatformKind.cpp PrettyStackTrace.cpp @@ -37,7 +41,6 @@ add_swift_library(swiftAST TypeRepr.cpp TypeWalker.cpp USRGeneration.cpp - Verifier.cpp LINK_LIBRARIES swiftMarkup swiftBasic diff --git a/lib/AST/CaptureInfo.cpp b/lib/AST/CaptureInfo.cpp index 21b51e4871497..6de67d3a0ce5d 100644 --- a/lib/AST/CaptureInfo.cpp +++ b/lib/AST/CaptureInfo.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/ConcreteDeclRef.cpp b/lib/AST/ConcreteDeclRef.cpp index 55813deac9ba8..e8efb3c895aa7 100644 --- a/lib/AST/ConcreteDeclRef.cpp +++ b/lib/AST/ConcreteDeclRef.cpp @@ -1,8 +1,8 @@ -//===--- ConcreteDeclRef.cpp - Reference to a concrete decl -----*- C++ -*-===// +//===--- ConcreteDeclRef.cpp - Reference to a concrete decl ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,23 +50,22 @@ void ConcreteDeclRef::dump(raw_ostream &os) { os << ", "; } - os << sub.getArchetype()->getFullName() - << "=" << sub.getReplacement().getString(); + os << sub.getReplacement().getString(); if (sub.getConformances().size()) { os << '['; bool isFirst = true; - for (const auto *c : sub.getConformances()) { + for (auto &c : sub.getConformances()) { if (isFirst) { isFirst = false; } else { os << ", "; } - if (c) { - c->printName(os); + if (c.isConcrete()) { + c.getConcrete()->printName(os); } else { - os << "nullptr"; + os << "abstract:" << c.getAbstract()->getName(); } } os << ']'; diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index a063ac5977c9a..e9e12622f7c1b 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -1,8 +1,8 @@ -//===--- ConformanceLookupTable - Conformance Lookup Table ------*- C++ -*-===// +//===--- ConformanceLookupTable - Conformance Lookup Table ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -149,7 +149,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage, lastProcessed.setInt(true); // If we have conformances we can load, do so. - // FIXME: This could be more lazy. + // FIXME: This could be lazier. auto loader = nominal->takeConformanceLoader(); if (loader.first) { SmallVector conformances; @@ -179,7 +179,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage, lastProcessed.setPointer(next); // If we have conformances we can load, do so. - // FIXME: This could be more lazy. + // FIXME: This could be lazier. auto loader = next->takeConformanceLoader(); if (loader.first) { SmallVector conformances; @@ -487,10 +487,14 @@ void ConformanceLookupTable::addProtocols(NominalTypeDecl *nominal, void ConformanceLookupTable::expandImpliedConformances(NominalTypeDecl *nominal, DeclContext *dc, LazyResolver *resolver) { - // Note: recursive type-checking implies that that AllConformances + // Note: recursive type-checking implies that AllConformances // may be reallocated during this traversal, so pay the lookup cost // during each iteration. for (unsigned i = 0; i != AllConformances[dc].size(); ++i) { + /// FIXME: Avoid the possibility of an infinite loop by fixing the root + /// cause instead (incomplete circularity detection). + assert(i <= 16384 && + "Infinite loop due to circular protocol inheritance?"); ConformanceEntry *conformanceEntry = AllConformances[dc][i]; ProtocolDecl *conformingProtocol = conformanceEntry->getProtocol(); diff --git a/lib/AST/ConformanceLookupTable.h b/lib/AST/ConformanceLookupTable.h index 63493b9323278..dbe5569b66504 100644 --- a/lib/AST/ConformanceLookupTable.h +++ b/lib/AST/ConformanceLookupTable.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1b78086da037d..79350e845c243 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,8 @@ #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Mangle.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/ResilienceExpansion.h" #include "swift/AST/TypeLoc.h" #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/SmallString.h" @@ -72,13 +74,13 @@ const clang::Module *ClangNode::getClangModule() const { } // Only allow allocation of Decls using the allocator in ASTContext. -void *Decl::operator new(size_t Bytes, ASTContext &C, +void *Decl::operator new(size_t Bytes, const ASTContext &C, unsigned Alignment) { return C.Allocate(Bytes, Alignment); } // Only allow allocation of Modules using the allocator in ASTContext. -void *Module::operator new(size_t Bytes, ASTContext &C, +void *Module::operator new(size_t Bytes, const ASTContext &C, unsigned Alignment) { return C.Allocate(Bytes, Alignment); } @@ -398,16 +400,12 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const { FU->getKind() != FileUnitKind::SerializedAST) return false; - auto hasInternalParameter = [](ArrayRef Pats) -> bool { - bool hasInternalParam = false; - for (auto Pat : Pats) { - Pat->forEachVariable([&](VarDecl *Param) { - if (Param->hasName() && Param->getNameStr().startswith("_")) { - hasInternalParam = true; - } - }); + auto hasInternalParameter = [](const ParameterList *params) -> bool { + for (auto param : *params) { + if (param->hasName() && param->getNameStr().startswith("_")) + return true; } - return hasInternalParam; + return false; }; if (auto AFD = dyn_cast(D)) { @@ -418,8 +416,9 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const { // If it's a function with a parameter with leading underscore, it's a // private function. - if (hasInternalParameter(AFD->getBodyParamPatterns())) - return true; + for (auto *PL : AFD->getParameterLists()) + if (hasInternalParameter(PL)) + return true; } if (auto SubscriptD = dyn_cast(D)) { @@ -560,16 +559,15 @@ GenericParamList::getForwardingSubstitutions(ASTContext &C) { for (auto archetype : getAllNestedArchetypes()) { // "Check conformance" on each declared protocol to build a // conformance map. - SmallVector conformances; + SmallVector conformances; - for (ProtocolDecl *conformsTo : archetype->getConformsTo()) { - (void)conformsTo; - conformances.push_back(nullptr); + for (ProtocolDecl *proto : archetype->getConformsTo()) { + conformances.push_back(ProtocolConformanceRef(proto)); } // Build an identity mapping with the derived conformances. auto replacement = SubstitutedType::get(archetype, archetype, C); - subs.push_back({archetype, replacement, C.AllocateCopy(conformances)}); + subs.push_back({replacement, C.AllocateCopy(conformances)}); } return C.AllocateCopy(subs); @@ -643,7 +641,7 @@ GenericParamList::getAsGenericSignatureElements(ASTContext &C, // Collect conformance requirements declared on the archetype. if (auto super = archetype->getSuperclass()) { - requirements.push_back(Requirement(RequirementKind::Conformance, + requirements.push_back(Requirement(RequirementKind::Superclass, typeParamTy, super)); } for (auto proto : archetype->getConformsTo()) { @@ -661,8 +659,8 @@ GenericParamList::getAsGenericSignatureElements(ASTContext &C, // Add conformance requirements for this associated archetype. for (const auto &repr : getRequirements()) { - // Handle same-type requirements at last. - if (repr.getKind() != RequirementKind::Conformance) + // Handle same-type requirements later. + if (repr.getKind() != RequirementReprKind::TypeConstraint) continue; // Primary conformance declarations would have already been gathered as @@ -671,13 +669,21 @@ GenericParamList::getAsGenericSignatureElements(ASTContext &C, if (!arch->getParent()) continue; - auto depTyOfReqt = getAsDependentType(repr.getSubject(), archetypeMap); - if (depTyOfReqt.getPointer() != depTy.getPointer()) + Type subject = getAsDependentType(repr.getSubject(), archetypeMap); + if (subject.getPointer() != depTy.getPointer()) continue; - Requirement reqt(RequirementKind::Conformance, - getAsDependentType(repr.getSubject(), archetypeMap), - getAsDependentType(repr.getConstraint(), archetypeMap)); + Type constraint = + getAsDependentType(repr.getConstraint(), archetypeMap); + + RequirementKind kind; + if (constraint->getClassOrBoundGenericClass()) { + kind = RequirementKind::Superclass; + } else { + kind = RequirementKind::Conformance; + } + + Requirement reqt(kind, subject, constraint); requirements.push_back(reqt); } } @@ -1012,6 +1018,17 @@ PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc, static_cast(StaticSpelling); } +PatternBindingDecl * +PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + SourceLoc VarLoc, + Pattern *Pat, Expr *E, + DeclContext *Parent) { + return create(Ctx, StaticLoc, StaticSpelling, VarLoc, + PatternBindingEntry(Pat, E), + Parent); +} + PatternBindingDecl * PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -1031,7 +1048,7 @@ PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc, for (auto pe : PatternList) { ++elt; auto &newEntry = entries[elt]; - newEntry = { nullptr, pe.getInit() }; + newEntry = pe; // This should take care of initializer with flags PBD->setPattern(elt, pe.getPattern()); } return PBD; @@ -1066,6 +1083,20 @@ unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) c return ~0U; } +SourceRange PatternBindingEntry::getOrigInitRange() const { + auto Init = InitCheckedAndRemoved.getPointer(); + return Init ? Init->getSourceRange() : SourceRange(); +} + +void PatternBindingEntry::setInit(Expr *E) { + auto F = InitCheckedAndRemoved.getInt(); + if (E) { + InitCheckedAndRemoved.setInt(F - Flags::Removed); + InitCheckedAndRemoved.setPointer(E); + } else { + InitCheckedAndRemoved.setInt(F | Flags::Removed); + } +} SourceRange PatternBindingDecl::getSourceRange() const { SourceLoc startLoc = getStartLoc(); @@ -1169,10 +1200,24 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) { llvm_unreachable("bad DeclKind"); } +static ResilienceExpansion getResilienceExpansion(const DeclContext *DC) { + if (auto *AFD = dyn_cast(DC)) + if (AFD->isTransparent() && + AFD->getFormalAccess() == Accessibility::Public) + return ResilienceExpansion::Minimal; + + return ResilienceExpansion::Maximal; +} + /// Determines the access semantics to use in a DeclRefExpr or /// MemberRefExpr use of this value in the specified context. AccessSemantics ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC) const { + // If we're inside a @_transparent function, use the most conservative + // access pattern, since we may be inlined from a different resilience + // domain. + ResilienceExpansion expansion = getResilienceExpansion(UseDC); + if (auto *var = dyn_cast(this)) { // Observing member are accessed directly from within their didSet/willSet // specifiers. This prevents assignments from becoming infinite loops. @@ -1183,7 +1228,7 @@ ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC) const { // "StoredWithTrivialAccessors" are generally always accessed indirectly, // but if we know that the trivial accessor will always produce the same - // thing as the getter/setter (i.e., it can't be overriden), then just do a + // thing as the getter/setter (i.e., it can't be overridden), then just do a // direct access. // // This is true in structs and for final properties. @@ -1201,12 +1246,10 @@ ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC) const { if (isPolymorphic(var)) return AccessSemantics::Ordinary; - // If the property is defined in a nominal type which must be accessed - // resiliently from the current module, we cannot do direct access. - auto VarDC = var->getDeclContext(); - if (auto *nominal = VarDC->isNominalTypeOrNominalTypeExtensionContext()) - if (!nominal->hasFixedLayout(UseDC->getParentModule())) - return AccessSemantics::Ordinary; + // If the property does not have a fixed layout from the given context, + // we cannot do direct access. + if (!var->hasFixedLayout(UseDC->getParentModule(), expansion)) + return AccessSemantics::Ordinary; // We know enough about the property to perform direct access. return AccessSemantics::DirectToStorage; @@ -1280,8 +1323,8 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics, case StoredWithTrivialAccessors: case AddressedWithTrivialAccessors: { - // If the property is defined in a non-final class or a protocol, the - // accessors are dynamically dispatched, and we cannot do direct access. + // If the property is defined in a non-final class or a protocol, the + // accessors are dynamically dispatched, and we cannot do direct access. if (isPolymorphic(this)) return AccessStrategy::DispatchToAccessor; @@ -1289,16 +1332,14 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics, // from some resilience domain, we cannot do direct access. // // As an optimization, we do want to perform direct accesses of stored - // properties of resilient types in the same resilience domain as the - // access. + // properties declared inside the same resilience domain as the access + // context. // // This is done by using DirectToStorage semantics above, with the // understanding that the access semantics are with respect to the // resilience domain of the accessor's caller. - auto DC = getDeclContext(); - if (auto *nominal = DC->isNominalTypeOrNominalTypeExtensionContext()) - if (!nominal->hasFixedLayout()) - return AccessStrategy::DirectToAccessor; + if (!hasFixedLayout()) + return AccessStrategy::DirectToAccessor; if (storageKind == StoredWithObservers || storageKind == StoredWithTrivialAccessors) { @@ -1327,6 +1368,39 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics, llvm_unreachable("bad access semantics"); } +bool AbstractStorageDecl::hasFixedLayout() const { + // Private and internal variables always have a fixed layout. + // TODO: internal variables with availability information need to be + // resilient, since they can be used from @_transparent functions. + if (getFormalAccess() != Accessibility::Public) + return true; + + // Check for an explicit @_fixed_layout attribute. + if (getAttrs().hasAttribute()) + return true; + + // If we're in a nominal type, just query the type. + auto nominal = getDeclContext()->isNominalTypeOrNominalTypeExtensionContext(); + if (nominal) + return nominal->hasFixedLayout(); + + // Must use resilient access patterns. + assert(getDeclContext()->isModuleScopeContext()); + return !getDeclContext()->getParentModule()->isResilienceEnabled(); +} + +bool AbstractStorageDecl::hasFixedLayout(ModuleDecl *M, + ResilienceExpansion expansion) const { + switch (expansion) { + case ResilienceExpansion::Minimal: + return hasFixedLayout(); + case ResilienceExpansion::Maximal: + return hasFixedLayout() || M == getModuleContext(); + } + llvm_unreachable("bad resilience expansion"); +} + + bool ValueDecl::isDefinition() const { switch (getKind()) { case DeclKind::Import: @@ -1550,7 +1624,7 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type, for (const auto &elt : tupleTy->getElements()) { Type eltTy = mapSignatureParamType(ctx, elt.getType()); if (anyChanged || eltTy.getPointer() != elt.getType().getPointer() || - elt.hasInit()) { + elt.getDefaultArgKind() != DefaultArgumentKind::None) { if (!anyChanged) { elements.reserve(tupleTy->getNumElements()); for (unsigned i = 0; i != idx; ++i) { @@ -1619,7 +1693,7 @@ OverloadSignature ValueDecl::getOverloadSignature() const { /*topLevelFunction=*/true, /*isMethod=*/afd->getImplicitSelfDecl() != nullptr, /*isInitializer=*/isa(afd), - afd->getNumParamPatterns())->getCanonicalType(); + afd->getNumParameterLists())->getCanonicalType(); signature.IsInstanceMember = isInstanceMember(); // Unary operators also include prefix/postfix. @@ -1737,19 +1811,6 @@ void ValueDecl::overwriteType(Type T) { setInvalid(); } -DeclContext *ValueDecl::getPotentialGenericDeclContext() { - if (auto func = dyn_cast(this)) - return func; - if (auto NTD = dyn_cast(this)) - return NTD; - - auto parentDC = getDeclContext(); - if (parentDC->isTypeContext()) - return parentDC; - - return nullptr; -} - Type ValueDecl::getInterfaceType() const { if (InterfaceTy) return InterfaceTy; @@ -1761,9 +1822,9 @@ Type ValueDecl::getInterfaceType() const { auto proto = cast(getDeclContext()); (void)proto->getType(); // make sure we've computed the type. // FIXME: the generic parameter types list should never be empty. - auto selfTy = proto->getGenericParamTypes().empty() + auto selfTy = proto->getInnermostGenericParamTypes().empty() ? proto->getProtocolSelf()->getType() - : proto->getGenericParamTypes().back(); + : proto->getInnermostGenericParamTypes().back(); auto &ctx = getASTContext(); InterfaceTy = DependentMemberType::get( selfTy, @@ -1850,27 +1911,31 @@ bool NominalTypeDecl::hasFixedLayout() const { if (getAttrs().hasAttribute()) return true; - if (hasClangNode()) { - // Classes imported from Objective-C *never* have a fixed layout. - // IRGen needs to use dynamic ivar layout to ensure that subclasses - // of Objective-C classes are resilient against base class size - // changes. - if (isa(this)) - return false; - - // Structs and enums imported from C *always* have a fixed layout. - // We know their size, and pass them as values in SIL and IRGen. + // Structs and enums imported from C *always* have a fixed layout. + // We know their size, and pass them as values in SIL and IRGen. + if (hasClangNode()) return true; - } - // Objective-C enums always have a fixed layout. + // @objc enums always have a fixed layout. if (isa(this) && isObjC()) return true; // Otherwise, access via indirect "resilient" interfaces. - return false; + return !getParentModule()->isResilienceEnabled(); +} + +bool NominalTypeDecl::hasFixedLayout(ModuleDecl *M, + ResilienceExpansion expansion) const { + switch (expansion) { + case ResilienceExpansion::Minimal: + return hasFixedLayout(); + case ResilienceExpansion::Maximal: + return hasFixedLayout() || M == getModuleContext(); + } + llvm_unreachable("bad resilience expansion"); } + /// Provide the set of parameters to a generic type, or null if /// this function is not generic. void NominalTypeDecl::setGenericParams(GenericParamList *params) { @@ -2285,7 +2350,7 @@ bool ClassDecl::inheritsSuperclassInitializers(LazyResolver *resolver) { } // All of the direct superclass's designated initializers have been overridden - // by the sublcass. Initializers can be inherited. + // by the subclass. Initializers can be inherited. ClassDeclBits.InheritsSuperclassInits = static_cast(StoredInheritsSuperclassInits::Inherited); return true; @@ -2329,25 +2394,26 @@ ObjCClassKind ClassDecl::checkObjCAncestry() const { static StringRef mangleObjCRuntimeName(const NominalTypeDecl *nominal, llvm::SmallVectorImpl &buffer) { { - buffer.clear(); - llvm::raw_svector_ostream os(buffer); + // Mangle the type. + Mangle::Mangler mangler(false/*dwarf*/, false/*punycode*/); // We add the "_Tt" prefix to make this a reserved name that will // not conflict with any valid Objective-C class or protocol name. - os << "_Tt"; + mangler.append("_Tt"); - // Mangle the type. - Mangle::Mangler mangler(os, false/*dwarf*/, false/*punycode*/); NominalTypeDecl *NTD = const_cast(nominal); if (isa(nominal)) { - mangler.mangleNominalType(NTD, - ResilienceExpansion::Minimal, - Mangle::Mangler::BindGenerics::None); + mangler.mangleNominalType(NTD, Mangle::Mangler::BindGenerics::None); } else { mangler.mangleProtocolDecl(cast(NTD)); } + + buffer.clear(); + llvm::raw_svector_ostream os(buffer); + mangler.finalize(os); } + assert(buffer.size() && "Invalid buffer size"); return StringRef(buffer.data(), buffer.size()); } @@ -2485,7 +2551,7 @@ bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const { bool ProtocolDecl::requiresClassSlow() { ProtocolDeclBits.RequiresClass = false; - // Ensure that the result can not change in future. + // Ensure that the result cannot change in future. assert(isInheritedProtocolsValid() || isBeingTypeChecked()); if (getAttrs().hasAttribute() || isObjC()) { @@ -3164,12 +3230,13 @@ SourceRange VarDecl::getSourceRange() const { } SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const { - Pattern *Pat = nullptr; - if (ParentPattern.is()) - Pat = ParentPattern.dyn_cast(); - else - Pat = getParentPattern(); + // For a parameter, map back to its parameter to get the TypeLoc. + if (auto *PD = dyn_cast(this)) { + if (auto typeRepr = PD->getTypeLoc().getTypeRepr()) + return typeRepr->getSourceRange(); + } + Pattern *Pat = getParentPattern(); if (!Pat || Pat->isImplicit()) return getSourceRange(); @@ -3231,8 +3298,11 @@ Pattern *VarDecl::getParentPattern() const { return nullptr; } -bool VarDecl::isImplicitSelf() const { - return isImplicit() && getName() == getASTContext().Id_self; +bool VarDecl::isSelfParameter() const { + // Note: we need to check the isImplicit() bit here to make sure that we + // don't classify explicit parameters declared with `self` as the self param. + return isa(this) && getName() == getASTContext().Id_self && + isImplicit(); } /// Return true if this stored property needs to be accessed with getters and @@ -3312,12 +3382,9 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { // If it isn't a 'let', don't touch it. if (!isLet()) return; - // Don't suggest mutability for explicit function parameters - if (isa(this) && !isImplicitSelf()) return; - // If this is the 'self' argument of a non-mutating method in a value type, // suggest adding 'mutating' to the method. - if (isImplicitSelf() && UseDC) { + if (isSelfParameter() && UseDC) { // If the problematic decl is 'self', then we might be trying to mutate // a property in a non-mutating method. auto FD = dyn_cast(UseDC->getInnermostMethodContext()); @@ -3331,6 +3398,9 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { } } + // Besides self, don't suggest mutability for explicit function parameters. + if (isa(this)) return; + // If this is a normal variable definition, then we can change 'let' to 'var'. // We even are willing to suggest this for multi-variable binding, like // "let (a,b) = " @@ -3347,6 +3417,123 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { } } +ParamDecl::ParamDecl(bool isLet, + SourceLoc letVarInOutLoc, SourceLoc argumentNameLoc, + Identifier argumentName, SourceLoc parameterNameLoc, + Identifier parameterName, Type ty, DeclContext *dc) + : VarDecl(DeclKind::Param, /*IsStatic=*/false, isLet, parameterNameLoc, + parameterName, ty, dc), + ArgumentName(argumentName), ArgumentNameLoc(argumentNameLoc), + LetVarInOutLoc(letVarInOutLoc) { +} + +/// Clone constructor, allocates a new ParamDecl identical to the first. +/// Intentionally not defined as a copy constructor to avoid accidental copies. +ParamDecl::ParamDecl(ParamDecl *PD) + : VarDecl(DeclKind::Param, /*IsStatic=*/false, PD->isLet(), PD->getNameLoc(), + PD->getName(), PD->hasType() ? PD->getType() : Type(), + PD->getDeclContext()), + ArgumentName(PD->getArgumentName()), + ArgumentNameLoc(PD->getArgumentNameLoc()), + LetVarInOutLoc(PD->getLetVarInOutLoc()), + typeLoc(PD->getTypeLoc()), + DefaultValueAndIsVariadic(PD->DefaultValueAndIsVariadic), + IsTypeLocImplicit(PD->IsTypeLocImplicit), + defaultArgumentKind(PD->defaultArgumentKind) { +} + + +/// \brief Retrieve the type of 'self' for the given context. +static Type getSelfTypeForContext(DeclContext *dc) { + // For a protocol or extension thereof, the type is 'Self'. + // FIXME: Weird that we're producing an archetype for protocol Self, + // but the declared type of the context in non-protocol cases. + if (dc->isProtocolOrProtocolExtensionContext()) { + // In the parser, generic parameters won't be wired up yet, just give up on + // producing a type. + if (dc->getGenericParamsOfContext() == nullptr) + return Type(); + return dc->getProtocolSelf()->getArchetype(); + } + return dc->getDeclaredTypeOfContext(); +} + + +/// Create an implicit 'self' decl for a method in the specified decl context. +/// If 'static' is true, then this is self for a static method in the type. +/// +/// Note that this decl is created, but it is returned with an incorrect +/// DeclContext that needs to be set correctly. This is automatically handled +/// when a function is created with this as part of its argument list. +/// +ParamDecl *ParamDecl::createSelf(SourceLoc loc, DeclContext *DC, + bool isStaticMethod, bool isInOut) { + ASTContext &C = DC->getASTContext(); + auto selfType = getSelfTypeForContext(DC); + + // If we have a selfType (i.e. we're not in the parser before we know such + // things, configure it. + if (selfType) { + if (isStaticMethod) + selfType = MetatypeType::get(selfType); + + if (isInOut) + selfType = InOutType::get(selfType); + } + + auto *selfDecl = new (C) ParamDecl(/*IsLet*/!isInOut, SourceLoc(),SourceLoc(), + Identifier(), loc, C.Id_self, selfType,DC); + selfDecl->setImplicit(); + return selfDecl; +} + +/// Return the full source range of this parameter. +SourceRange ParamDecl::getSourceRange() const { + SourceRange range; + + SourceLoc APINameLoc = getArgumentNameLoc(); + SourceLoc nameLoc = getNameLoc(); + + if (APINameLoc.isValid() && nameLoc.isInvalid()) + range = APINameLoc; + else if (APINameLoc.isInvalid() && nameLoc.isValid()) + range = nameLoc; + else + range = SourceRange(APINameLoc, nameLoc); + + if (range.isInvalid()) return range; + + // It would be nice to extend the front of the range to show where inout is, + // but we don't have that location info. Extend the back of the range to the + // location of the default argument, or the typeloc if they are valid. + if (auto expr = getDefaultValue()) { + auto endLoc = expr->getExpr()->getEndLoc(); + if (endLoc.isValid()) + return SourceRange(range.Start, endLoc); + } + + // If the typeloc has a valid location, use it to end the range. + if (auto typeRepr = getTypeLoc().getTypeRepr()) { + auto endLoc = typeRepr->getEndLoc(); + if (endLoc.isValid() && !isTypeLocImplicit()) + return SourceRange(range.Start, endLoc); + } + + // Otherwise, just return the info we have about the parameter. + return range; +} + +Type ParamDecl::getVarargBaseTy(Type VarArgT) { + TypeBase *T = VarArgT.getPointer(); + if (ArraySliceType *AT = dyn_cast(T)) + return AT->getBaseType(); + if (BoundGenericType *BGT = dyn_cast(T)) { + // It's the stdlib Array. + return BGT->getGenericArgs()[0]; + } + assert(isa(T)); + return T; +} /// Determine whether the given Swift type is an integral type, i.e., /// a type that wraps a builtin integer. @@ -3377,14 +3564,18 @@ static bool isIntegralType(Type type) { return false; } -void SubscriptDecl::setIndices(Pattern *p) { +void SubscriptDecl::setIndices(ParameterList *p) { Indices = p; - // FIXME: What context should the indices patterns be in? + if (Indices) + Indices->setDeclContextOfParamDecls(this); } Type SubscriptDecl::getIndicesType() const { - return getType()->castTo()->getInput(); + const auto type = getType(); + if (type->is()) + return type; + return type->castTo()->getInput(); } Type SubscriptDecl::getIndicesInterfaceType() const { @@ -3519,7 +3710,8 @@ DeclName AbstractFunctionDecl::getEffectiveFullName() const { case AccessorKind::IsMutableAddressor: case AccessorKind::IsGetter: return subscript ? subscript->getFullName() - : DeclName(ctx, afd->getName(), { }); + : DeclName(ctx, afd->getName(), + ArrayRef()); case AccessorKind::IsSetter: case AccessorKind::IsMaterializeForSet: @@ -3567,19 +3759,14 @@ Type AbstractFunctionDecl::computeInterfaceSelfType(bool isInitializingCtor) { /// /// Note that some functions don't have an implicit 'self' decl, for example, /// free functions. In this case nullptr is returned. -VarDecl *AbstractFunctionDecl::getImplicitSelfDecl() const { - ArrayRef ParamPatterns = getBodyParamPatterns(); - if (ParamPatterns.empty()) +ParamDecl *AbstractFunctionDecl::getImplicitSelfDecl() { + auto paramLists = getParameterLists(); + if (paramLists.empty()) return nullptr; - // "self" is represented as (typed_pattern (named_pattern (var_decl 'self')). - const Pattern *P = ParamPatterns[0]->getSemanticsProvidingPattern(); - - // The decl should be named 'self' and be implicit. - auto NP = dyn_cast(P); - if (NP && NP->isImplicit() && - NP->getDecl()->getName() == getASTContext().Id_self) - return NP->getDecl(); + // "self" is always the first parameter list. + if (paramLists[0]->size() == 1 && paramLists[0]->get(0)->isSelfParameter()) + return paramLists[0]->get(0); return nullptr; } @@ -3589,43 +3776,21 @@ Type AbstractFunctionDecl::getExtensionType() const { std::pair AbstractFunctionDecl::getDefaultArg(unsigned Index) const { - ArrayRef Patterns = getBodyParamPatterns(); - - if (getImplicitSelfDecl()) { - // Skip the 'self' parameter; it is not counted. - Patterns = Patterns.slice(1); - } - - // Find the (sub-)pattern for this index. - // FIXME: This is O(n), which is lame. We should fix the FuncDecl - // representation. - const TuplePatternElt *Found = nullptr; - for (auto OrigPattern : Patterns) { - auto Params = - dyn_cast(OrigPattern->getSemanticsProvidingPattern()); - if (!Params) { - if (Index == 0) { - return { DefaultArgumentKind::None, Type() }; - } + auto paramLists = getParameterLists(); - --Index; - continue; - } + if (getImplicitSelfDecl()) // Skip the 'self' parameter; it is not counted. + paramLists = paramLists.slice(1); - for (auto &Elt : Params->getElements()) { - if (Index == 0) { - Found = &Elt; - break; - } - --Index; + for (auto paramList : paramLists) { + if (Index < paramList->size()) { + auto param = paramList->get(Index); + return { param->getDefaultArgumentKind(), param->getType() }; } - - if (Found) - break; + + Index -= paramList->size(); } - assert(Found && "No argument with this index"); - return { Found->getDefaultArgKind(), Found->getPattern()->getType() }; + llvm_unreachable("Invalid parameter index"); } bool AbstractFunctionDecl::argumentNameIsAPIByDefault(unsigned i) const { @@ -3671,15 +3836,14 @@ SourceRange AbstractFunctionDecl::getSignatureSourceRange() const { if (isImplicit()) return SourceRange(); - auto Pats = getBodyParamPatterns(); - if (Pats.empty()) + auto paramLists = getParameterLists(); + if (paramLists.empty()) return getNameLoc(); - for (int I = Pats.size() - 1; I >= 0; I--) { - auto endLoc = Pats[I]->getEndLoc(); - if (endLoc.isValid()) { + for (auto *paramList : reversed(paramLists)) { + auto endLoc = paramList->getSourceRange().End; + if (endLoc.isValid()) return SourceRange(getNameLoc(), endLoc); - } } return getNameLoc(); } @@ -3823,15 +3987,6 @@ AbstractFunctionDecl *AbstractFunctionDecl::getOverriddenDecl() const { return nullptr; } -/// Set the DeclContext of any VarDecls in P to the specified DeclContext. -static void setDeclContextOfPatternVars(Pattern *P, DeclContext *DC) { - if (!P) return; - P->forEachVariable([&](VarDecl *VD) { - assert(isa(VD) && "Pattern variable is not a parameter?"); - VD->setDeclContext(DC); - }); -} - FuncDecl *FuncDecl::createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, @@ -3876,7 +4031,7 @@ FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, SourceLoc NameLoc, SourceLoc ThrowsLoc, SourceLoc AccessorKeywordLoc, GenericParamList *GenericParams, - Type Ty, ArrayRef BodyParams, + Type Ty, ArrayRef BodyParams, TypeLoc FnRetType, DeclContext *Parent, ClangNode ClangN) { const unsigned NumParamPatterns = BodyParams.size(); @@ -3902,15 +4057,13 @@ bool FuncDecl::isExplicitNonMutating() const { !getDeclContext()->getDeclaredTypeInContext()->hasReferenceSemantics(); } -void FuncDecl::setDeserializedSignature(ArrayRef BodyParams, +void FuncDecl::setDeserializedSignature(ArrayRef BodyParams, TypeLoc FnRetType) { - MutableArrayRef BodyParamsRef = getBodyParamPatterns(); + MutableArrayRef BodyParamsRef = getParameterLists(); unsigned NumParamPatterns = BodyParamsRef.size(); #ifndef NDEBUG - unsigned NumParams = getDeclContext()->isTypeContext() - ? BodyParams[1]->numTopLevelVariables() - : BodyParams[0]->numTopLevelVariables(); + unsigned NumParams = BodyParams[getDeclContext()->isTypeContext()]->size(); auto Name = getFullName(); assert((!Name || !Name.isSimpleName()) && "Must have a simple name"); assert(!Name || (Name.getArgumentNames().size() == NumParams)); @@ -3921,7 +4074,8 @@ void FuncDecl::setDeserializedSignature(ArrayRef BodyParams, // Set the decl context of any vardecls to this FuncDecl. for (auto P : BodyParams) - setDeclContextOfPatternVars(P, this); + if (P) + P->setDeclContextOfParamDecls(this); this->FnRetType = FnRetType; } @@ -3965,12 +4119,8 @@ bool FuncDecl::isUnaryOperator() const { unsigned opArgIndex = getDeclContext()->isProtocolOrProtocolExtensionContext() ? 1 : 0; - auto *argTuple = dyn_cast(getBodyParamPatterns()[opArgIndex]); - if (!argTuple) - return true; - - return argTuple->getNumElements() == 1 && - !argTuple->getElement(0).hasEllipsis(); + auto *params = getParameterList(opArgIndex); + return params->size() == 1 && !params->get(0)->isVariadic(); } bool FuncDecl::isBinaryOperator() const { @@ -3980,19 +4130,15 @@ bool FuncDecl::isBinaryOperator() const { unsigned opArgIndex = getDeclContext()->isProtocolOrProtocolExtensionContext() ? 1 : 0; - auto *argTuple = dyn_cast(getBodyParamPatterns()[opArgIndex]); - if (!argTuple) - return false; - - return argTuple->getNumElements() == 2 - || (argTuple->getNumElements() == 1 && - argTuple->getElement(0).hasEllipsis()); + auto *params = getParameterList(opArgIndex); + return params->size() == 2 && !params->get(1)->isVariadic(); } ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, OptionalTypeKind Failability, SourceLoc FailabilityLoc, - Pattern *SelfBodyParam, Pattern *BodyParams, + ParamDecl *selfDecl, + ParameterList *BodyParams, GenericParamList *GenericParams, SourceLoc throwsLoc, DeclContext *Parent) @@ -4000,7 +4146,7 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, ConstructorLoc, 2, GenericParams), FailabilityLoc(FailabilityLoc), ThrowsLoc(throwsLoc) { - setBodyParams(SelfBodyParam, BodyParams); + setParameterLists(selfDecl, BodyParams); ConstructorDeclBits.ComputedBodyInitKind = 0; ConstructorDeclBits.InitKind @@ -4009,16 +4155,22 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, this->Failability = static_cast(Failability); } -void ConstructorDecl::setBodyParams(Pattern *selfPattern, Pattern *bodyParams) { - BodyParams[0] = selfPattern; - BodyParams[1] = bodyParams; - setDeclContextOfPatternVars(selfPattern, this); - setDeclContextOfPatternVars(bodyParams, this); +void ConstructorDecl::setParameterLists(ParamDecl *selfDecl, + ParameterList *bodyParams) { + if (selfDecl) { + ParameterLists[0] = ParameterList::createWithoutLoc(selfDecl); + ParameterLists[0]->setDeclContextOfParamDecls(this); + } else { + ParameterLists[0] = nullptr; + } + + ParameterLists[1] = bodyParams; + if (bodyParams) + bodyParams->setDeclContextOfParamDecls(this); assert(!getFullName().isSimpleName() && "Constructor name must be compound"); assert(!bodyParams || - (getFullName().getArgumentNames().size() - == bodyParams->numTopLevelVariables())); + (getFullName().getArgumentNames().size() == bodyParams->size())); } bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { @@ -4027,31 +4179,27 @@ bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { getFullName().getArgumentNames()[0].empty()) return false; - const Pattern *paramPattern = getBodyParamPatterns()[1]; - Type paramType; - if (auto tuplePattern = dyn_cast(paramPattern)) { - if (tuplePattern->getNumElements() != 1 || - tuplePattern->getElement(0).hasEllipsis()) - return false; - - paramType = tuplePattern->getElement(0).getPattern()->getType(); - } else { - paramType = paramPattern->getType(); - } + auto *params = getParameterList(1); + if (params->size() != 1) + return false; - return paramType->isVoid(); + return params->get(0)->getType()->isVoid(); } DestructorDecl::DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc, - Pattern *SelfPattern, DeclContext *Parent) + ParamDecl *selfDecl, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Destructor, Parent, NameHack, DestructorLoc, 1, nullptr) { - setSelfPattern(SelfPattern); + setSelfDecl(selfDecl); } -void DestructorDecl::setSelfPattern(Pattern *selfPattern) { - SelfPattern = selfPattern; - setDeclContextOfPatternVars(SelfPattern, this); +void DestructorDecl::setSelfDecl(ParamDecl *selfDecl) { + if (selfDecl) { + SelfParameter = ParameterList::createWithoutLoc(selfDecl); + SelfParameter->setDeclContextOfParamDecls(this); + } else { + SelfParameter = nullptr; + } } @@ -4108,9 +4256,9 @@ SourceRange FuncDecl::getSourceRange() const { getBodyResultTypeLoc().getSourceRange().End.isValid() && !this->isAccessor()) return { StartLoc, getBodyResultTypeLoc().getSourceRange().End }; - const Pattern *LastPat = getBodyParamPatterns().back(); - if (!LastPat->isImplicit()) - return { StartLoc, LastPat->getEndLoc() }; + auto LastParamListEndLoc = getParameterLists().back()->getSourceRange().End; + if (LastParamListEndLoc.isValid()) + return { StartLoc, LastParamListEndLoc }; return StartLoc; } @@ -4275,10 +4423,13 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags, if (isa(Callee)) { arg = apply->getArg(); - } else if (auto *UCE = dyn_cast(Callee)) { - arg = UCE->getSubExpr(); } else if (auto *CRE = dyn_cast(Callee)) { arg = CRE->getArg(); + } else if (auto *dotExpr = dyn_cast(Callee)) { + if (dotExpr->getName().getBaseName().str() != "init") + return { true, E }; + + arg = dotExpr->getBase(); } else { // Not a constructor call. return { true, E }; diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 5bd84fed1d23f..3a41560de97a2 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -46,6 +46,7 @@ DeclContext::isNominalTypeOrNominalTypeExtensionContext() const { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: return nullptr; @@ -107,6 +108,7 @@ Type DeclContext::getDeclaredTypeOfContext() const { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: return Type(); @@ -144,6 +146,7 @@ Type DeclContext::getDeclaredTypeInContext() const { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::Initializer: case DeclContextKind::SerializedLocal: return Type(); @@ -172,112 +175,92 @@ Type DeclContext::getDeclaredTypeInContext() const { } Type DeclContext::getDeclaredInterfaceType() const { - switch (getContextKind()) { - case DeclContextKind::Module: - case DeclContextKind::FileUnit: - case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::TopLevelCodeDecl: - case DeclContextKind::AbstractFunctionDecl: - case DeclContextKind::Initializer: - case DeclContextKind::SerializedLocal: - return Type(); - - case DeclContextKind::ExtensionDecl: - // FIXME: Need a sugar-preserving getExtendedInterfaceType for extensions - if (auto nominal = getDeclaredTypeOfContext()->getAnyNominal()) - return nominal->getDeclaredInterfaceType(); - return Type(); - - case DeclContextKind::NominalTypeDecl: - return cast(this)->getDeclaredInterfaceType(); - } - llvm_unreachable("bad DeclContextKind"); + // FIXME: Need a sugar-preserving getExtendedInterfaceType for extensions + if (auto nominal = isNominalTypeOrNominalTypeExtensionContext()) + return nominal->getDeclaredInterfaceType(); + return Type(); } GenericParamList *DeclContext::getGenericParamsOfContext() const { - switch (getContextKind()) { - case DeclContextKind::Module: - case DeclContextKind::FileUnit: - case DeclContextKind::TopLevelCodeDecl: - return nullptr; - - case DeclContextKind::SerializedLocal: - case DeclContextKind::Initializer: - case DeclContextKind::AbstractClosureExpr: - // Closures and initializers can't themselves be generic, but they - // can occur in generic contexts. - return getParent()->getGenericParamsOfContext(); - - case DeclContextKind::AbstractFunctionDecl: { - auto *AFD = cast(this); - if (auto GP = AFD->getGenericParams()) - return GP; - - // If we're within a type context, pick up the generic signature - // of that context. - if (AFD->getDeclContext()->isTypeContext()) - return AFD->getDeclContext()->getGenericParamsOfContext(); - - return nullptr; - } + for (const DeclContext *dc = this; ; dc = dc->getParent()) { + switch (dc->getContextKind()) { + case DeclContextKind::Module: + case DeclContextKind::FileUnit: + case DeclContextKind::TopLevelCodeDecl: + return nullptr; - case DeclContextKind::NominalTypeDecl: { - auto nominal = cast(this); - if (auto gp = nominal->getGenericParams()) - return gp; + case DeclContextKind::SerializedLocal: + case DeclContextKind::Initializer: + case DeclContextKind::AbstractClosureExpr: + case DeclContextKind::SubscriptDecl: + // Closures and initializers can't themselves be generic, but they + // can occur in generic contexts. + continue; - if (nominal->getDeclContext()->isTypeContext()) - return nominal->getDeclContext()->getGenericParamsOfContext(); + case DeclContextKind::AbstractFunctionDecl: { + auto *AFD = cast(dc); + if (auto GP = AFD->getGenericParams()) + return GP; + continue; + } - return nullptr; - } + case DeclContextKind::NominalTypeDecl: { + auto NTD = cast(dc); + if (auto GP = NTD->getGenericParams()) + return GP; + continue; + } - case DeclContextKind::ExtensionDecl: - return cast(this)->getGenericParams(); + case DeclContextKind::ExtensionDecl: { + auto ED = cast(dc); + if (auto GP = ED->getGenericParams()) + return GP; + continue; + } + } + llvm_unreachable("bad DeclContextKind"); } - llvm_unreachable("bad DeclContextKind"); } GenericSignature *DeclContext::getGenericSignatureOfContext() const { - switch (getContextKind()) { - case DeclContextKind::Module: - case DeclContextKind::FileUnit: - case DeclContextKind::TopLevelCodeDecl: - case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::Initializer: - case DeclContextKind::SerializedLocal: - return nullptr; + for (const DeclContext *dc = this; ; dc = dc->getParent()) { + switch (dc->getContextKind()) { + case DeclContextKind::Module: + case DeclContextKind::FileUnit: + case DeclContextKind::TopLevelCodeDecl: + return nullptr; - case DeclContextKind::AbstractFunctionDecl: { - auto *AFD = cast(this); - if (auto genericSig = AFD->getGenericSignature()) - return genericSig; - - // If we're within a type context, pick up the generic signature - // of that context. - if (AFD->getDeclContext()->isTypeContext()) - return AFD->getDeclContext()->getGenericSignatureOfContext(); - - return nullptr; - } + case DeclContextKind::Initializer: + case DeclContextKind::SerializedLocal: + case DeclContextKind::AbstractClosureExpr: + case DeclContextKind::SubscriptDecl: + // Closures and initializers can't themselves be generic, but they + // can occur in generic contexts. + continue; - case DeclContextKind::NominalTypeDecl: { - auto nominal = cast(this); - if (auto genericSig = nominal->getGenericSignature()) - return genericSig; - - // If we're within a type context, pick up the generic signature - // of that context. - if (nominal->getDeclContext()->isTypeContext()) - return nominal->getDeclContext()->getGenericSignatureOfContext(); - - return nullptr; - } + case DeclContextKind::AbstractFunctionDecl: { + auto *AFD = cast(dc); + if (auto genericSig = AFD->getGenericSignature()) + return genericSig; + continue; + } - case DeclContextKind::ExtensionDecl: - return cast(this)->getGenericSignature(); + case DeclContextKind::NominalTypeDecl: { + auto NTD = cast(dc); + if (auto genericSig = NTD->getGenericSignature()) + return genericSig; + continue; + } + + case DeclContextKind::ExtensionDecl: { + auto ED = cast(dc); + if (auto genericSig = ED->getGenericSignature()) + return genericSig; + continue; + } + } + llvm_unreachable("bad DeclContextKind"); } - llvm_unreachable("bad DeclContextKind"); } DeclContext *DeclContext::getLocalContext() { @@ -315,6 +298,7 @@ AbstractFunctionDecl *DeclContext::getInnermostMethodContext() { case DeclContextKind::Module: case DeclContextKind::NominalTypeDecl: case DeclContextKind::TopLevelCodeDecl: + case DeclContextKind::SubscriptDecl: // Not in a method context. return nullptr; } @@ -329,6 +313,7 @@ DeclContext *DeclContext::getInnermostTypeContext() { case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::SerializedLocal: Result = Result->getParent(); continue; @@ -361,6 +346,9 @@ Decl *DeclContext::getInnermostDeclarationDeclContext() { case DeclContextKind::AbstractFunctionDecl: return cast(DC); + case DeclContextKind::SubscriptDecl: + return cast(DC); + case DeclContextKind::NominalTypeDecl: return cast(DC); @@ -414,6 +402,7 @@ bool DeclContext::isGenericContext() const { case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: case DeclContextKind::SerializedLocal: + case DeclContextKind::SubscriptDecl: // Check parent context. continue; @@ -464,11 +453,7 @@ unsigned DeclContext::getGenericTypeContextDepth() const { depth++; } - // Until nominal type generic signatures are parented onto outer generic - // function signatures, we can just punt here -- the outermost nominal - // type context's generic parameters all have a depth of 0. - return 0; - // return depth; + return depth; } /// Determine whether the innermost context is generic. @@ -516,6 +501,13 @@ DeclContext::isCascadingContextForLookup(bool functionsAreNonCascading) const { break; } + case DeclContextKind::SubscriptDecl: { + auto *SD = cast(this); + if (SD->hasAccessibility()) + return SD->getFormalAccess() > Accessibility::Private; + break; + } + case DeclContextKind::Module: case DeclContextKind::FileUnit: return true; @@ -563,6 +555,8 @@ bool DeclContext::walkContext(ASTWalker &Walker) { return cast(this)->walk(Walker); case DeclContextKind::AbstractFunctionDecl: return cast(this)->walk(Walker); + case DeclContextKind::SubscriptDecl: + return cast(this)->walk(Walker); case DeclContextKind::SerializedLocal: llvm_unreachable("walk is unimplemented for deserialized contexts"); case DeclContextKind::Initializer: @@ -636,6 +630,7 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const { case DeclContextKind::AbstractFunctionDecl: Kind = "AbstractFunctionDecl"; break; + case DeclContextKind::SubscriptDecl: Kind = "SubscriptDecl"; break; } OS.indent(Depth*2 + indent) << "0x" << (void*)this << " " << Kind; @@ -683,6 +678,15 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const { OS << " : (no type set)"; break; } + case DeclContextKind::SubscriptDecl: { + auto *SD = cast(this); + OS << " name=" << SD->getName(); + if (SD->hasType()) + OS << " : " << SD->getType(); + else + OS << " : (no type set)"; + break; + } case DeclContextKind::Initializer: switch (cast(this)->getInitializerKind()) { case InitializerKind::PatternBinding: { @@ -813,13 +817,7 @@ void IterableDeclContext::loadAllMembers() const { break; } - bool hasMissingRequiredMembers = false; - resolver->loadAllMembers(const_cast< Decl *>(container), contextData, - &hasMissingRequiredMembers); - - if (hasMissingRequiredMembers) - if (auto proto = dyn_cast(this)) - const_cast(proto)->setHasMissingRequirements(true); + resolver->loadAllMembers(const_cast< Decl *>(container), contextData); --NumUnloadedLazyIterableDeclContexts; } diff --git a/lib/AST/DeclNameLoc.cpp b/lib/AST/DeclNameLoc.cpp new file mode 100644 index 0000000000000..6ebaee3c95add --- /dev/null +++ b/lib/AST/DeclNameLoc.cpp @@ -0,0 +1,39 @@ +//===--- DeclNameLoc.cpp - Declaration Name Location Info -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements the DeclNameLoc class. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/DeclNameLoc.h" +#include "swift/AST/ASTContext.h" + +using namespace swift; + +DeclNameLoc::DeclNameLoc(ASTContext &ctx, SourceLoc baseNameLoc, + SourceLoc lParenLoc, + ArrayRef argumentLabelLocs, + SourceLoc rParenLoc) + : NumArgumentLabels(argumentLabelLocs.size()) { + assert(NumArgumentLabels > 0 && "Use other constructor"); + + // Copy the location information into permanent storage. + auto storedLocs = ctx.Allocate(NumArgumentLabels + 3); + storedLocs[BaseNameIndex] = baseNameLoc; + storedLocs[LParenIndex] = lParenLoc; + storedLocs[RParenIndex] = rParenLoc; + std::memcpy(storedLocs.data() + FirstArgumentLabelIndex, + argumentLabelLocs.data(), + argumentLabelLocs.size() * sizeof(SourceLoc)); + + LocationInfo = storedLocs.data(); +} diff --git a/lib/AST/DefaultArgumentKind.cpp b/lib/AST/DefaultArgumentKind.cpp new file mode 100644 index 0000000000000..bbc70a70f16f5 --- /dev/null +++ b/lib/AST/DefaultArgumentKind.cpp @@ -0,0 +1,106 @@ +//===--- DefaultArgumentKind.cpp - Default Argument Implementation --------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements utilities associated with default arguments. +// +//===----------------------------------------------------------------------===// +#include "swift/AST/DefaultArgumentKind.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +using namespace swift; + +StringRef swift::getDefaultArgumentSpelling(DefaultArgumentKind kind) { + switch (kind) { + case DefaultArgumentKind::None: + case DefaultArgumentKind::Normal: + case DefaultArgumentKind::Inherited: + return StringRef(); + + case DefaultArgumentKind::File: + return "__FILE__"; + + case DefaultArgumentKind::Line: + return "__LINE__"; + + case DefaultArgumentKind::Column: + return "__COLUMN__"; + + case DefaultArgumentKind::Function: + return "__FUNCTION__"; + + case DefaultArgumentKind::DSOHandle: + return "__DSO_HANDLE__"; + + case DefaultArgumentKind::Nil: + return "nil"; + + case DefaultArgumentKind::EmptyArray: + return "[]"; + + case DefaultArgumentKind::EmptyDictionary: + return "[:]"; + } +} + +DefaultArgumentKind swift::inferDefaultArgumentKind(Expr *expr) { + if (auto call = dyn_cast(expr)) { + if (auto ctorRefCall = dyn_cast(call->getFn())) { + if (auto ctorRef = dyn_cast(ctorRefCall->getFn())) { + if (auto ctor = dyn_cast(ctorRef->getDecl())) { + auto ctorArg = call->getArg()->getSemanticsProvidingExpr(); + + // __FILE__, __LINE__, __COLUMN__, __FUNCTION__, __DSO_HANDLE__. + if (auto magic = dyn_cast(ctorArg)) { + switch (magic->getKind()) { + case MagicIdentifierLiteralExpr::File: + return DefaultArgumentKind::File; + case MagicIdentifierLiteralExpr::Line: + return DefaultArgumentKind::Line; + case MagicIdentifierLiteralExpr::Column: + return DefaultArgumentKind::Column; + case MagicIdentifierLiteralExpr::Function: + return DefaultArgumentKind::Function; + case MagicIdentifierLiteralExpr::DSOHandle: + return DefaultArgumentKind::DSOHandle; + } + } + + // nil. + if (ctor->getFullName().getArgumentNames().size() == 1 && + ctor->getFullName().getArgumentNames()[0] + == ctor->getASTContext().Id_nilLiteral) + return DefaultArgumentKind::Nil; + } + } + } + } + + // Empty array literals, []. + if (auto arrayExpr = dyn_cast(expr)) { + if (arrayExpr->getElements().empty()) + return DefaultArgumentKind::EmptyArray; + + return DefaultArgumentKind::None; + } + + // Empty dictionary literals, [:]. + if (auto dictionaryExpr = dyn_cast(expr)) { + if (dictionaryExpr->getElements().empty()) + return DefaultArgumentKind::EmptyDictionary; + + return DefaultArgumentKind::None; + } + + return DefaultArgumentKind::None; +} + diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 7053457995264..b626d0e57a330 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -1,8 +1,8 @@ -//===- DiagnosticEngine.h - Diagnostic Display Engine -----------*- C++ -*-===// +//===--- DiagnosticEngine.cpp - Diagnostic Display Engine -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,8 +28,10 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" + using namespace swift; +namespace { enum class DiagnosticOptions { /// No options. none, @@ -45,30 +47,55 @@ enum class DiagnosticOptions { /// After a fatal error subsequent diagnostics are suppressed. Fatal, }; - struct StoredDiagnosticInfo { - /// \brief The kind of diagnostic we're dealing with. - DiagnosticKind Kind; - - DiagnosticOptions Options; + DiagnosticKind kind : 2; + bool pointsToFirstBadToken : 1; + bool isFatal : 1; + + StoredDiagnosticInfo(DiagnosticKind k, bool firstBadToken, bool fatal) + : kind(k), pointsToFirstBadToken(firstBadToken), isFatal(fatal) {} + StoredDiagnosticInfo(DiagnosticKind k, DiagnosticOptions opts) + : StoredDiagnosticInfo(k, + opts == DiagnosticOptions::PointsToFirstBadToken, + opts == DiagnosticOptions::Fatal) {} +}; - // FIXME: Category - - /// \brief Text associated with the diagnostic - const char *Text; +// Reproduce the DiagIDs, as we want both the size and access to the raw ids +// themselves. +enum LocalDiagID : uint32_t { +#define DIAG(KIND, ID, Options, Text, Signature) ID, +#include "swift/AST/DiagnosticsAll.def" + NumDiags }; +} -static StoredDiagnosticInfo StoredDiagnosticInfos[] = { -#define ERROR(ID,Category,Options,Text,Signature) \ - { DiagnosticKind::Error, DiagnosticOptions::Options, Text }, -#define WARNING(ID,Category,Options,Text,Signature) \ - { DiagnosticKind::Warning, DiagnosticOptions::Options, Text }, -#define NOTE(ID,Category,Options,Text,Signature) \ - { DiagnosticKind::Note, DiagnosticOptions::Options, Text }, +// TODO: categorization +static StoredDiagnosticInfo storedDiagnosticInfos[] = { +#define ERROR(ID, Options, Text, Signature) \ + StoredDiagnosticInfo(DiagnosticKind::Error, DiagnosticOptions::Options), +#define WARNING(ID, Options, Text, Signature) \ + StoredDiagnosticInfo(DiagnosticKind::Warning, DiagnosticOptions::Options), +#define NOTE(ID, Options, Text, Signature) \ + StoredDiagnosticInfo(DiagnosticKind::Note, DiagnosticOptions::Options), +#include "swift/AST/DiagnosticsAll.def" +}; +static_assert(sizeof(storedDiagnosticInfos) / sizeof(StoredDiagnosticInfo) == + LocalDiagID::NumDiags, + "array size mismatch"); + +static const char *diagnosticStrings[] = { +#define ERROR(ID, Options, Text, Signature) Text, +#define WARNING(ID, Options, Text, Signature) Text, +#define NOTE(ID, Options, Text, Signature) Text, #include "swift/AST/DiagnosticsAll.def" - { DiagnosticKind::Error, DiagnosticOptions::none, "" } + "", }; +DiagnosticState::DiagnosticState() { + // Initialize our per-diagnostic state to default + perDiagnosticBehavior.resize(LocalDiagID::NumDiags, Behavior::Unspecified); +} + static CharSourceRange toCharSourceRange(SourceManager &SM, SourceRange SR) { return CharSourceRange(SM, SR.Start, Lexer::getLocForEndOfToken(SM, SR.End)); } @@ -175,15 +202,7 @@ void InFlightDiagnostic::flush() { } bool DiagnosticEngine::isDiagnosticPointsToFirstBadToken(DiagID ID) const { - const StoredDiagnosticInfo &StoredInfo = - StoredDiagnosticInfos[(unsigned) ID]; - return StoredInfo.Options == DiagnosticOptions::PointsToFirstBadToken; -} - -bool DiagnosticEngine::isDiagnosticFatal(DiagID ID) const { - const StoredDiagnosticInfo &StoredInfo = - StoredDiagnosticInfos[(unsigned) ID]; - return StoredInfo.Options == DiagnosticOptions::Fatal; + return storedDiagnosticInfos[(unsigned) ID].pointsToFirstBadToken; } /// \brief Skip forward to one of the given delimiters. @@ -443,12 +462,89 @@ static void formatDiagnosticText(StringRef InText, (void)Result; assert(ArgIndex < Args.size() && "Out-of-range argument index"); InText = InText.substr(Length); - + // Convert the argument to a string. formatDiagnosticArgument(Modifier, ModifierArguments, Args, ArgIndex, Out); } } +static DiagnosticKind toDiagnosticKind(DiagnosticState::Behavior behavior) { + switch (behavior) { + case DiagnosticState::Behavior::Unspecified: + llvm_unreachable("unspecified behavior"); + case DiagnosticState::Behavior::Ignore: + llvm_unreachable("trying to map an ignored diagnostic"); + case DiagnosticState::Behavior::Error: + case DiagnosticState::Behavior::Fatal: + return DiagnosticKind::Error; + case DiagnosticState::Behavior::Note: + return DiagnosticKind::Note; + case DiagnosticState::Behavior::Warning: + return DiagnosticKind::Warning; + } +} + +DiagnosticState::Behavior DiagnosticState::determineBehavior(DiagID id) { + auto set = [this](DiagnosticState::Behavior lvl) { + if (lvl == Behavior::Fatal) { + fatalErrorOccurred = true; + anyErrorOccurred = true; + } else if (lvl == Behavior::Error) { + anyErrorOccurred = true; + } + + previousBehavior = lvl; + return lvl; + }; + + // We determine how to handle a diagnostic based on the following rules + // 1) If current state dictates a certain behavior, follow that + // 2) If the user provided a behavior for this specific diagnostic, follow + // that + // 3) If the user provided a behavior for this diagnostic's kind, follow + // that + // 4) Otherwise remap the diagnostic kind + + auto diagInfo = storedDiagnosticInfos[(unsigned)id]; + bool isNote = diagInfo.kind == DiagnosticKind::Note; + + // 1) If current state dictates a certain behavior, follow that + + // Notes relating to ignored diagnostics should also be ignored + if (previousBehavior == Behavior::Ignore && isNote) + return set(Behavior::Ignore); + + // Suppress diagnostics when in a fatal state, except for follow-on notes + if (fatalErrorOccurred) + if (!showDiagnosticsAfterFatalError && !isNote) + return set(Behavior::Ignore); + + // 2) If the user provided a behavior for this specific diagnostic, follow + // that + + if (perDiagnosticBehavior[(unsigned)id] != Behavior::Unspecified) + return set(perDiagnosticBehavior[(unsigned)id]); + + // 3) If the user provided a behavior for this diagnostic's kind, follow + // that + if (diagInfo.kind == DiagnosticKind::Warning) { + if (suppressWarnings) + return set(Behavior::Ignore); + if (warningsAsErrors) + return set(Behavior::Error); + } + + // 4) Otherwise remap the diagnostic kind + switch (diagInfo.kind) { + case DiagnosticKind::Note: + return set(Behavior::Note); + case DiagnosticKind::Error: + return set(diagInfo.isFatal ? Behavior::Fatal : Behavior::Error); + case DiagnosticKind::Warning: + return set(Behavior::Warning); + } +} + void DiagnosticEngine::flushActiveDiagnostic() { assert(ActiveDiagnostic && "No active diagnostic to flush"); if (TransactionCount == 0) { @@ -467,33 +563,9 @@ void DiagnosticEngine::emitTentativeDiagnostics() { } void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { - const StoredDiagnosticInfo &StoredInfo - = StoredDiagnosticInfos[(unsigned)diagnostic.getID()]; - - if (FatalState != FatalErrorState::None) { - bool shouldIgnore = true; - if (StoredInfo.Kind == DiagnosticKind::Note) - shouldIgnore = (FatalState == FatalErrorState::Fatal); - else - FatalState = FatalErrorState::Fatal; - - if (shouldIgnore && !ShowDiagnosticsAfterFatalError) { - return; - } - } - - // Check whether this is an error. - switch (StoredInfo.Kind) { - case DiagnosticKind::Error: - HadAnyError = true; - if (isDiagnosticFatal(diagnostic.getID())) - FatalState = FatalErrorState::JustEmitted; - break; - - case DiagnosticKind::Note: - case DiagnosticKind::Warning: - break; - } + auto behavior = state.determineBehavior(diagnostic.getID()); + if (behavior == DiagnosticState::Behavior::Ignore) + return; // Figure out the source location. SourceLoc loc = diagnostic.getLoc(); @@ -502,12 +574,6 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { // If a declaration was provided instead of a location, and that declaration // has a location we can point to, use that location. loc = decl->getLoc(); - // With an implicit parameter try to point to its type. - if (loc.isInvalid() && isa(decl)) { - if (auto Pat = - cast(decl)->getParamParentPattern()) - loc = Pat->getLoc(); - } if (loc.isInvalid()) { // There is no location we can point to. Pretty-print the declaration @@ -564,6 +630,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { case DeclContextKind::Initializer: case DeclContextKind::AbstractClosureExpr: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: break; } @@ -618,7 +685,8 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { llvm::SmallString<256> Text; { llvm::raw_svector_ostream Out(Text); - formatDiagnosticText(StoredInfo.Text, diagnostic.getArgs(), Out); + formatDiagnosticText(diagnosticStrings[(unsigned)diagnostic.getID()], + diagnostic.getArgs(), Out); } // Pass the diagnostic off to the consumer. @@ -627,7 +695,8 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { Info.Ranges = diagnostic.getRanges(); Info.FixIts = diagnostic.getFixIts(); for (auto &Consumer : Consumers) { - Consumer->handleDiagnostic(SourceMgr, loc, StoredInfo.Kind, Text, Info); + Consumer->handleDiagnostic(SourceMgr, loc, toDiagnosticKind(behavior), Text, + Info); } } diff --git a/lib/AST/DiagnosticList.cpp b/lib/AST/DiagnosticList.cpp index 95c4f7c62e79c..cac4a75260e06 100644 --- a/lib/AST/DiagnosticList.cpp +++ b/lib/AST/DiagnosticList.cpp @@ -1,8 +1,8 @@ -//===- DiagnosticList.cpp - Diagnostic Definitions ------------------------===// +//===--- DiagnosticList.cpp - Diagnostic Definitions ----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,7 +18,7 @@ using namespace swift; enum class swift::DiagID : uint32_t { -#define DIAG(KIND,ID,Category,Options,Text,Signature) ID, +#define DIAG(KIND,ID,Options,Text,Signature) ID, #include "swift/AST/DiagnosticsAll.def" }; @@ -26,7 +26,7 @@ enum class swift::DiagID : uint32_t { // diagnostic IDs. namespace swift { namespace diag { -#define DIAG(KIND,ID,Category,Options,Text,Signature) \ +#define DIAG(KIND,ID,Options,Text,Signature) \ detail::DiagWithArguments::type ID = { DiagID::ID }; #include "swift/AST/DiagnosticsAll.def" } diff --git a/lib/AST/DocComment.cpp b/lib/AST/DocComment.cpp index 4e3900cd5915e..44787fd9298ee 100644 --- a/lib/AST/DocComment.cpp +++ b/lib/AST/DocComment.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index bc548f943fcf6..1e5b2f23b8cb1 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -314,6 +314,7 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind, NON_LVALUE_EXPR(Assign) NON_LVALUE_EXPR(DefaultValue) NON_LVALUE_EXPR(CodeCompletion) + NON_LVALUE_EXPR(ObjCSelector) #define UNCHECKED_EXPR(KIND, BASE) \ NON_LVALUE_EXPR(KIND) @@ -487,6 +488,7 @@ bool Expr::canAppendCallParentheses() const { case ExprKind::StringLiteral: case ExprKind::InterpolatedStringLiteral: case ExprKind::MagicIdentifierLiteral: + case ExprKind::ObjCSelector: return true; case ExprKind::ObjectLiteral: @@ -502,7 +504,6 @@ bool Expr::canAppendCallParentheses() const { case ExprKind::SuperRef: case ExprKind::Type: case ExprKind::OtherConstructorDeclRef: - case ExprKind::UnresolvedConstructor: case ExprKind::DotSyntaxBaseIgnored: return true; @@ -525,7 +526,6 @@ bool Expr::canAppendCallParentheses() const { case ExprKind::UnresolvedSpecialize: case ExprKind::UnresolvedMember: case ExprKind::UnresolvedDot: - case ExprKind::UnresolvedSelector: return true; case ExprKind::Sequence: @@ -866,10 +866,10 @@ ConstructorDecl *OtherConstructorDeclRefExpr::getDecl() const { } MemberRefExpr::MemberRefExpr(Expr *base, SourceLoc dotLoc, - ConcreteDeclRef member, SourceRange nameRange, + ConcreteDeclRef member, DeclNameLoc nameLoc, bool Implicit, AccessSemantics semantics) : Expr(ExprKind::MemberRef, Implicit), Base(base), - Member(member), DotLoc(dotLoc), NameRange(nameRange) { + Member(member), DotLoc(dotLoc), NameLoc(nameLoc) { MemberRefExprBits.Semantics = (unsigned) semantics; MemberRefExprBits.IsSuper = false; @@ -1059,14 +1059,11 @@ RebindSelfInConstructorExpr::getCalledConstructor(bool &isChainToSuper) const { return otherCtorRef; } -void AbstractClosureExpr::setParams(Pattern *P) { - ParamPattern = P; +void AbstractClosureExpr::setParameterList(ParameterList *P) { + parameterList = P; // Change the DeclContext of any parameters to be this closure. - if (P) { - P->forEachVariable([&](VarDecl *VD) { - VD->setDeclContext(this); - }); - } + if (P) + P->setDeclContextOfParamDecls(this); } @@ -1141,33 +1138,6 @@ Expr *AutoClosureExpr::getSingleExpressionBody() const { FORWARD_SOURCE_LOCS_TO(UnresolvedPatternExpr, subPattern) -UnresolvedSelectorExpr::UnresolvedSelectorExpr(Expr *subExpr, SourceLoc dotLoc, - DeclName name, - ArrayRef components) - : Expr(ExprKind::UnresolvedSelector, /*implicit*/ false), - SubExpr(subExpr), DotLoc(dotLoc), Name(name) -{ - assert(name.getArgumentNames().size() + 1 == components.size() && - "number of component locs does not match number of name components"); - auto buf = getComponentsBuf(); - std::uninitialized_copy(components.begin(), components.end(), - buf.begin()); -} - -UnresolvedSelectorExpr *UnresolvedSelectorExpr::create(ASTContext &C, - Expr *subExpr, SourceLoc dotLoc, - DeclName name, - ArrayRef components) { - assert(name.getArgumentNames().size() + 1 == components.size() && - "number of component locs does not match number of name components"); - - void *buf = C.Allocate(sizeof(UnresolvedSelectorExpr) - + (name.getArgumentNames().size() + 1) - * sizeof(ComponentLoc), - alignof(UnresolvedSelectorExpr)); - return ::new (buf) UnresolvedSelectorExpr(subExpr, dotLoc, name, components); -} - TypeExpr::TypeExpr(TypeLoc TyLoc) : Expr(ExprKind::Type, /*implicit*/false), Info(TyLoc) { Type Ty = TyLoc.getType(); @@ -1181,13 +1151,27 @@ TypeExpr::TypeExpr(Type Ty) setType(MetatypeType::get(Ty, Ty->getASTContext())); } +// The type of a TypeExpr is always a metatype type. Return the instance +// type or null if not set yet. +Type TypeExpr::getInstanceType() const { + if (!getType() || getType()->is()) + return Type(); + + return getType()->castTo()->getInstanceType(); +} + + /// Return a TypeExpr for a simple identifier and the specified location. -TypeExpr *TypeExpr::createForDecl(SourceLoc Loc, TypeDecl *Decl) { +TypeExpr *TypeExpr::createForDecl(SourceLoc Loc, TypeDecl *Decl, + bool isImplicit) { ASTContext &C = Decl->getASTContext(); assert(Loc.isValid()); auto *Repr = new (C) SimpleIdentTypeRepr(Loc, Decl->getName()); Repr->setValue(Decl); - return new (C) TypeExpr(TypeLoc(Repr, Type())); + auto result = new (C) TypeExpr(TypeLoc(Repr, Type())); + if (isImplicit) + result->setImplicit(); + return result; } TypeExpr *TypeExpr::createForSpecializedDecl(SourceLoc Loc, TypeDecl *D, diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 15fc379f0a8cd..2c483a68fe947 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -255,6 +255,21 @@ GenericSignature::getCanonicalManglingSignature(ModuleDecl &M) const { depTypes.push_back(depTy); return; } + + case RequirementKind::Superclass: { + assert(std::find(depTypes.begin(), depTypes.end(), + depTy) != depTypes.end() + && "didn't see witness marker first?"); + // Organize conformance constraints, sifting out the base class + // requirement. + auto &depConstraints = constraints[depTy]; + + auto constraintType = type.get()->getCanonicalType(); + assert(depConstraints.baseClass.isNull() + && "multiple base class constraints?!"); + depConstraints.baseClass = constraintType; + return; + } case RequirementKind::Conformance: { assert(std::find(depTypes.begin(), depTypes.end(), @@ -265,14 +280,8 @@ GenericSignature::getCanonicalManglingSignature(ModuleDecl &M) const { auto &depConstraints = constraints[depTy]; auto constraintType = type.get()->getCanonicalType(); - if (constraintType->isExistentialType()) { - depConstraints.protocols.push_back(constraintType); - } else { - assert(depConstraints.baseClass.isNull() - && "multiple base class constraints?!"); - depConstraints.baseClass = constraintType; - } - + assert(constraintType->isExistentialType()); + depConstraints.protocols.push_back(constraintType); return; } @@ -315,7 +324,7 @@ GenericSignature::getCanonicalManglingSignature(ModuleDecl &M) const { const auto &depConstraints = foundConstraints->second; if (depConstraints.baseClass) - minimalRequirements.push_back(Requirement(RequirementKind::Conformance, + minimalRequirements.push_back(Requirement(RequirementKind::Superclass, depTy, depConstraints.baseClass)); @@ -389,10 +398,6 @@ GenericSignature::getSubstitutionMap(ArrayRef args) const { } // Seed the type map with pre-existing substitutions. - for (auto sub : args) { - subs[sub.getArchetype()] = sub.getReplacement(); - } - for (auto depTy : getAllDependentTypes()) { auto replacement = args.front().getReplacement(); args = args.slice(1); diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp index 34a69141e76ba..3bb91269a1bbc 100644 --- a/lib/AST/Identifier.cpp +++ b/lib/AST/Identifier.cpp @@ -1,8 +1,8 @@ -//===--- Identifier.cpp - Uniqued Identifier --------------------*- C++ -*-===// +//===--- Identifier.cpp - Uniqued Identifier ------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -102,7 +102,8 @@ void DeclName::dump() const { llvm::errs() << *this << "\n"; } -llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { +llvm::raw_ostream &DeclName::print(llvm::raw_ostream &os, + bool skipEmptyArgumentNames) const { // Print the base name. os << getBaseName(); @@ -110,19 +111,21 @@ llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { if (isSimpleName()) return os; - // If there is more than one argument yet none of them have names, - // we're done. - if (getArgumentNames().size() > 0) { - bool anyNonEmptyNames = false; - for (auto c : getArgumentNames()) { - if (!c.empty()) { - anyNonEmptyNames = true; - break; + if (skipEmptyArgumentNames) { + // If there is more than one argument yet none of them have names, + // we're done. + if (getArgumentNames().size() > 0) { + bool anyNonEmptyNames = false; + for (auto c : getArgumentNames()) { + if (!c.empty()) { + anyNonEmptyNames = true; + break; + } } - } - if (!anyNonEmptyNames) - return os; + if (!anyNonEmptyNames) + return os; + } } // Print the argument names. @@ -132,6 +135,11 @@ llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { } os << ")"; return os; + +} + +llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { + return print(os, /*skipEmptyArgumentNames=*/true); } ObjCSelector::ObjCSelector(ASTContext &ctx, unsigned numArgs, diff --git a/lib/AST/LookupVisibleDecls.cpp b/lib/AST/LookupVisibleDecls.cpp index a85177bf080af..bd46f9f75c0b7 100644 --- a/lib/AST/LookupVisibleDecls.cpp +++ b/lib/AST/LookupVisibleDecls.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -122,7 +122,7 @@ static bool isDeclVisibleInLookupMode(ValueDecl *Member, LookupState LS, } if (auto *FD = dyn_cast(Member)) { - // Can not call static functions on non-metatypes. + // Cannot call static functions on non-metatypes. if (!LS.isOnMetatype() && FD->isStatic()) return false; @@ -130,27 +130,27 @@ static bool isDeclVisibleInLookupMode(ValueDecl *Member, LookupState LS, return true; } if (auto *VD = dyn_cast(Member)) { - // Can not use static properties on non-metatypes. + // Cannot use static properties on non-metatypes. if (!(LS.isQualified() && LS.isOnMetatype()) && VD->isStatic()) return false; - // Can not use instance properties on metatypes. + // Cannot use instance properties on metatypes. if (LS.isOnMetatype() && !VD->isStatic()) return false; return true; } if (isa(Member)) { - // Can not reference enum elements on non-metatypes. + // Cannot reference enum elements on non-metatypes. if (!(LS.isQualified() && LS.isOnMetatype())) return false; } if (auto CD = dyn_cast(Member)) { - // Constructors with stub implementations can not be called in Swift. + // Constructors with stub implementations cannot be called in Swift. if (CD->hasStubImplementation()) return false; if (LS.isQualified() && LS.isOnSuperclass()) { - // Can not call initializers from a superclass, except for inherited + // Cannot call initializers from a superclass, except for inherited // convenience initializers. return LS.isInheritsSuperclassInitializers() && CD->isInheritable(); } @@ -277,7 +277,7 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer, if (D->getOverriddenDecl()) return; - // Initializers can not be found by dynamic lookup. + // Initializers cannot be found by dynamic lookup. if (isa(D)) return; @@ -500,6 +500,8 @@ static void lookupVisibleMemberDeclsImpl( ClassDecl *CurClass = dyn_cast(CurNominal); if (CurClass && CurClass->hasSuperclass()) { + assert(BaseTy.getPointer() != CurClass->getSuperclass().getPointer() && + "type is its own superclass"); BaseTy = CurClass->getSuperclass(); Reason = getReasonForSuper(Reason); @@ -588,7 +590,7 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { } auto &PossiblyConflicting = FoundDecls[VD->getName()]; - // Check all overriden decls. + // Check all overridden decls. { auto *CurrentVD = VD->getOverriddenDecl(); while (CurrentVD) { @@ -712,13 +714,12 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, namelookup::FindLocalVal(SM, Loc, Consumer).visit(AFD->getBody()); } - for (auto *P : AFD->getBodyParamPatterns()) - namelookup::FindLocalVal(SM, Loc, Consumer) - .checkPattern(P, DeclVisibilityKind::FunctionParameter); + for (auto *P : AFD->getParameterLists()) + namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P); // Constructors and destructors don't have 'self' in parameter patterns. if (isa(AFD) || isa(AFD)) - Consumer.foundDecl(AFD->getImplicitSelfDecl(), + Consumer.foundDecl(const_cast(AFD->getImplicitSelfDecl()), DeclVisibilityKind::FunctionParameter); if (AFD->getExtensionType()) { @@ -740,9 +741,8 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, if (Loc.isValid()) { auto CE = cast(ACE); namelookup::FindLocalVal(SM, Loc, Consumer).visit(CE->getBody()); - if (auto P = CE->getParams()) { - namelookup::FindLocalVal(SM, Loc, Consumer) - .checkPattern(P, DeclVisibilityKind::FunctionParameter); + if (auto P = CE->getParameters()) { + namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P); } } } else if (auto ED = dyn_cast(DC)) { @@ -759,13 +759,10 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, TypeResolver); } - // Check the generic parameters for something with the given name. - if (GenericParams) { - namelookup::FindLocalVal(SM, Loc, Consumer) - .checkGenericParams(GenericParams, - DeclVisibilityKind::GenericParameter); - } - + // Check any generic parameters for something with the given name. + namelookup::FindLocalVal(SM, Loc, Consumer) + .checkGenericParams(GenericParams); + DC = DC->getParent(); Reason = DeclVisibilityKind::MemberOfOutsideNominal; } diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index 8be2d575bf11a..a7a78a54dadfa 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -1,8 +1,8 @@ -//===--- Mangle.cpp - Swift Name Mangling --------------------------------===// +//===--- Mangle.cpp - Swift Name Mangling ---------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -58,20 +58,38 @@ namespace { } }; } - + +// Translates operator fixity to demangler operators. +static Demangle::OperatorKind TranslateOperator(OperatorFixity fixity) { + switch (fixity) { + case OperatorFixity::NotOperator:return Demangle::OperatorKind::NotOperator; + case OperatorFixity::Prefix: return Demangle::OperatorKind::Prefix; + case OperatorFixity::Postfix: return Demangle::OperatorKind::Postfix; + case OperatorFixity::Infix: return Demangle::OperatorKind::Infix; + } + llvm_unreachable("invalid operator fixity"); +} + +/// Finish the mangling of the symbol and return the mangled name. +std::string Mangler::finalize() { + assert(Storage.size() && "Mangling an empty name"); + std::string result = std::string(Storage.data(), Storage.size()); + Storage.clear(); + return result; +} + +/// Finish the mangling of the symbol and write the mangled name into +/// \p stream. +void Mangler::finalize(llvm::raw_ostream &stream) { + std::string result = finalize(); + stream.write(result.data(), result.size()); +} + /// Mangle a StringRef as an identifier into a buffer. void Mangler::mangleIdentifier(StringRef str, OperatorFixity fixity, bool isOperator) { - auto operatorKind = [=]() -> Demangle::OperatorKind { - if (!isOperator) return Demangle::OperatorKind::NotOperator; - switch (fixity) { - case OperatorFixity::NotOperator:return Demangle::OperatorKind::NotOperator; - case OperatorFixity::Prefix: return Demangle::OperatorKind::Prefix; - case OperatorFixity::Postfix: return Demangle::OperatorKind::Postfix; - case OperatorFixity::Infix: return Demangle::OperatorKind::Infix; - } - llvm_unreachable("invalid operator fixity"); - }(); + auto operatorKind = isOperator ? TranslateOperator(fixity) : + Demangle::OperatorKind::NotOperator; std::string buf; Demangle::mangleIdentifier(str.data(), str.size(), operatorKind, buf, @@ -213,7 +231,7 @@ void Mangler::mangleContext(const DeclContext *ctx, BindGenerics shouldBind) { switch (local->getLocalDeclContextKind()) { case LocalDeclContextKind::AbstractClosure: mangleClosureEntity(cast(local), - ResilienceExpansion::Minimal, /*uncurry*/ 0); + /*uncurry*/ 0); return; case LocalDeclContextKind::DefaultArgumentInitializer: { auto argInit = cast(local); @@ -232,8 +250,7 @@ void Mangler::mangleContext(const DeclContext *ctx, BindGenerics shouldBind) { } case DeclContextKind::NominalTypeDecl: - mangleNominalType(cast(ctx), ResilienceExpansion::Minimal, - shouldBind); + mangleNominalType(cast(ctx), shouldBind); return; case DeclContextKind::ExtensionDecl: { @@ -265,10 +282,10 @@ void Mangler::mangleContext(const DeclContext *ctx, BindGenerics shouldBind) { mangleModule(ExtD->getParentModule()); if (mangleSignature) { Mod = ExtD->getModuleContext(); - mangleGenericSignature(sig, ResilienceExpansion::Minimal); + mangleGenericSignature(sig); } } - mangleNominalType(decl, ResilienceExpansion::Minimal, shouldBind, + mangleNominalType(decl, shouldBind, getCanonicalSignatureOrNull(ExtD->getGenericSignature(), *ExtD->getParentModule()), ExtD->getGenericParams()); @@ -277,7 +294,7 @@ void Mangler::mangleContext(const DeclContext *ctx, BindGenerics shouldBind) { case DeclContextKind::AbstractClosureExpr: return mangleClosureEntity(cast(ctx), - ResilienceExpansion::Minimal, /*uncurry*/ 0); + /*uncurry*/ 0); case DeclContextKind::AbstractFunctionDecl: { auto fn = cast(ctx); @@ -286,16 +303,20 @@ void Mangler::mangleContext(const DeclContext *ctx, BindGenerics shouldBind) { // using the non-(de)allocating variants. if (auto ctor = dyn_cast(fn)) { return mangleConstructorEntity(ctor, /*allocating*/ false, - ResilienceExpansion::Minimal, /*uncurry*/ 0); } if (auto dtor = dyn_cast(fn)) return mangleDestructorEntity(dtor, /*deallocating*/ false); - return mangleEntity(fn, ResilienceExpansion::Minimal, /*uncurry*/ 0); + return mangleEntity(fn, /*uncurry*/ 0); } + case DeclContextKind::SubscriptDecl: + // FIXME: We may need to do something here if subscripts contain any symbols + // exposed with linkage names. + return mangleContext(ctx->getParent(), shouldBind); + case DeclContextKind::Initializer: switch (cast(ctx)->getInitializerKind()) { case InitializerKind::DefaultArgument: { @@ -446,7 +467,7 @@ static void bindAllGenericParameters(Mangler &mangler, } void Mangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) { - assert(DWARFMangling && "DWARFMangling expected whn mangling for debugger"); + assert(DWARFMangling && "DWARFMangling expected when mangling for debugger"); // Polymorphic function types carry their own generic parameters and // manglePolymorphicType will bind them. @@ -464,7 +485,7 @@ void Mangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) { DC->getGenericParamsOfContext()); DeclCtx = DC; - mangleType(Ty, ResilienceExpansion::Minimal, /*uncurry*/ 0); + mangleType(Ty, /*uncurry*/ 0); } void Mangler::mangleDeclTypeForDebugger(const ValueDecl *decl) { @@ -549,7 +570,7 @@ void Mangler::mangleDeclTypeForDebugger(const ValueDecl *decl) { DC->getGenericParamsOfContext()); } - mangleDeclType(decl, ResilienceExpansion::Minimal, /*uncurry*/ 0); + mangleDeclType(decl, /*uncurry*/ 0); } /// Is this declaration a method for mangling purposes? If so, we'll leave the @@ -600,10 +621,7 @@ Type Mangler::getDeclTypeForMangling(const ValueDecl *decl, } // Shed the 'self' type and generic requirements from method manglings. - if (C.LangOpts.DisableSelfTypeMangling - && isMethodDecl(decl) - && type && !type->is()) { - + if (isMethodDecl(decl) && type && !type->is()) { // Drop the Self argument clause from the type. type = type->castTo()->getResult(); @@ -629,6 +647,7 @@ Type Mangler::getDeclTypeForMangling(const ValueDecl *decl, continue; case RequirementKind::Conformance: + case RequirementKind::Superclass: // We don't need the requirement if the constrained type is above the // method depth. if (!genericParamIsBelowDepth(reqt.getFirstType(), initialParamDepth)) @@ -654,7 +673,6 @@ Type Mangler::getDeclTypeForMangling(const ValueDecl *decl, } void Mangler::mangleDeclType(const ValueDecl *decl, - ResilienceExpansion explosion, unsigned uncurryLevel) { ArrayRef genericParams; unsigned initialParamDepth; @@ -669,10 +687,10 @@ void Mangler::mangleDeclType(const ValueDecl *decl, if (!genericParams.empty() || !requirements.empty()) { Buffer << 'u'; mangleGenericSignatureParts(genericParams, initialParamDepth, - requirements, explosion); + requirements); } - mangleType(type->getCanonicalType(), explosion, uncurryLevel); + mangleType(type->getCanonicalType(), uncurryLevel); // Bind the declaration's generic context for nested decls. if (decl->getInterfaceType() @@ -685,8 +703,7 @@ void Mangler::mangleDeclType(const ValueDecl *decl, } } -void Mangler::mangleConstrainedType(CanType type, - ResilienceExpansion expansion) { +void Mangler::mangleConstrainedType(CanType type) { // The type constrained by a generic requirement should always be a // generic parameter or associated type thereof. Assuming this lets us save // an introducer character in the common case when a generic parameter is @@ -697,14 +714,13 @@ void Mangler::mangleConstrainedType(CanType type, mangleGenericParamIndex(gp); return; } - mangleType(type, expansion, 0); + mangleType(type, 0); } void Mangler::mangleGenericSignatureParts( ArrayRef params, unsigned initialParamDepth, - ArrayRef requirements, - ResilienceExpansion expansion) { + ArrayRef requirements) { // Mangle the number of parameters. unsigned depth = 0; unsigned count = 0; @@ -748,36 +764,37 @@ void Mangler::mangleGenericSignatureParts( case RequirementKind::WitnessMarker: break; - case RequirementKind::Conformance: { + case RequirementKind::Conformance: if (!didMangleRequirement) { Buffer << 'R'; didMangleRequirement = true; } - SmallVector protocols; - if (reqt.getSecondType()->isExistentialType(protocols) - && protocols.size() == 1) { - // Protocol constraints are the common case, so mangle them more - // efficiently. - // TODO: We could golf this a little more by assuming the first type - // is a dependent type. - mangleConstrainedType(reqt.getFirstType()->getCanonicalType(), - expansion); - mangleProtocolName(protocols[0]); - break; + // Protocol constraints are the common case, so mangle them more + // efficiently. + // TODO: We could golf this a little more by assuming the first type + // is a dependent type. + mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); + mangleProtocolName( + reqt.getSecondType()->castTo()->getDecl()); + break; + + case RequirementKind::Superclass: + if (!didMangleRequirement) { + Buffer << 'R'; + didMangleRequirement = true; } - mangleConstrainedType(reqt.getFirstType()->getCanonicalType(), expansion); - mangleType(reqt.getSecondType()->getCanonicalType(), expansion, 0); + mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); + mangleType(reqt.getSecondType()->getCanonicalType(), 0); break; - } case RequirementKind::SameType: if (!didMangleRequirement) { Buffer << 'R'; didMangleRequirement = true; } - mangleConstrainedType(reqt.getFirstType()->getCanonicalType(), expansion); + mangleConstrainedType(reqt.getFirstType()->getCanonicalType()); Buffer << 'z'; - mangleType(reqt.getSecondType()->getCanonicalType(), expansion, 0); + mangleType(reqt.getSecondType()->getCanonicalType(), 0); break; } } @@ -785,14 +802,12 @@ void Mangler::mangleGenericSignatureParts( Buffer << 'r'; } -void Mangler::mangleGenericSignature(const GenericSignature *sig, - ResilienceExpansion expansion) { +void Mangler::mangleGenericSignature(const GenericSignature *sig) { assert(Mod); auto canSig = sig->getCanonicalManglingSignature(*Mod); CurGenericSignature = canSig; mangleGenericSignatureParts(canSig->getGenericParams(), 0, - canSig->getRequirements(), - expansion); + canSig->getRequirements()); } static void mangleMetatypeRepresentation(raw_ostream &Buffer, @@ -881,13 +896,13 @@ void Mangler::mangleAssociatedTypeName(DependentMemberType *dmt, /// ::= Xo # unowned reference type /// ::= Xw # weak reference type /// ::= XF # SIL function type +/// ::= Xb # SIL @box type /// /// ::= _ # 0 /// ::= _ # N+1 /// /// ::= ? -void Mangler::mangleType(Type type, ResilienceExpansion explosion, - unsigned uncurryLevel) { +void Mangler::mangleType(Type type, unsigned uncurryLevel) { assert((DWARFMangling || type->isCanonical()) && "expecting canonical types when not mangling for the debugger"); TypeBase *tybase = type.getPointer(); @@ -942,8 +957,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, return; case TypeKind::BuiltinVector: Buffer << "Bv" << cast(tybase)->getNumElements(); - mangleType(cast(tybase)->getElementType(), explosion, - uncurryLevel); + mangleType(cast(tybase)->getElementType(), uncurryLevel); return; case TypeKind::NameAlias: { @@ -952,7 +966,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, TypeAliasDecl *decl = NameAliasTy->getDecl(); if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) // It's not possible to mangle the context of the builtin module. - return mangleType(decl->getUnderlyingType(), explosion, uncurryLevel); + return mangleType(decl->getUnderlyingType(), uncurryLevel); Buffer << "a"; // For the DWARF output we want to mangle the type alias + context, @@ -982,7 +996,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, auto *IUO = cast(tybase); auto implDecl = tybase->getASTContext().getImplicitlyUnwrappedOptionalDecl(); auto GenTy = BoundGenericType::get(implDecl, Type(), IUO->getBaseType()); - return mangleType(GenTy, ResilienceExpansion::Minimal, 0); + return mangleType(GenTy, 0); } case TypeKind::ExistentialMetatype: { @@ -993,8 +1007,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, } else { Buffer << 'P' << 'M'; } - return mangleType(EMT->getInstanceType(), - ResilienceExpansion::Minimal, 0); + return mangleType(EMT->getInstanceType(), 0); } case TypeKind::Metatype: { MetatypeType *MT = cast(tybase); @@ -1004,30 +1017,25 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, } else { Buffer << 'M'; } - return mangleType(MT->getInstanceType(), - ResilienceExpansion::Minimal, 0); + return mangleType(MT->getInstanceType(), 0); } case TypeKind::LValue: llvm_unreachable("@lvalue types should not occur in function interfaces"); case TypeKind::InOut: Buffer << 'R'; - return mangleType(cast(tybase)->getObjectType(), - ResilienceExpansion::Minimal, 0); + return mangleType(cast(tybase)->getObjectType(), 0); case TypeKind::UnmanagedStorage: Buffer << "Xu"; - return mangleType(cast(tybase)->getReferentType(), - ResilienceExpansion::Minimal, 0); + return mangleType(cast(tybase)->getReferentType(), 0); case TypeKind::UnownedStorage: Buffer << "Xo"; - return mangleType(cast(tybase)->getReferentType(), - ResilienceExpansion::Minimal, 0); + return mangleType(cast(tybase)->getReferentType(), 0); case TypeKind::WeakStorage: Buffer << "Xw"; - return mangleType(cast(tybase)->getReferentType(), - ResilienceExpansion::Minimal, 0); + return mangleType(cast(tybase)->getReferentType(), 0); case TypeKind::Tuple: { auto tuple = cast(tybase); @@ -1042,7 +1050,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, for (auto &field : tuple->getElements()) { if (field.hasName()) mangleIdentifier(field.getName()); - mangleType(field.getType(), explosion, 0); + mangleType(field.getType(), 0); } Buffer << '_'; return; @@ -1062,7 +1070,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, // are several occasions in which we'd like to mangle them in the // abstract. ContextStack context(*this); - mangleNominalType(cast(tybase)->getDecl(), explosion, + mangleNominalType(cast(tybase)->getDecl(), BindGenerics::None); return; } @@ -1071,7 +1079,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, case TypeKind::Enum: case TypeKind::Struct: { ContextStack context(*this); - return mangleNominalType(cast(tybase)->getDecl(), explosion, + return mangleNominalType(cast(tybase)->getDecl(), BindGenerics::None); } @@ -1083,10 +1091,10 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, Buffer << 'G'; { ContextStack context(*this); - mangleNominalType(boundType->getDecl(), explosion, BindGenerics::None); + mangleNominalType(boundType->getDecl(), BindGenerics::None); } for (auto arg : boundType->getGenericArgs()) { - mangleType(arg, ResilienceExpansion::Minimal, /*uncurry*/ 0); + mangleType(arg, /*uncurry*/ 0); } Buffer << '_'; return; @@ -1181,13 +1189,13 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, if (fn->isNoReturn()) Buffer << 'N'; if (fn->isPolymorphic()) { Buffer << 'G'; - mangleGenericSignature(fn->getGenericSignature(), explosion); + mangleGenericSignature(fn->getGenericSignature()); } Buffer << '_'; auto mangleParameter = [&](SILParameterInfo param) { Buffer << mangleParameterConvention(param.getConvention()); - mangleType(param.getType(), ResilienceExpansion::Minimal, 0); + mangleType(param.getType(), 0); }; for (auto param : fn->getParametersWithoutIndirectResult()) { @@ -1200,13 +1208,13 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, } else { auto result = fn->getResult(); Buffer << mangleResultConvention(result.getConvention()); - mangleType(result.getType(), ResilienceExpansion::Minimal, 0); + mangleType(result.getType(), 0); } if (fn->hasErrorResult()) { auto error = fn->getErrorResult(); Buffer << 'z' << mangleResultConvention(error.getConvention()); - mangleType(error.getType(), ResilienceExpansion::Minimal, 0); + mangleType(error.getType(), 0); } Buffer << '_'; @@ -1231,7 +1239,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, assert(archetype->getAssocType() && "child archetype has no associated type?!"); - mangleType(parent, explosion, 0); + mangleType(parent, 0); mangleIdentifier(archetype->getName()); addSubstitution(archetype); return; @@ -1278,19 +1286,24 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, if (DWARFMangling) { Buffer << 'q' << Index(info.Index); - // The DWARF output created by Swift is intentionally flat, - // therefore archetypes are emitted with their DeclContext if - // they appear at the top level of a type (_Tt). - // Clone a new, non-DWARF Mangler for the DeclContext. - Mangler ContextMangler(Buffer, /*DWARFMangling=*/false); - SmallVector SortedSubsts(Substitutions.size()); - for (auto S : Substitutions) SortedSubsts[S.second] = S.first; - for (auto S : SortedSubsts) ContextMangler.addSubstitution(S); - for (; relativeDepth > 0; --relativeDepth) - DC = DC->getParent(); - assert(DC && "no decl context for archetype found"); - if (!DC) return; - ContextMangler.mangleContext(DC, BindGenerics::None); + + { + // The DWARF output created by Swift is intentionally flat, + // therefore archetypes are emitted with their DeclContext if + // they appear at the top level of a type (_Tt). + // Clone a new, non-DWARF Mangler for the DeclContext. + Mangler ContextMangler(/*DWARFMangling=*/false); + SmallVector SortedSubsts(Substitutions.size()); + for (auto S : Substitutions) SortedSubsts[S.second] = S.first; + for (auto S : SortedSubsts) ContextMangler.addSubstitution(S); + for (; relativeDepth > 0; --relativeDepth) + DC = DC->getParent(); + assert(DC && "no decl context for archetype found"); + if (!DC) return; + ContextMangler.mangleContext(DC, BindGenerics::None); + ContextMangler.finalize(Buffer); + } + } else { if (relativeDepth != 0) { Buffer << 'd' << Index(relativeDepth - 1); @@ -1304,10 +1317,10 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, auto dynamicSelf = cast(tybase); if (dynamicSelf->getSelfType()->getAnyNominal()) { Buffer << 'D'; - mangleType(dynamicSelf->getSelfType(), explosion, uncurryLevel); + mangleType(dynamicSelf->getSelfType(), uncurryLevel); } else { // Mangle DynamicSelf as Self within a protocol. - mangleType(dynamicSelf->getSelfType(), explosion, uncurryLevel); + mangleType(dynamicSelf->getSelfType(), uncurryLevel); } return; } @@ -1315,8 +1328,8 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, case TypeKind::GenericFunction: { auto genFunc = cast(tybase); Buffer << 'u'; - mangleGenericSignature(genFunc->getGenericSignature(), explosion); - mangleFunctionType(genFunc, explosion, uncurryLevel); + mangleGenericSignature(genFunc->getGenericSignature()); + mangleFunctionType(genFunc, uncurryLevel); return; } @@ -1372,13 +1385,13 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, // Dependent members of non-generic-param types are not canonical, but // we may still want to mangle them for debugging or indexing purposes. Buffer << 'q'; - mangleType(memTy->getBase(), explosion, 0); + mangleType(memTy->getBase(), 0); mangleAssociatedTypeName(memTy, /*canAbbreviate*/false); return; } case TypeKind::Function: - mangleFunctionType(cast(tybase), explosion, uncurryLevel); + mangleFunctionType(cast(tybase), uncurryLevel); return; case TypeKind::ProtocolComposition: { @@ -1394,6 +1407,11 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion, } case TypeKind::SILBox: + Buffer << 'X' << 'b'; + mangleType(cast(tybase)->getBoxedType(), + uncurryLevel); + return; + case TypeKind::SILBlockStorage: llvm_unreachable("should never be mangled"); } @@ -1447,7 +1465,6 @@ static char getSpecifierForNominalType(const NominalTypeDecl *decl) { } void Mangler::mangleNominalType(const NominalTypeDecl *decl, - ResilienceExpansion explosion, BindGenerics shouldBind, CanGenericSignature extGenericSig, const GenericParamList *extGenericParams) { @@ -1554,7 +1571,6 @@ bool Mangler::tryMangleStandardSubstitution(const NominalTypeDecl *decl) { } void Mangler::mangleFunctionType(AnyFunctionType *fn, - ResilienceExpansion explosion, unsigned uncurryLevel) { assert((DWARFMangling || fn->isCanonical()) && "expecting canonical types when not mangling for the debugger"); @@ -1597,9 +1613,8 @@ void Mangler::mangleFunctionType(AnyFunctionType *fn, if (fn->throws()) Buffer << 'z'; - mangleType(fn->getInput(), explosion, 0); - mangleType(fn->getResult(), explosion, - (uncurryLevel > 0 ? uncurryLevel - 1 : 0)); + mangleType(fn->getInput(), 0); + mangleType(fn->getResult(), (uncurryLevel > 0 ? uncurryLevel - 1 : 0)); } void Mangler::mangleClosureComponents(Type Ty, unsigned discriminator, @@ -1620,12 +1635,10 @@ void Mangler::mangleClosureComponents(Type Ty, unsigned discriminator, Ty = ErrorType::get(localContext->getASTContext()); if (!DeclCtx) DeclCtx = localContext; - mangleType(Ty->getCanonicalType(), ResilienceExpansion::Minimal, - /*uncurry*/ 0); + mangleType(Ty->getCanonicalType(), /*uncurry*/ 0); } void Mangler::mangleClosureEntity(const SerializedAbstractClosureExpr *closure, - ResilienceExpansion explosion, unsigned uncurryingLevel) { mangleClosureComponents(closure->getType(), closure->getDiscriminator(), closure->isImplicit(), closure->getParent(), @@ -1633,7 +1646,6 @@ void Mangler::mangleClosureEntity(const SerializedAbstractClosureExpr *closure, } void Mangler::mangleClosureEntity(const AbstractClosureExpr *closure, - ResilienceExpansion explosion, unsigned uncurryLevel) { mangleClosureComponents(closure->getType(), closure->getDiscriminator(), isa(closure), closure->getParent(), @@ -1642,12 +1654,11 @@ void Mangler::mangleClosureEntity(const AbstractClosureExpr *closure, void Mangler::mangleConstructorEntity(const ConstructorDecl *ctor, bool isAllocating, - ResilienceExpansion explosion, unsigned uncurryLevel) { Buffer << 'F'; mangleContextOf(ctor, BindGenerics::Enclosing); Buffer << (isAllocating ? 'C' : 'c'); - mangleDeclType(ctor, explosion, uncurryLevel); + mangleDeclType(ctor, uncurryLevel); } void Mangler::mangleDestructorEntity(const DestructorDecl *dtor, @@ -1698,14 +1709,13 @@ static StringRef getCodeForAccessorKind(AccessorKind kind, void Mangler::mangleAccessorEntity(AccessorKind kind, AddressorKind addressorKind, - const AbstractStorageDecl *decl, - ResilienceExpansion explosion) { + const AbstractStorageDecl *decl) { assert(kind != AccessorKind::NotAccessor); Buffer << 'F'; mangleContextOf(decl, BindGenerics::All); Buffer << getCodeForAccessorKind(kind, addressorKind); mangleDeclName(decl); - mangleDeclType(decl, explosion, 0); + mangleDeclType(decl, 0); } void Mangler::mangleAddressorEntity(const ValueDecl *decl) { @@ -1713,7 +1723,7 @@ void Mangler::mangleAddressorEntity(const ValueDecl *decl) { mangleContextOf(decl, BindGenerics::All); Buffer << "au"; mangleDeclName(decl); - mangleDeclType(decl, ResilienceExpansion::Minimal, 0); + mangleDeclType(decl, 0); } void Mangler::mangleGlobalGetterEntity(ValueDecl *decl) { @@ -1721,7 +1731,7 @@ void Mangler::mangleGlobalGetterEntity(ValueDecl *decl) { mangleContextOf(decl, BindGenerics::All); Buffer << 'G'; mangleDeclName(decl); - mangleDeclType(decl, ResilienceExpansion::Minimal, 0); + mangleDeclType(decl, 0); } void Mangler::mangleDefaultArgumentEntity(const DeclContext *func, @@ -1734,12 +1744,11 @@ void Mangler::mangleDefaultArgumentEntity(const DeclContext *func, void Mangler::mangleInitializerEntity(const VarDecl *var) { // The initializer is its own entity whose context is the variable. Buffer << 'I'; - mangleEntity(var, ResilienceExpansion::Minimal, /*uncurry*/ 0); + mangleEntity(var, /*uncurry*/ 0); Buffer << 'i'; } void Mangler::mangleEntity(const ValueDecl *decl, - ResilienceExpansion explosion, unsigned uncurryLevel) { assert(!isa(decl)); assert(!isa(decl)); @@ -1754,8 +1763,7 @@ void Mangler::mangleEntity(const ValueDecl *decl, auto accessorKind = func->getAccessorKind(); if (accessorKind != AccessorKind::NotAccessor) return mangleAccessorEntity(accessorKind, func->getAddressorKind(), - func->getAccessorStorageDecl(), - explosion); + func->getAccessorStorageDecl()); } BindGenerics shouldBindParent = BindGenerics::All; @@ -1781,7 +1789,7 @@ void Mangler::mangleEntity(const ValueDecl *decl, if (!DeclCtx) DeclCtx = decl->getDeclContext(); mangleContextOf(decl, shouldBindParent); mangleDeclName(decl); - mangleDeclType(decl, explosion, uncurryLevel); + mangleDeclType(decl, uncurryLevel); } void Mangler::mangleDirectness(bool isIndirect) { @@ -1798,10 +1806,9 @@ void Mangler::mangleProtocolConformance(const ProtocolConformance *conformance){ Mod = conformance->getDeclContext()->getParentModule(); if (auto sig = conformance->getGenericSignature()) { Buffer << 'u'; - mangleGenericSignature(sig, ResilienceExpansion::Minimal); + mangleGenericSignature(sig); } - mangleType(conformance->getInterfaceType()->getCanonicalType(), - ResilienceExpansion::Minimal, 0); + mangleType(conformance->getInterfaceType()->getCanonicalType(), 0); mangleProtocolName(conformance->getProtocol()); mangleModule(conformance->getDeclContext()->getParentModule()); } @@ -1809,19 +1816,43 @@ void Mangler::mangleProtocolConformance(const ProtocolConformance *conformance){ void Mangler::mangleFieldOffsetFull(const ValueDecl *decl, bool isIndirect) { Buffer << "_TWv"; mangleDirectness(isIndirect); - mangleEntity(decl, ResilienceExpansion::Minimal, 0); + mangleEntity(decl, 0); } void Mangler::mangleTypeFullMetadataFull(CanType ty) { Buffer << "_TMf"; - mangleType(ty, ResilienceExpansion::Minimal, 0); + mangleType(ty, 0); } void Mangler::mangleTypeMetadataFull(CanType ty, bool isPattern) { Buffer << "_TM"; if (isPattern) Buffer << 'P'; - mangleType(ty, ResilienceExpansion::Minimal, 0); + mangleType(ty, 0); +} + +void Mangler::append(StringRef S) { + Buffer << S; +} + +void Mangler::append(char C) { + Buffer << C; +} + +void Mangler::mangleNatural(const APInt &Nat) { + Buffer << Nat; +} + +void Mangler::mangleIdentifierSymbol(StringRef Name) { + // Mangle normal identifiers as: + // count identifier-char+ + // where the count is the number of characters in the identifier, + // and where individual identifier characters represent themselves. + Buffer << Name.size() << Name; +} + +void Mangler::appendSymbol(StringRef Name) { + Buffer << Name; } void Mangler::mangleGlobalVariableFull(const VarDecl *decl) { @@ -1838,7 +1869,7 @@ void Mangler::mangleGlobalVariableFull(const VarDecl *decl) { } Buffer << "_T"; - mangleEntity(decl, ResilienceExpansion(0), 0); + mangleEntity(decl, 0); } void Mangler::mangleGlobalInit(const VarDecl *decl, int counter, diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 6ffdb8a66c56b..578bc843d952d 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -338,7 +338,8 @@ void SourceLookupCache::invalidate() { ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx) : TypeDecl(DeclKind::Module, &ctx, name, SourceLoc(), { }), - DeclContext(DeclContextKind::Module, nullptr) { + DeclContext(DeclContextKind::Module, nullptr), + Flags({0, 0, 0}), DSOHandle(nullptr) { ctx.addDestructorCleanup(*this); setImplicit(); setType(ModuleType::get(this)); @@ -399,8 +400,8 @@ DerivedFileUnit &Module::getDerivedFileUnit() const { } VarDecl *Module::getDSOHandle() { - if (DSOHandleAndFlags.getPointer()) - return DSOHandleAndFlags.getPointer(); + if (DSOHandle) + return DSOHandle; auto unsafeMutablePtr = getASTContext().getUnsafeMutablePointerDecl(); if (!unsafeMutablePtr) @@ -423,7 +424,7 @@ VarDecl *Module::getDSOHandle() { handleVar->getAttrs().add( new (ctx) SILGenNameAttr("__dso_handle", /*Implicit=*/true)); handleVar->setAccessibility(Accessibility::Internal); - DSOHandleAndFlags.setPointer(handleVar); + DSOHandle = handleVar; return handleVar; } @@ -458,6 +459,7 @@ void Module::lookupMember(SmallVectorImpl &results, case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: llvm_unreachable("This context does not support lookup."); case DeclContextKind::FileUnit: @@ -518,12 +520,24 @@ void Module::lookupMember(SmallVectorImpl &results, } } +void Module::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + FORWARD(lookupObjCMethods, (selector, results)); +} + void BuiltinUnit::lookupValue(Module::AccessPathTy accessPath, DeclName name, NLKind lookupKind, SmallVectorImpl &result) const { getCache().lookupValue(name.getBaseName(), lookupKind, *this, result); } +void BuiltinUnit::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + // No @objc methods in the Builtin module. +} + DerivedFileUnit::DerivedFileUnit(Module &M) : FileUnit(FileUnitKind::Derived, M) { M.getASTContext().addDestructorCleanup(*this); @@ -560,6 +574,17 @@ void DerivedFileUnit::lookupVisibleDecls(Module::AccessPathTy accessPath, } } +void DerivedFileUnit::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + for (auto D : DerivedDecls) { + if (auto func = dyn_cast(D)) { + if (func->isObjC() && func->getObjCSelector() == selector) + results.push_back(func); + } + } +} + void DerivedFileUnit::getTopLevelDecls(SmallVectorImpl &results) const { results.append(DerivedDecls.begin(), DerivedDecls.end()); @@ -605,6 +630,15 @@ void SourceFile::lookupClassMember(Module::AccessPathTy accessPath, getCache().lookupClassMember(accessPath, name, results, *this); } +void SourceFile::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + // FIXME: Make sure this table is complete, somehow. + auto known = ObjCMethods.find(selector); + if (known == ObjCMethods.end()) return; + results.append(known->second.begin(), known->second.end()); +} + void Module::getLocalTypeDecls(SmallVectorImpl &Results) const { FORWARD(getLocalTypeDecls, (Results)); } @@ -632,7 +666,7 @@ DeclContext *BoundGenericType::getGenericParamContext( if (!gpContext) return getDecl(); - assert(gpContext->getDeclaredTypeOfContext()->getAnyNominal() == getDecl() && + assert(gpContext->isNominalTypeOrNominalTypeExtensionContext() == getDecl() && "not a valid context"); return gpContext; } @@ -659,8 +693,6 @@ ArrayRef BoundGenericType::getSubstitutions( return *known; // Compute the set of substitutions. - llvm::SmallPtrSet knownArchetypes; - SmallVector archetypeStack; TypeSubstitutionMap substitutions; auto genericParams = gpContext->getGenericParamsOfContext(); unsigned index = 0; @@ -703,33 +735,31 @@ ArrayRef BoundGenericType::getSubstitutions( if (!type) type = ErrorType::get(module->getASTContext()); - SmallVector conformances; - if (type->is() || type->isTypeParameter()) { + SmallVector conformances; + for (auto proto : archetype->getConformsTo()) { // If the type is a type variable or is dependent, just fill in null - // conformances. FIXME: It seems like we should record these as - // requirements (?). - conformances.assign(archetype->getConformsTo().size(), nullptr); - } else { - // Find the conformances. - for (auto proto : archetype->getConformsTo()) { + // conformances. + if (type->is() || type->isTypeParameter()) { + conformances.push_back(ProtocolConformanceRef(proto)); + + // Otherwise, find the conformances. + } else { auto conforms = module->lookupConformance(type, proto, resolver); switch (conforms.getInt()) { case ConformanceKind::Conforms: - conformances.push_back(conforms.getPointer()); + conformances.push_back( + ProtocolConformanceRef(proto, conforms.getPointer())); break; case ConformanceKind::UncheckedConforms: - conformances.push_back(nullptr); - break; case ConformanceKind::DoesNotConform: - conformances.push_back(nullptr); + conformances.push_back(ProtocolConformanceRef(proto)); break; } } } // Record this substitution. - resultSubstitutions[index] = {archetype, type, - ctx.AllocateCopy(conformances)}; + resultSubstitutions[index] = {type, ctx.AllocateCopy(conformances)}; ++index; } @@ -909,6 +939,11 @@ LookupConformanceResult Module::lookupConformance(Type type, auto substitutions = type->gatherAllSubstitutions(this, substitutionsVec, resolver, explicitConformanceDC); + + for (auto sub : substitutions) { + if (sub.getReplacement()->is()) + return { nullptr, ConformanceKind::DoesNotConform }; + } // Create the specialized conformance entry. auto result = ctx.getSpecializedConformance(type, conformance, diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 1edfaa1024078..7a9e1b7e663f4 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -1,8 +1,8 @@ -//===--- ModuleNameLookup.cpp - Name lookup within a module ----*- c++ -*--===// +//===--- ModuleNameLookup.cpp - Name lookup within a module ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 3fde23dd87a26..6236a8439689a 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -71,6 +71,9 @@ bool swift::removeOverriddenDecls(SmallVectorImpl &decls) { // A.init are in the chain. Make sure we still remove A.init from the // set in this case. if (decl->getFullName().getBaseName() == ctx.Id_init) { + /// FIXME: Avoid the possibility of an infinite loop by fixing the root + /// cause instead (incomplete circularity detection). + assert(decl != overrides && "Circular class inheritance?"); decl = overrides; continue; } @@ -421,8 +424,8 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, localVal.visit(AFD->getBody()); if (!Results.empty()) return; - for (Pattern *P : AFD->getBodyParamPatterns()) - localVal.checkPattern(P, DeclVisibilityKind::FunctionParameter); + for (auto *PL : AFD->getParameterLists()) + localVal.checkParameterList(PL); if (!Results.empty()) return; } @@ -468,8 +471,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, localVal.visit(CE->getBody()); if (!Results.empty()) return; - localVal.checkPattern(CE->getParams(), - DeclVisibilityKind::FunctionParameter); + localVal.checkParameterList(CE->getParameters()); if (!Results.empty()) return; } @@ -508,8 +510,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, // Check the generic parameters for something with the given name. if (GenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(GenericParams, - DeclVisibilityKind::GenericParameter); + localVal.checkGenericParams(GenericParams); if (!Results.empty()) return; @@ -579,8 +580,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, if (dcGenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); - localVal.checkGenericParams(dcGenericParams, - DeclVisibilityKind::GenericParameter); + localVal.checkGenericParams(dcGenericParams); if (!Results.empty()) return; @@ -698,7 +698,7 @@ class swift::MemberLookupTable { /// Update a lookup table with members from newly-added extensions. void updateLookupTable(NominalTypeDecl *nominal); - /// \brief Add the given member to the lookup tabke. + /// \brief Add the given member to the lookup table. void addMember(Decl *members); /// \brief Add the given members to the lookup table. @@ -1091,9 +1091,6 @@ bool DeclContext::lookupQualified(Type type, // Look for module references. if (auto moduleTy = type->getAs()) { - assert(!(options & NL_IgnoreAccessibility) && - "accessibility always enforced for module-level lookup"); - Module *module = moduleTy->getModule(); auto topLevelScope = getModuleScopeContext(); if (module == topLevelScope->getParentModule()) { @@ -1374,3 +1371,21 @@ bool DeclContext::lookupQualified(Type type, // We're done. Report success/failure. return !decls.empty(); } + +void DeclContext::lookupAllObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + // Collect all of the methods with this selector. + forAllVisibleModules(this, [&](Module::ImportedModule import) { + import.second->lookupObjCMethods(selector, results); + }); + + // Filter out duplicates. + llvm::SmallPtrSet visited; + results.erase( + std::remove_if(results.begin(), results.end(), + [&](AbstractFunctionDecl *func) -> bool { + return !visited.insert(func).second; + }), + results.end()); +} diff --git a/lib/AST/NameLookupImpl.h b/lib/AST/NameLookupImpl.h index 055735cc1e159..a1264b29e3987 100644 --- a/lib/AST/NameLookupImpl.h +++ b/lib/AST/NameLookupImpl.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,6 +15,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/ParameterList.h" namespace swift { namespace namelookup { @@ -89,14 +90,19 @@ class FindLocalVal : public StmtVisitor { return; } } + + void checkParameterList(const ParameterList *params) { + for (auto param : *params) { + checkValueDecl(param, DeclVisibilityKind::FunctionParameter); + } + } - void checkGenericParams(GenericParamList *Params, - DeclVisibilityKind Reason) { + void checkGenericParams(GenericParamList *Params) { if (!Params) return; for (auto P : *Params) - checkValueDecl(P, Reason); + checkValueDecl(P, DeclVisibilityKind::GenericParameter); } void checkSourceFile(const SourceFile &SF) { diff --git a/lib/AST/Parameter.cpp b/lib/AST/Parameter.cpp new file mode 100644 index 0000000000000..fe765b987b4f4 --- /dev/null +++ b/lib/AST/Parameter.cpp @@ -0,0 +1,152 @@ +//===--- Parameter.cpp - Functions & closures parameters ------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the Parameter class, the ParameterList class and support +// logic. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ParameterList.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/Expr.h" +#include "swift/AST/ExprHandle.h" +using namespace swift; + +/// TODO: unique and reuse the () parameter list in ASTContext, it is common to +/// many methods. Other parameter lists cannot be uniqued because the decls +/// within them are always different anyway (they have different DeclContext's). +ParameterList * +ParameterList::create(const ASTContext &C, SourceLoc LParenLoc, + ArrayRef params, SourceLoc RParenLoc) { + assert(LParenLoc.isValid() == RParenLoc.isValid() && + "Either both paren locs are valid or neither are"); + + auto byteSize = sizeof(ParameterList)+params.size()*sizeof(ParamDecl*); + auto rawMem = C.Allocate(byteSize, alignof(ParameterList)); + + // Placement initialize the ParameterList and the Parameter's. + auto PL = ::new (rawMem) ParameterList(LParenLoc, params.size(), RParenLoc); + + for (size_t i = 0, e = params.size(); i != e; ++i) + ::new (&PL->get(i)) ParamDecl*(params[i]); + + return PL; +} + +/// Create an implicit 'self' decl for a method in the specified decl context. +/// If 'static' is true, then this is self for a static method in the type. +/// +/// Note that this decl is created, but it is returned with an incorrect +/// DeclContext that needs to be set correctly. This is automatically handled +/// when a function is created with this as part of its argument list. +/// +ParameterList *ParameterList::createSelf(SourceLoc loc, DeclContext *DC, + bool isStaticMethod, bool isInOut) { + auto *PD = ParamDecl::createSelf(loc, DC, isStaticMethod, isInOut); + return create(DC->getASTContext(), PD); +} + +/// Change the DeclContext of any contained parameters to the specified +/// DeclContext. +void ParameterList::setDeclContextOfParamDecls(DeclContext *DC) { + for (auto P : *this) + P->setDeclContext(DC); +} + + + +/// Make a duplicate copy of this parameter list. This allocates copies of +/// the ParamDecls, so they can be reparented into a new DeclContext. +ParameterList *ParameterList::clone(const ASTContext &C, + OptionSet options) const { + // If this list is empty, don't actually bother with a copy. + if (size() == 0) + return const_cast(this); + + SmallVector params(begin(), end()); + + // Remap the ParamDecls inside of the ParameterList. + for (auto &decl : params) { + decl = new (C) ParamDecl(decl); + if (options & Implicit) + decl->setImplicit(); + + // If the argument isn't named, and we're cloning for an inherited + // constructor, give the parameter a name so that silgen will produce a + // value for it. + if (decl->getName().empty() && (options & Inherited)) + decl->setName(C.getIdentifier("argument")); + + // If we're inheriting a default argument, mark it as such. + if (decl->isDefaultArgument() && (options & Inherited)) { + decl->setDefaultArgumentKind(DefaultArgumentKind::Inherited); + decl->setDefaultValue(nullptr); + } + } + + return create(C, params); +} + +/// Return a TupleType or ParenType for this parameter list. This returns a +/// null type if one of the ParamDecls does not have a type set for it yet. +Type ParameterList::getType(const ASTContext &C) const { + if (size() == 0) + return TupleType::getEmpty(C); + + SmallVector argumentInfo; + + for (auto P : *this) { + if (!P->hasType()) return Type(); + + argumentInfo.push_back({ + P->getType(), P->getArgumentName(), + P->getDefaultArgumentKind(), P->isVariadic() + }); + } + + return TupleType::get(argumentInfo, C); +} + + +/// Return the full function type for a set of curried parameter lists that +/// returns the specified result type. This returns a null type if one of the +/// ParamDecls does not have a type set for it yet. +/// +Type ParameterList::getFullType(Type resultType, ArrayRef PLL) { + auto result = resultType; + auto &C = result->getASTContext(); + + for (auto PL : reversed(PLL)) { + auto paramType = PL->getType(C); + if (!paramType) return Type(); + result = FunctionType::get(paramType, result); + } + return result; +} + +/// Return the full source range of this parameter list. +SourceRange ParameterList::getSourceRange() const { + // If we have locations for the parens, then they define our range. + if (LParenLoc.isValid()) + return { LParenLoc, RParenLoc }; + + // Otherwise, try the first and last parameter. + if (size() != 0) { + auto Start = get(0)->getStartLoc(); + auto End = getArray().back()->getEndLoc(); + if (Start.isValid() && End.isValid()) + return { Start, End }; + } + + return SourceRange(); +} + diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index afb1d21b20f2d..a3b6a4716bacf 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,6 +16,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/AST.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/TypeLoc.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/raw_ostream.h" @@ -25,7 +26,7 @@ using namespace swift; llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, PatternKind kind) { switch (kind) { case PatternKind::Paren: - return OS << "parethesized pattern"; + return OS << "parenthesized pattern"; case PatternKind::Tuple: return OS << "tuple pattern"; case PatternKind::Named: @@ -289,367 +290,8 @@ case PatternKind::ID: foundRefutablePattern = true; break; return foundRefutablePattern; } - - -unsigned Pattern::numTopLevelVariables() const { - auto pattern = getSemanticsProvidingPattern(); - if (auto tuple = dyn_cast(pattern)) - return tuple->getNumElements(); - return 1; -} - -static Pattern *buildImplicitLetParameter(ASTContext &ctx, Identifier name, - SourceLoc loc, TypeLoc tyLoc, - DeclContext *DC) { - auto *paramDecl = new (ctx) ParamDecl(/*IsLet*/ true, SourceLoc(), - Identifier(), loc, name, - tyLoc.getType(), DC); - - paramDecl->setImplicit(); - Pattern *P = new (ctx) NamedPattern(paramDecl, /*Implicit=*/true); - P->setType(tyLoc.getType()); - P = new (ctx) TypedPattern(P, tyLoc, /*Implicit=*/true); - P->setType(tyLoc.getType()); - paramDecl->setParamParentPattern(P); - return P; -} - -Pattern *Pattern::buildImplicitSelfParameter(SourceLoc loc, TypeLoc tyLoc, - DeclContext *DC) { - ASTContext &ctx = DC->getASTContext(); - return ::buildImplicitLetParameter(ctx, ctx.Id_self, loc, tyLoc, DC); -} - -Pattern *Pattern::buildImplicitLetParameter(SourceLoc loc, StringRef name, - TypeLoc tyLoc, DeclContext *DC) { - ASTContext &ctx = DC->getASTContext(); - Identifier ident = (name.empty() ? Identifier() : ctx.getIdentifier(name)); - return ::buildImplicitLetParameter(ctx, ident, loc, tyLoc, DC); -} - -Pattern *Pattern::clone(ASTContext &context, - OptionSet options) const { - Pattern *result; - switch (getKind()) { - case PatternKind::Any: { - result = new (context) AnyPattern(cast(this)->getLoc()); - break; - } - - case PatternKind::Named: { - auto named = cast(this); - VarDecl *var; - if (auto param = dyn_cast(named->getDecl())) { - - auto name = param->getName(); - // If the argument isn't named, and we're cloning for an inherited - // constructor, give the parameter a name so that silgen will produce a - // value for it. - if (name.empty() && (options & Inherited)) - name = context.getIdentifier("argument"); - - var = new (context) ParamDecl(param->isLet(), - param->getArgumentNameLoc(), - param->getArgumentName(), - param->getLoc(), name, - param->hasType() - ? param->getType() - : Type(), - param->getDeclContext()); - } else { - var = new (context) VarDecl(!named->getDecl()->isInstanceMember(), - named->getDecl()->isLet(), - named->getLoc(), - named->getBoundName(), - named->getDecl()->hasType() - ? named->getDecl()->getType() - : Type(), - named->getDecl()->getDeclContext()); - } - - if ((options & Implicit) || var->isImplicit()) - var->setImplicit(); - result = new (context) NamedPattern(var); - break; - } - - case PatternKind::Paren: { - auto paren = cast(this); - result = new (context) ParenPattern(paren->getLParenLoc(), - paren->getSubPattern()->clone(context, - options), - paren->getRParenLoc()); - break; - } - - case PatternKind::Tuple: { - auto tuple = cast(this); - SmallVector elts; - elts.reserve(tuple->getNumElements()); - for (const auto &elt : tuple->getElements()) { - auto eltPattern = elt.getPattern()->clone(context, options); - - // If we're inheriting a default argument, mark it as such. - if (elt.getDefaultArgKind() != DefaultArgumentKind::None && - (options & Inherited)) { - elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), - eltPattern, elt.hasEllipsis(), - elt.getEllipsisLoc(), nullptr, - DefaultArgumentKind::Inherited)); - } else { - elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), - eltPattern, elt.hasEllipsis(), - elt.getEllipsisLoc(), elt.getInit(), - elt.getDefaultArgKind())); - } - } - - result = TuplePattern::create(context, tuple->getLParenLoc(), elts, - tuple->getRParenLoc()); - break; - } - - case PatternKind::Typed: { - auto typed = cast(this); - result = new(context) TypedPattern(typed->getSubPattern()->clone(context, - options), - typed->getTypeLoc().clone(context)); - break; - } - - case PatternKind::Is: { - auto isa = cast(this); - result = new(context) IsPattern(isa->getLoc(), - isa->getCastTypeLoc().clone(context), - isa->getSubPattern()->clone(context, - options), - isa->getCastKind()); - break; - } - - case PatternKind::NominalType: { - auto nom = cast(this); - SmallVector elts; - for (const auto &elt : nom->getElements()) { - elts.push_back(NominalTypePattern::Element(elt.getPropertyLoc(), - elt.getPropertyName(), - elt.getProperty(), - elt.getColonLoc(), - elt.getSubPattern()->clone(context, - options))); - } - - result = NominalTypePattern::create(nom->getCastTypeLoc().clone(context), - nom->getLParenLoc(), - elts, - nom->getRParenLoc(), context); - break; - } - - case PatternKind::EnumElement: { - auto oof = cast(this); - Pattern *sub = nullptr; - if (oof->hasSubPattern()) - sub = oof->getSubPattern()->clone(context, options); - result = new (context) EnumElementPattern(oof->getParentType() - .clone(context), - oof->getLoc(), - oof->getNameLoc(), - oof->getName(), - oof->getElementDecl(), - sub); - break; - } - - case PatternKind::OptionalSome: { - auto osp = cast(this); - auto *sub = osp->getSubPattern()->clone(context, options); - auto *r = new (context) OptionalSomePattern(sub, osp->getQuestionLoc()); - r->setElementDecl(osp->getElementDecl()); - result = r; - break; - } - - case PatternKind::Bool: { - auto bp = cast(this); - result = new (context) BoolPattern(bp->getNameLoc(), bp->getValue()); - break; - } - - case PatternKind::Expr: { - auto expr = cast(this); - result = new(context) ExprPattern(expr->getSubExpr(), - expr->isResolved(), - expr->getMatchExpr(), - expr->getMatchVar()); - break; - } - - case PatternKind::Var: { - auto var = cast(this); - result = new(context) VarPattern(var->getLoc(), var->isLet(), - var->getSubPattern()->clone( - context, - options|IsVar)); - } - } - - if (hasType()) - result->setType(getType()); - if ((options & Implicit) || isImplicit()) - result->setImplicit(); - - return result; -} - -Pattern *Pattern::cloneForwardable(ASTContext &context, DeclContext *DC, - OptionSet options) const { - Pattern *result; - switch (getKind()) { - case PatternKind::Any: - case PatternKind::Is: - case PatternKind::NominalType: - case PatternKind::EnumElement: - case PatternKind::OptionalSome: - case PatternKind::Bool: - case PatternKind::Expr: - llvm_unreachable("cannot forward this kind of pattern"); - - case PatternKind::Named: - return clone(context, options); - - case PatternKind::Paren: { - auto paren = cast(this); - auto sub = paren->getSubPattern()->cloneForwardable(context, DC, options); - result = new (context) ParenPattern(paren->getLParenLoc(), - sub, - paren->getRParenLoc()); - break; - } - - case PatternKind::Var: { - auto var = cast(this); - result = new(context) VarPattern(var->getLoc(), var->isLet(), - var->getSubPattern()->cloneForwardable( - context, DC, options|IsVar)); - break; - } - - case PatternKind::Tuple: { - auto tuple = cast(this); - SmallVector elts; - elts.reserve(tuple->getNumElements()); - for (const auto &elt : tuple->getElements()) { - auto eltPattern = elt.getPattern()->cloneForwardable(context, DC, options); - - // If we're inheriting a default argument, mark it as such. - if (elt.getDefaultArgKind() != DefaultArgumentKind::None && - (options & Inherited)) { - elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), - eltPattern, elt.hasEllipsis(), - elt.getEllipsisLoc(), nullptr, - DefaultArgumentKind::Inherited)); - } else { - elts.push_back(TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), - eltPattern, elt.hasEllipsis(), - elt.getEllipsisLoc(), elt.getInit(), - elt.getDefaultArgKind())); - } - } - - result = TuplePattern::create(context, tuple->getLParenLoc(), elts, - tuple->getRParenLoc()); - break; - } - - case PatternKind::Typed: { - auto typed = cast(this); - TypeLoc tyLoc = typed->getTypeLoc().clone(context); - const Pattern *origSub = typed->getSubPattern(); - - // If the original sub-pattern is a single named variable, go - // ahead and clone it. - if (origSub->getSingleVar()) { - Pattern *cloneSub = origSub->cloneForwardable(context, DC, options); - result = new (context) TypedPattern(cloneSub, tyLoc); - - // Otherwise, create a new bound variable. - } else { - result = buildImplicitLetParameter(origSub->getLoc(), "", tyLoc, DC); - } - break; - } - } - - if (hasType()) - result->setType(getType()); - if ((options & Implicit) || isImplicit()) - result->setImplicit(); - - return result; -} - -Expr *Pattern::buildForwardingRefExpr(ASTContext &context) const { - switch (getKind()) { - case PatternKind::Any: - case PatternKind::Is: - case PatternKind::NominalType: - case PatternKind::EnumElement: - case PatternKind::OptionalSome: - case PatternKind::Bool: - case PatternKind::Expr: - llvm_unreachable("cannot forward this kind of pattern"); - - case PatternKind::Named: { - auto np = cast(this); - Expr *ref = new (context) DeclRefExpr(np->getDecl(), SourceLoc(), - /*implicit*/ true); - if (np->getDecl()->getType()->is()) - ref = new (context) InOutExpr(SourceLoc(), ref, Type(), - /*implicit=*/true); - return ref; - } - - case PatternKind::Paren: { - auto paren = cast(this); - return paren->getSubPattern()->buildForwardingRefExpr(context); - } - - case PatternKind::Var: { - auto var = cast(this); - return var->getSubPattern()->buildForwardingRefExpr(context); - } - - case PatternKind::Typed: { - auto typed = cast(this); - return typed->getSubPattern()->buildForwardingRefExpr(context); - } - - case PatternKind::Tuple: { - auto tuple = cast(this); - SmallVector elts; - SmallVector labels; - SmallVector labelLocs; - elts.reserve(tuple->getNumElements()); - labels.reserve(tuple->getNumElements()); - labelLocs.reserve(tuple->getNumElements()); - for (const auto &elt : tuple->getElements()) { - elts.push_back(elt.getPattern()->buildForwardingRefExpr(context)); - labels.push_back(Identifier()); // FIXME? - labelLocs.push_back(SourceLoc()); - } - - return TupleExpr::create(context, SourceLoc(), elts, labels, labelLocs, - SourceLoc(), /*trailing closure*/ false, - /*implicit*/ true); - } - - } - llvm_unreachable("bad pattern kind"); -} - /// Standard allocator for Patterns. -void *Pattern::operator new(size_t numBytes, ASTContext &C) { +void *Pattern::operator new(size_t numBytes, const ASTContext &C) { return C.Allocate(numBytes, alignof(Pattern)); } @@ -662,20 +304,7 @@ Identifier Pattern::getBoundName() const { return Identifier(); } -Identifier Pattern::getBodyName() const { - if (auto *NP = dyn_cast(getSemanticsProvidingPattern())) - return NP->getBodyName(); - return Identifier(); -} - Identifier NamedPattern::getBoundName() const { - if (auto param = dyn_cast(Var)) - return param->getArgumentName(); - - return Var->getName(); -} - -Identifier NamedPattern::getBodyName() const { return Var->getName(); } @@ -703,10 +332,7 @@ Pattern *TuplePattern::createSimple(ASTContext &C, SourceLoc lp, assert(lp.isValid() == rp.isValid()); if (elements.size() == 1 && - !elements[0].hasEllipsis() && - elements[0].getInit() == nullptr && - elements[0].getPattern()->getBoundName().empty() && - elements[0].getPattern()->getBodyName().empty()) { + elements[0].getPattern()->getBoundName().empty()) { auto &first = const_cast(elements.front()); return new (C) ParenPattern(lp, first.getPattern(), rp, implicit); } @@ -724,24 +350,6 @@ SourceRange TuplePattern::getSourceRange() const { Fields.back().getPattern()->getEndLoc() }; } -bool TuplePattern::hasAnyEllipsis() const { - for (const auto elt : getElements()) { - if (elt.hasEllipsis()) - return true; - } - - return false; -} - -SourceLoc TuplePattern::getAnyEllipsisLoc() const { - for (const auto elt : getElements()) { - if (elt.hasEllipsis()) - return elt.getEllipsisLoc(); - } - - return SourceLoc(); -} - SourceRange TypedPattern::getSourceRange() const { if (isImplicit()) { // If a TypedPattern is implicit, then its type is definitely implicit, so diff --git a/lib/AST/PlatformKind.cpp b/lib/AST/PlatformKind.cpp index dc1f5a51ffb05..c863836210ed4 100644 --- a/lib/AST/PlatformKind.cpp +++ b/lib/AST/PlatformKind.cpp @@ -1,8 +1,8 @@ -//===--- PlatformKind.cpp - Swift Language Platform Kinds -------*- C++ -*-===// +//===--- PlatformKind.cpp - Swift Language Platform Kinds -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index d0be7c12568de..5b3dbaff856de 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index c67845f958653..c57c07397f04b 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -1,8 +1,8 @@ -//===--- ProtocolConformance.cpp - AST Protocol Conformance -----*- C++ -*-===// +//===--- ProtocolConformance.cpp - AST Protocol Conformance ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -29,6 +29,26 @@ using namespace swift; +ProtocolConformanceRef::ProtocolConformanceRef(ProtocolDecl *protocol, + ProtocolConformance *conf) { + assert(protocol != nullptr && + "cannot construct ProtocolConformanceRef with null protocol"); + if (conf) { + assert(protocol == conf->getProtocol() && "protocol conformance mismatch"); + Union = conf; + } else { + Union = protocol; + } +} + +ProtocolDecl *ProtocolConformanceRef::getRequirement() const { + if (isConcrete()) { + return getConcrete()->getProtocol(); + } else { + return getAbstract(); + } +} + void *ProtocolConformance::operator new(size_t bytes, ASTContext &context, AllocationArena arena, unsigned alignment) { @@ -145,7 +165,7 @@ GenericParamList *ProtocolConformance::getGenericParams() const { case ProtocolConformanceKind::Specialized: // If we have a specialized protocol conformance, since we do not support - // currently partial specialization, we know that it can not have any open + // currently partial specialization, we know that it cannot have any open // type variables. return nullptr; } @@ -174,7 +194,7 @@ GenericSignature *ProtocolConformance::getGenericSignature() const { case ProtocolConformanceKind::Specialized: // If we have a specialized protocol conformance, since we do not support - // currently partial specialization, we know that it can not have any open + // currently partial specialization, we know that it cannot have any open // type variables. return nullptr; } @@ -241,7 +261,7 @@ void NormalProtocolConformance::setTypeWitness( assert(getProtocol() == cast(assocType->getDeclContext()) && "associated type in wrong protocol"); assert(TypeWitnesses.count(assocType) == 0 && "Type witness already known"); - assert(!isComplete() && "Conformance already complete?"); + assert((!isComplete() || isInvalid()) && "Conformance already complete?"); TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl); } @@ -289,6 +309,13 @@ SpecializedProtocolConformance::SpecializedProtocolConformance( assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized); } +SubstitutionIterator +SpecializedProtocolConformance::getGenericSubstitutionIterator() const { + return SubstitutionIterator( + GenericConformance->getDeclContext()->getGenericParamsOfContext(), + GenericSubstitutions); +} + bool SpecializedProtocolConformance::hasTypeWitness( AssociatedTypeDecl *assocType, LazyResolver *resolver) const { @@ -328,9 +355,8 @@ SpecializedProtocolConformance::getTypeWitnessSubstAndDecl( } // Gather the conformances for the type witness. These should never fail. - SmallVector conformances; - auto archetype = genericWitness.getArchetype(); - for (auto proto : archetype->getConformsTo()) { + SmallVector conformances; + for (auto proto : assocType->getConformingProtocols(resolver)) { auto conforms = conformingModule->lookupConformance(specializedType, proto, resolver); assert((conforms.getInt() == ConformanceKind::Conforms || @@ -338,13 +364,13 @@ SpecializedProtocolConformance::getTypeWitnessSubstAndDecl( specializedType->isTypeParameter() || specializedType->is()) && "Improperly checked substitution"); - conformances.push_back(conforms.getPointer()); + conformances.push_back(ProtocolConformanceRef(proto, conforms.getPointer())); } // Form the substitution. auto &ctx = assocType->getASTContext(); TypeWitnesses[assocType] = std::make_pair( - Substitution{archetype, specializedType, + Substitution{specializedType, ctx.AllocateCopy(conformances)}, typeDecl); return TypeWitnesses[assocType]; @@ -439,12 +465,12 @@ ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const { // Preserve specialization through this operation by peeling off the // substitutions from a specialized conformance so we can apply them later. const ProtocolConformance *unspecialized; - ArrayRef subs; + SubstitutionIterator subs; switch (getKind()) { case ProtocolConformanceKind::Specialized: { auto spec = cast(this); unspecialized = spec->getGenericConformance(); - subs = spec->getGenericSubstitutions(); + subs = spec->getGenericSubstitutionIterator(); break; } @@ -484,15 +510,16 @@ ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const { ArchetypeConformanceMap conformanceMap; // Fill in the substitution and conformance maps. - // FIXME: Unfortunate reliance on Substitution::Archetype here. - for (auto sub : subs) { - auto arch = sub.getArchetype(); + for (auto archAndSub : subs) { + auto arch = archAndSub.first; + auto sub = archAndSub.second; conformanceMap[arch] = sub.getConformances(); if (arch->isPrimary()) subMap[arch] = sub.getReplacement(); } return foundInherited->subst(getDeclContext()->getParentModule(), - getType(), subs, subMap, conformanceMap); + getType(), subs.getSubstitutions(), + subMap, conformanceMap); } assert((getType()->isEqual(foundInherited->getType()) || foundInherited->getType()->isSuperclassOf(getType(), nullptr)) @@ -642,7 +669,7 @@ DeclContext::getLocalProtocols( nullptr, diagnostics); - // Sort if requred. + // Sort if required. if (sorted) { llvm::array_pod_sort(result.begin(), result.end(), &ProtocolType::compareProtocols); diff --git a/lib/AST/RawComment.cpp b/lib/AST/RawComment.cpp index cbc32320f8edb..72aee1c5f7b34 100644 --- a/lib/AST/RawComment.cpp +++ b/lib/AST/RawComment.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 14f31f7638ff8..92227e5d7525c 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -165,7 +165,7 @@ SourceLoc DeferStmt::getEndLoc() const { return tempDecl->getBody()->getEndLoc(); } -/// Dig the original users's body of the defer out for AST fidelity. +/// Dig the original user's body of the defer out for AST fidelity. BraceStmt *DeferStmt::getBodyAsWritten() const { return tempDecl->getBody(); } @@ -248,7 +248,7 @@ bool DoCatchStmt::isSyntacticallyExhaustive() const { } void LabeledConditionalStmt::setCond(StmtCondition e) { - // When set set a condition into a Conditional Statement, inform each of the + // When set a condition into a Conditional Statement, inform each of the // variables bound in any patterns that this is the owning statement for the // pattern. for (auto &elt : e) diff --git a/lib/AST/Substitution.cpp b/lib/AST/Substitution.cpp index 2e2df054abbbd..d9d75c300d866 100644 --- a/lib/AST/Substitution.cpp +++ b/lib/AST/Substitution.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,7 +26,7 @@ using namespace swift; bool Substitution::operator==(const Substitution &other) const { // The archetypes may be missing, but we can compare them directly // because archetypes are always canonical. - return Archetype == other.Archetype && + return Replacement->getCanonicalType() == other.Replacement->getCanonicalType() && Conformance.equals(other.Conformance); } @@ -50,22 +50,13 @@ getSubstitutionMaps(GenericParamList *context, assert(subs.empty() && "did not use all substitutions?!"); } -Substitution::Substitution(ArchetypeType *Archetype, - Type Replacement, - ArrayRef Conformance) - : Archetype(Archetype), Replacement(Replacement), Conformance(Conformance) +Substitution::Substitution(Type Replacement, + ArrayRef Conformance) + : Replacement(Replacement), Conformance(Conformance) { // The replacement type must be materializable. assert(Replacement->isMaterializable() && "cannot substitute with a non-materializable type"); - - assert(Archetype && "missing archetype in substitution"); - - // The conformance list must match the archetype conformances. - if (!Replacement->hasDependentProtocolConformances()) { - assert(Conformance.size() == Archetype->getConformsTo().size() - && "substitution conformances don't match archetype"); - } } Substitution Substitution::subst(Module *module, @@ -89,78 +80,87 @@ Substitution Substitution::subst(Module *module, if (substReplacement->isEqual(Replacement)) return *this; - bool conformancesChanged = false; - SmallVector substConformance; - substConformance.reserve(Conformance.size()); - - // When substituting a concrete type for an archetype, we need to fill in the - // conformances. - if (auto replacementArch = Replacement->getAs()) { - if (!substReplacement->hasDependentProtocolConformances()) { - // Find the conformances mapped to the archetype. - auto found = conformanceMap.find(replacementArch); - assert(found != conformanceMap.end() - && "no conformances for replaced archetype?!"); + if (Conformance.empty()) { + return {substReplacement, Conformance}; + } - auto &foundConformances = found->second; + bool conformancesChanged = false; + SmallVector substConformances; + substConformances.reserve(Conformance.size()); - // If the substituted replacement archetype has no conformances, - // then there are no conformances to substitute. - if (foundConformances.empty()) - return Substitution{Archetype, substReplacement, Conformance}; + for (auto c : Conformance) { + // If we have a concrete conformance, we need to substitute the + // conformance to apply to the new type. + if (c.isConcrete()) { + auto substC = c.getConcrete()->subst(module, substReplacement, subs, + subMap, conformanceMap); + substConformances.push_back(ProtocolConformanceRef(substC)); + if (c != substConformances.back()) + conformancesChanged = true; + continue; + } - conformancesChanged = true; + // Otherwise, we may need to fill in the conformance. + ProtocolDecl *proto = c.getAbstract(); + Optional conformance; - // Get the conformances for the type that apply to the original + // If the original type was an archetype, check the conformance map. + if (auto replacementArch = Replacement->getAs()) { + // Check for conformances for the type that apply to the original // substituted archetype. - for (auto proto : Archetype->getConformsTo()) { - for (auto c : foundConformances) { - if (c->getProtocol() == proto) { - substConformance.push_back(c); - goto found_conformance; - } - if (c->getProtocol()->inheritsFrom(proto)) { - substConformance.push_back(c->getInheritedConformance(proto)); - goto found_conformance; + auto it = conformanceMap.find(replacementArch); + assert(it != conformanceMap.end()); + for (ProtocolConformanceRef found : it->second) { + auto foundProto = found.getRequirement(); + if (foundProto == proto) { + conformance = found; + break; + } else if (foundProto->inheritsFrom(proto)) { + if (found.isConcrete()) { + conformance = ProtocolConformanceRef( + found.getConcrete()->getInheritedConformance(proto)); + } else { + conformance = found; } + break; } - - // FIXME: AnyObject conformances can be synthesized from - // thin air. Gross. - if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) { - auto classDecl - = substReplacement->getClassOrBoundGenericClass(); - SmallVector conformances; - classDecl->lookupConformance(classDecl->getParentModule(), - proto, conformances); - substConformance.push_back(conformances.front()); - goto found_conformance; - } - - assert(false && "did not find conformance for archetype requirement?!"); -found_conformance:; } } - } else { - // If we substituted a concrete type for another, we need to substitute the - // conformance to apply to the new type. - for (auto c : Conformance) { - auto substC = c->subst(module, substReplacement, subs, - subMap, conformanceMap); - if (c != substC) + + // If that didn't find anything, we can still synthesize AnyObject + // conformances from thin air. FIXME: gross. + if (!conformance && + proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) { + auto classDecl + = substReplacement->getClassOrBoundGenericClass(); + SmallVector lookupResults; + classDecl->lookupConformance(classDecl->getParentModule(), + proto, lookupResults); + conformance = ProtocolConformanceRef(lookupResults.front()); + } + + if (conformance) { + if (conformance->isConcrete()) conformancesChanged = true; - substConformance.push_back(substC); + substConformances.push_back(*conformance); + } else { + assert(substReplacement->hasDependentProtocolConformances() && + "couldn't find concrete conformance for concrete type?"); + substConformances.push_back(ProtocolConformanceRef(proto)); } } + assert(substConformances.size() == Conformance.size()); - ArrayRef substConformanceRef; + ArrayRef substConfs; if (conformancesChanged) - substConformanceRef = module->getASTContext().AllocateCopy(substConformance); + substConfs = module->getASTContext().AllocateCopy(substConformances); else - substConformanceRef = Conformance; + substConfs = Conformance; - assert(substReplacement->hasDependentProtocolConformances() - || substConformanceRef.size() == Archetype->getConformsTo().size()); + return Substitution{substReplacement, substConfs}; +} - return Substitution{Archetype, substReplacement, substConformanceRef}; +SubstitutionIterator::SubstitutionIterator(GenericParamList *params, + ArrayRef subs) + : Archetypes(params->getAllArchetypes()), Subs(subs) { } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index cc4e2d4b6ec38..a6367432b7b06 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -721,7 +721,7 @@ static Type getStrippedType(const ASTContext &context, Type type, Type eltTy = getStrippedType(context, elt.getType(), stripLabels, stripDefaultArgs); if (anyChanged || eltTy.getPointer() != elt.getType().getPointer() || - (elt.hasInit() && stripDefaultArgs) || + (elt.hasDefaultArg() && stripDefaultArgs) || (elt.hasName() && stripLabels)) { if (!anyChanged) { elements.reserve(tuple->getNumElements()); @@ -765,38 +765,6 @@ Type TypeBase::getUnlabeledType(ASTContext &Context) { /*defaultArgs=*/true); } -Type TypeBase::getRelabeledType(ASTContext &ctx, - ArrayRef labels) { - if (auto tupleTy = dyn_cast(this)) { - assert(labels.size() == tupleTy->getNumElements() && - "Wrong number of labels"); - SmallVector elements; - unsigned i = 0; - bool anyChanged = false; - for (const auto &elt : tupleTy->getElements()) { - if (elt.getName() != labels[i]) - anyChanged = true; - - elements.push_back(TupleTypeElt(elt.getType(), labels[i], - elt.getDefaultArgKind(), elt.isVararg())); - ++i; - } - - if (!anyChanged) - return this; - - return TupleType::get(elements, ctx); - } - - // If there is no label, the type is unchanged. - if (labels[0].empty()) - return this; - - // Create a one-element tuple to capture the label. - TupleTypeElt elt(this, labels[0]); - return TupleType::get(elt, ctx); -} - Type TypeBase::getWithoutDefaultArgs(const ASTContext &Context) { return getStrippedType(Context, Type(this), /*labels=*/false, /*defaultArgs=*/true); @@ -956,22 +924,6 @@ TypeDecl *TypeBase::getDirectlyReferencedTypeDecl() const { return nullptr; } -StringRef TypeBase::getInferredDefaultArgString() { - if (auto structDecl = getStructOrBoundGenericStruct()) { - if (structDecl->getClangDecl()) { - for (auto attr : structDecl->getAttrs()) { - if (auto synthesizedProto = dyn_cast(attr)) { - if (synthesizedProto->getProtocolKind() - == KnownProtocolKind::OptionSetType) - return "[]"; - } - } - } - } - - return "nil"; -} - /// \brief Collect the protocols in the existential type T into the given /// vector. static void addProtocols(Type T, SmallVectorImpl &Protocols) { @@ -1501,7 +1453,7 @@ bool TypeBase::isSpelledLike(Type other) { return false; for (size_t i = 0, sz = tMe->getNumElements(); i < sz; ++i) { auto &myField = tMe->getElement(i), &theirField = tThem->getElement(i); - if (myField.hasInit() != theirField.hasInit()) + if (myField.hasDefaultArg() != theirField.hasDefaultArg()) return false; if (myField.getName() != theirField.getName()) @@ -1867,7 +1819,7 @@ bool TypeBase::canOverride(Type other, bool allowUnsafeParameterOverride, /// value. bool TupleType::hasAnyDefaultValues() const { for (const TupleTypeElt &Elt : Elements) - if (Elt.hasInit()) + if (Elt.hasDefaultArg()) return true; return false; } @@ -1893,7 +1845,7 @@ int TupleType::getElementForScalarInit() const { int FieldWithoutDefault = -1; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { // Ignore fields with a default value. - if (Elements[i].hasInit()) continue; + if (Elements[i].hasDefaultArg()) continue; // If we already saw a non-vararg field missing a default value, then we // cannot assign a scalar to this tuple. @@ -2253,6 +2205,7 @@ const { for (auto &reqt : getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: + case RequirementKind::Superclass: case RequirementKind::WitnessMarker: // Substituting the parameter eliminates conformance constraints rooted // in the parameter. @@ -2313,9 +2266,12 @@ static Type getMemberForBaseType(Module *module, // If the parent is an archetype, extract the child archetype with the // given name. if (auto archetypeParent = substBase->getAs()) { - if (!archetypeParent->hasNestedType(name) && - archetypeParent->getParent()->isSelfDerived()) { - return archetypeParent->getParent()->getNestedTypeValue(name); + if (!archetypeParent->hasNestedType(name)) { + const auto parent = archetypeParent->getParent(); + if (!parent) + return ErrorType::get(module->getASTContext()); + if (parent->isSelfDerived()) + return parent->getNestedTypeValue(name); } return archetypeParent->getNestedTypeValue(name); @@ -2503,6 +2459,7 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(DeclContext *dc) { // Find the superclass type with the context matching that of the member. auto ownerNominal = dc->isNominalTypeOrNominalTypeExtensionContext(); while (!baseTy->is() && + baseTy->getAnyNominal() && baseTy->getAnyNominal() != ownerNominal) { baseTy = baseTy->getSuperclass(resolver); assert(baseTy && "Couldn't find appropriate context"); diff --git a/lib/AST/TypeRefinementContext.cpp b/lib/AST/TypeRefinementContext.cpp index 112b4567b6da1..62d04471375d7 100644 --- a/lib/AST/TypeRefinementContext.cpp +++ b/lib/AST/TypeRefinementContext.cpp @@ -1,8 +1,8 @@ -//===--- TypeRefinementContext.cpp - Swift Refinement Context ---*- C++ -*-===// +//===--- TypeRefinementContext.cpp - Swift Refinement Context -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index f851be94f0ea3..5d3d0db17debf 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -1,8 +1,8 @@ -//===--- TypeRepr.cpp - Swift Language Type Representation ------*- C++ -*-===// +//===--- TypeRepr.cpp - Swift Language Type Representation ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -68,7 +68,8 @@ SourceRange TypeRepr::getSourceRange() const { } /// Standard allocator for TypeReprs. -void *TypeRepr::operator new(size_t Bytes, ASTContext &C, unsigned Alignment) { +void *TypeRepr::operator new(size_t Bytes, const ASTContext &C, + unsigned Alignment) { return C.Allocate(Bytes, Alignment); } @@ -106,10 +107,10 @@ void TypeRepr::print(ASTPrinter &Printer, const PrintOptions &Opts) const { namespace { class CloneVisitor : public TypeReprVisitor { - ASTContext &Ctx; + const ASTContext &Ctx; public: - explicit CloneVisitor(ASTContext &ctx) : Ctx(ctx) { } + explicit CloneVisitor(const ASTContext &ctx) : Ctx(ctx) { } #define TYPEREPR(CLASS, PARENT) \ TypeRepr *visit##CLASS##TypeRepr(CLASS##TypeRepr* type); @@ -157,8 +158,7 @@ TypeRepr *CloneVisitor::visitFunctionTypeRepr(FunctionTypeRepr *T) { } TypeRepr *CloneVisitor::visitArrayTypeRepr(ArrayTypeRepr *T) { - return new (Ctx) ArrayTypeRepr(visit(T->getBase()), T->getSize(), - T->getBrackets(), T->usesOldSyntax()); + return new (Ctx) ArrayTypeRepr(visit(T->getBase()), T->getBrackets()); } TypeRepr *CloneVisitor::visitDictionaryTypeRepr(DictionaryTypeRepr *T) { @@ -221,7 +221,7 @@ TypeRepr *CloneVisitor::visitFixedTypeRepr(FixedTypeRepr *T) { return new (Ctx) FixedTypeRepr(T->getType(), T->getLoc()); } -TypeRepr *TypeRepr::clone(ASTContext &ctx) const { +TypeRepr *TypeRepr::clone(const ASTContext &ctx) const { CloneVisitor visitor(ctx); return visitor.visit(const_cast(this)); } @@ -337,17 +337,9 @@ void FunctionTypeRepr::printImpl(ASTPrinter &Printer, void ArrayTypeRepr::printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const { - if (usesOldSyntax()) { - printTypeRepr(Base, Printer, Opts); - Printer << "["; - if (auto size = getSize()) - size->getExpr()->print(Printer, Opts); - Printer << "]"; - } else { - Printer << "["; - printTypeRepr(Base, Printer, Opts); - Printer << "]"; - } + Printer << "["; + printTypeRepr(getBase(), Printer, Opts); + Printer << "]"; } void DictionaryTypeRepr::printImpl(ASTPrinter &Printer, diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 5813f4165b3c2..580a44c9462f2 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -97,6 +97,7 @@ class Traversal : public TypeVisitor switch (req.getKind()) { case RequirementKind::SameType: case RequirementKind::Conformance: + case RequirementKind::Superclass: if (doIt(req.getSecondType())) return true; break; diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index 533c0d23cb1a2..533b11bcf9283 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -1,8 +1,8 @@ -//===--- USRGeneration.h - Routines for USR generation --------------------===// +//===--- USRGeneration.cpp - Routines for USR generation ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -71,22 +71,22 @@ bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { return true; OS << getUSRSpacePrefix(); - Mangler Mangler(OS); + Mangler Mangler; if (auto Ctor = dyn_cast(VD)) { Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false, - ResilienceExpansion::Minimal, /*uncurryingLevel=*/0); + /*uncurryingLevel=*/0); } else if (auto Dtor = dyn_cast(VD)) { Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false); } else if (auto NTD = dyn_cast(VD)) { - Mangler.mangleNominalType(NTD, ResilienceExpansion::Minimal, - Mangler::BindGenerics::None); + Mangler.mangleNominalType(NTD, Mangler::BindGenerics::None); } else if (isa(VD) || isa(VD)) { Mangler.mangleContextOf(VD, Mangler::BindGenerics::None); Mangler.mangleDeclName(VD); } else { - Mangler.mangleEntity(VD, ResilienceExpansion::Minimal, - /*uncurryingLevel=*/0); + Mangler.mangleEntity(VD, /*uncurryingLevel=*/0); } + + Mangler.finalize(OS); return false; } @@ -108,9 +108,9 @@ bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind, AbstractStorageDecl *SD = const_cast(D); OS << getUSRSpacePrefix(); - Mangler Mangler(OS); - Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, - SD, ResilienceExpansion::Minimal); + Mangler Mangler; + Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, SD); + Mangler.finalize(OS); return false; } diff --git a/lib/ASTSectionImporter/ASTSectionImporter.cpp b/lib/ASTSectionImporter/ASTSectionImporter.cpp index 607534e467c09..2a237eb26d01d 100644 --- a/lib/ASTSectionImporter/ASTSectionImporter.cpp +++ b/lib/ASTSectionImporter/ASTSectionImporter.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 68b95ffb2aa0b..d8f14e719413f 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -82,6 +82,7 @@ add_swift_library(swiftBasic StringExtras.cpp TaskQueue.cpp ThreadSafeRefCounted.cpp + Timer.cpp Unicode.cpp UUID.cpp Version.cpp diff --git a/lib/Basic/Cache.cpp b/lib/Basic/Cache.cpp index d8464920d9287..928b3b09fa296 100644 --- a/lib/Basic/Cache.cpp +++ b/lib/Basic/Cache.cpp @@ -1,14 +1,14 @@ -//===--- Cache.h - Caching mechanism implementation -----------------------===// +//===--- Cache.cpp - Caching mechanism implementation ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #if defined(__APPLE__) #include "Darwin/Cache-Mac.cpp" diff --git a/lib/Basic/ClusteredBitVector.cpp b/lib/Basic/ClusteredBitVector.cpp index 002195de0bb4c..65e38016822f0 100644 --- a/lib/Basic/ClusteredBitVector.cpp +++ b/lib/Basic/ClusteredBitVector.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Darwin/Cache-Mac.cpp b/lib/Basic/Darwin/Cache-Mac.cpp index 557ba5f36c72e..c617ac251dc46 100644 --- a/lib/Basic/Darwin/Cache-Mac.cpp +++ b/lib/Basic/Darwin/Cache-Mac.cpp @@ -1,18 +1,18 @@ -//===--- Cache.h - Caching mechanism implementation -----------------------===// +//===--- Cache-Mac.cpp - Caching mechanism implementation -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This file implements the caching mechanism using darwin's libcache. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "swift/Basic/Cache.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Basic/Default/TaskQueue.inc b/lib/Basic/Default/TaskQueue.inc index 21097bbcb6453..118df97464391 100644 --- a/lib/Basic/Default/TaskQueue.inc +++ b/lib/Basic/Default/TaskQueue.inc @@ -1,8 +1,8 @@ -//===--- Default/TaskQueue.inc - Default serial TaskQueue -------*- C++ -*-===// +//===--- TaskQueue.inc - Default serial TaskQueue ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Demangle.cpp b/lib/Basic/Demangle.cpp index 3c1d28efd6cc1..17851600a3df0 100644 --- a/lib/Basic/Demangle.cpp +++ b/lib/Basic/Demangle.cpp @@ -2,17 +2,17 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This file implements declaration name demangling in Swift. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "swift/Basic/Demangle.h" #include "swift/Basic/Fallthrough.h" @@ -197,12 +197,6 @@ class NameSource { return true; } - bool nextIfNot(char c) { - if (isEmpty() || peek() == c) return false; - advanceOffset(1); - return true; - } - /// Claim the next few characters if they exactly match the given string. bool nextIf(StringRef str) { if (!Text.startswith(str)) return false; @@ -376,10 +370,6 @@ class Demangler { } private: - enum class IsProtocol { - yes = true, no = false - }; - enum class IsVariadic { yes = true, no = false }; @@ -577,6 +567,18 @@ class Demangler { DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance); return witnessTable; } + if (Mangled.nextIf('G')) { + auto witnessTable = + NodeFactory::create(Node::Kind::GenericProtocolWitnessTable); + DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance); + return witnessTable; + } + if (Mangled.nextIf('I')) { + auto witnessTable = NodeFactory::create( + Node::Kind::GenericProtocolWitnessTableInstantiationFunction); + DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance); + return witnessTable; + } if (Mangled.nextIf('l')) { auto accessor = NodeFactory::create(Node::Kind::LazyProtocolWitnessTableAccessor); @@ -597,17 +599,20 @@ class Demangler { DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance); return tableTemplate; } - if (Mangled.nextIf('D')) { - auto tableGenerator = NodeFactory::create( - Node::Kind::DependentProtocolWitnessTableGenerator); - DEMANGLE_CHILD_OR_RETURN(tableGenerator, ProtocolConformance); - return tableGenerator; + if (Mangled.nextIf('t')) { + auto accessor = NodeFactory::create( + Node::Kind::AssociatedTypeMetadataAccessor); + DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance); + DEMANGLE_CHILD_OR_RETURN(accessor, DeclName); + return accessor; } - if (Mangled.nextIf('d')) { - auto tableTemplate = NodeFactory::create( - Node::Kind::DependentProtocolWitnessTableTemplate); - DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance); - return tableTemplate; + if (Mangled.nextIf('T')) { + auto accessor = NodeFactory::create( + Node::Kind::AssociatedTypeWitnessTableAccessor); + DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance); + DEMANGLE_CHILD_OR_RETURN(accessor, DeclName); + DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName); + return accessor; } return nullptr; } @@ -1883,6 +1888,16 @@ class Demangler { type_application->addChild(type_list); return type_application; } + if (c == 'X') { + if (Mangled.nextIf('b')) { + NodePointer type = demangleType(); + if (!type) + return nullptr; + NodePointer boxType = NodeFactory::create(Node::Kind::SILBoxType); + boxType->addChild(type); + return boxType; + } + } if (c == 'K') { return demangleFunctionType(Node::Kind::AutoClosureType); } @@ -2331,6 +2346,7 @@ class NodePrinter { case Node::Kind::QualifiedArchetype: case Node::Kind::ReturnType: case Node::Kind::SelfTypeRef: + case Node::Kind::SILBoxType: case Node::Kind::Structure: case Node::Kind::TupleElementName: case Node::Kind::Type: @@ -2341,6 +2357,8 @@ class NodePrinter { case Node::Kind::Allocator: case Node::Kind::ArgumentTuple: + case Node::Kind::AssociatedTypeMetadataAccessor: + case Node::Kind::AssociatedTypeWitnessTableAccessor: case Node::Kind::AutoClosureType: case Node::Kind::CFunctionPointer: case Node::Kind::Constructor: @@ -2352,8 +2370,6 @@ class NodePrinter { case Node::Kind::DependentGenericParamCount: case Node::Kind::DependentGenericConformanceRequirement: case Node::Kind::DependentGenericSameTypeRequirement: - case Node::Kind::DependentProtocolWitnessTableGenerator: - case Node::Kind::DependentProtocolWitnessTableTemplate: case Node::Kind::Destructor: case Node::Kind::DidSet: case Node::Kind::DirectMethodReferenceAttribute: @@ -2370,6 +2386,8 @@ class NodePrinter { case Node::Kind::FunctionSignatureSpecializationParamPayload: case Node::Kind::FunctionType: case Node::Kind::Generics: + case Node::Kind::GenericProtocolWitnessTable: + case Node::Kind::GenericProtocolWitnessTableInstantiationFunction: case Node::Kind::GenericSpecialization: case Node::Kind::GenericSpecializationParam: case Node::Kind::GenericType: @@ -2510,7 +2528,7 @@ class NodePrinter { return; } - if (Options.SynthesizeSugarOnTypes == false || + if (!Options.SynthesizeSugarOnTypes || pointer->getKind() == Node::Kind::BoundGenericClass) { // no sugar here @@ -2844,10 +2862,10 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) assert((pointer->getNumChildren() == 2 || pointer->getNumChildren() == 3) && "Extension expects 2 or 3 children."); if (Options.QualifyEntities && Options.DisplayExtensionContexts) { - Printer << "ext."; + Printer << "(extension in "; // Print the module where extension is defined. print(pointer->getChild(0), true); - Printer << "."; + Printer << "):"; } print(pointer->getChild(1), asContext); if (pointer->getNumChildren() == 3) @@ -3154,14 +3172,6 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) case Node::Kind::PostfixOperator: Printer << pointer->getText() << " postfix"; return; - case Node::Kind::DependentProtocolWitnessTableGenerator: - Printer << "dependent protocol witness table generator for "; - print(pointer->getFirstChild()); - return; - case Node::Kind::DependentProtocolWitnessTableTemplate: - Printer << "dependent protocol witness table template for "; - print(pointer->getFirstChild()); - return; case Node::Kind::LazyProtocolWitnessTableAccessor: Printer << "lazy protocol witness table accessor for type "; print(pointer->getChild(0)); @@ -3182,6 +3192,14 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) Printer << "protocol witness table for "; print(pointer->getFirstChild()); return; + case Node::Kind::GenericProtocolWitnessTable: + Printer << "generic protocol witness table for "; + print(pointer->getFirstChild()); + return; + case Node::Kind::GenericProtocolWitnessTableInstantiationFunction: + Printer << "instantiation function for generic protocol witness table for "; + print(pointer->getFirstChild()); + return; case Node::Kind::ProtocolWitness: { Printer << "protocol witness for "; print(pointer->getChild(1)); @@ -3268,6 +3286,20 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) Printer << "lazy cache variable for type metadata for "; print(pointer->getChild(0)); return; + case Node::Kind::AssociatedTypeMetadataAccessor: + Printer << "associated type metadata accessor for "; + print(pointer->getChild(1)); + Printer << " in "; + print(pointer->getChild(0)); + return; + case Node::Kind::AssociatedTypeWitnessTableAccessor: + Printer << "associated type witness table accessor for "; + print(pointer->getChild(1)); + Printer << " : "; + print(pointer->getChild(2)); + Printer << " in "; + print(pointer->getChild(0)); + return; case Node::Kind::NominalTypeDescriptor: Printer << "nominal type descriptor for "; print(pointer->getChild(0)); @@ -3304,6 +3336,12 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType) printFunctionType(pointer); return; } + case Node::Kind::SILBoxType: { + Printer << "@box "; + NodePointer type = pointer->getChild(0); + print(type); + return; + } case Node::Kind::Metatype: { unsigned Idx = 0; if (pointer->getNumChildren() == 2) { diff --git a/lib/Basic/DemangleWrappers.cpp b/lib/Basic/DemangleWrappers.cpp index 816c741819f23..adc5b58d69b67 100644 --- a/lib/Basic/DemangleWrappers.cpp +++ b/lib/Basic/DemangleWrappers.cpp @@ -1,14 +1,14 @@ -//===--- DemangleWrappers.cpp - Swift Name Demangling --------------------===// +//===--- DemangleWrappers.cpp - Swift Name Demangling ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "swift/Basic/DemangleWrappers.h" #include "swift/Basic/PrettyStackTrace.h" diff --git a/lib/Basic/DiagnosticConsumer.cpp b/lib/Basic/DiagnosticConsumer.cpp index fc94798b8c815..cc333eacf2ced 100644 --- a/lib/Basic/DiagnosticConsumer.cpp +++ b/lib/Basic/DiagnosticConsumer.cpp @@ -1,8 +1,8 @@ -//===- DiagnosticConsumer.cpp - Diagnostic Consumer Impl --------*- C++ -*-===// +//===--- DiagnosticConsumer.cpp - Diagnostic Consumer Impl ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/DiverseStack.cpp b/lib/Basic/DiverseStack.cpp index c3d47c7dc9ab9..4f738b28a4b24 100644 --- a/lib/Basic/DiverseStack.cpp +++ b/lib/Basic/DiverseStack.cpp @@ -1,8 +1,8 @@ -//===--- DiverseStack.cpp - Out-of-line code for the heterogeneous stack ---===// +//===--- DiverseStack.cpp - Out-of-line code for the heterogeneous stack --===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/EditorPlaceholder.cpp b/lib/Basic/EditorPlaceholder.cpp index fa6983dd73ac7..76b5257b176f3 100644 --- a/lib/Basic/EditorPlaceholder.cpp +++ b/lib/Basic/EditorPlaceholder.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/FileSystem.cpp b/lib/Basic/FileSystem.cpp index fd842fe0cefbc..035f0d3f51043 100644 --- a/lib/Basic/FileSystem.cpp +++ b/lib/Basic/FileSystem.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/JSONSerialization.cpp b/lib/Basic/JSONSerialization.cpp index 76da55de80438..ed17af9d6507c 100644 --- a/lib/Basic/JSONSerialization.cpp +++ b/lib/Basic/JSONSerialization.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -207,8 +207,7 @@ void Output::scalarString(StringRef &S, bool MustQuote) { // Convert the current character into hexadecimal digits. Stream << llvm::hexdigit((c >> 4) & 0xF); Stream << llvm::hexdigit((c >> 0) & 0xF); - } - else { + } else { // This isn't a control character, so we don't need to escape it. // As a result, emit it directly; if it's part of a multi-byte UTF8 // representation, all bytes will be emitted in this fashion. diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index ae8c69d125368..9c29ef2af9821 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -36,7 +36,9 @@ const std::vector LangOptions::SupportedArchBuildConfigArguments = "arm", "arm64", "i386", - "x86_64" + "x86_64", + "powerpc64", + "powerpc64le" }; bool LangOptions::isOSBuildConfigSupported(llvm::StringRef OSName) { @@ -115,6 +117,12 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { case llvm::Triple::ArchType::aarch64: addTargetConfigOption("arch", "arm64"); break; + case llvm::Triple::ArchType::ppc64: + addTargetConfigOption("arch", "powerpc64"); + break; + case llvm::Triple::ArchType::ppc64le: + addTargetConfigOption("arch", "powerpc64le"); + break; case llvm::Triple::ArchType::x86: addTargetConfigOption("arch", "i386"); break; diff --git a/lib/Basic/PartsOfSpeech.def b/lib/Basic/PartsOfSpeech.def index 9af825f84671c..dec4af5d728e4 100644 --- a/lib/Basic/PartsOfSpeech.def +++ b/lib/Basic/PartsOfSpeech.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // This file lists words that map to various parts of speech. -// ===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #if !defined(PREPOSITION) && !defined(VERB) # error define one or more of PREPOSITION, VERB @@ -28,10 +28,6 @@ # define VERB(Word) #endif -#ifndef AUXILIARY_VERB -# define AUXILIARY_VERB(Word) -#endif - DIRECTIONAL_PREPOSITION(above) DIRECTIONAL_PREPOSITION(after) DIRECTIONAL_PREPOSITION(along) @@ -842,33 +838,6 @@ VERB(yell) VERB(zip) VERB(zoom) -AUXILIARY_VERB(am) -AUXILIARY_VERB(are) -AUXILIARY_VERB(been) -AUXILIARY_VERB(being) -AUXILIARY_VERB(can) -AUXILIARY_VERB(could) -AUXILIARY_VERB(did) -AUXILIARY_VERB(does) -AUXILIARY_VERB(had) -AUXILIARY_VERB(has) -AUXILIARY_VERB(have) -AUXILIARY_VERB(having) -AUXILIARY_VERB(is) -AUXILIARY_VERB(may) -AUXILIARY_VERB(might) -AUXILIARY_VERB(must) -AUXILIARY_VERB(need) -AUXILIARY_VERB(needs) -AUXILIARY_VERB(ought) -AUXILIARY_VERB(shall) -AUXILIARY_VERB(should) -AUXILIARY_VERB(was) -AUXILIARY_VERB(were) -AUXILIARY_VERB(will) -AUXILIARY_VERB(would) - -#undef AUXILIARY_VERB #undef VERB #undef DIRECTIONAL_PREPOSITION #undef PREPOSITION diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index a620f9e9e13af..2dcef79ec8f1f 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -1,8 +1,8 @@ -//===-- Platform.cpp - Implement platform-related helpers -------*- C++ -*-===// +//===--- Platform.cpp - Implement platform-related helpers ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/PrefixMap.cpp b/lib/Basic/PrefixMap.cpp index 585ead7862568..09327feb73e96 100644 --- a/lib/Basic/PrefixMap.cpp +++ b/lib/Basic/PrefixMap.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/PrettyStackTrace.cpp b/lib/Basic/PrettyStackTrace.cpp index c5dbf1e3efaf9..324d737c8c045 100644 --- a/lib/Basic/PrettyStackTrace.cpp +++ b/lib/Basic/PrettyStackTrace.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/PrimitiveParsing.cpp b/lib/Basic/PrimitiveParsing.cpp index cc5455d2716fe..92e09284e0a99 100644 --- a/lib/Basic/PrimitiveParsing.cpp +++ b/lib/Basic/PrimitiveParsing.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Program.cpp b/lib/Basic/Program.cpp index a82b50a68b42f..ef6f1f58d5c2f 100644 --- a/lib/Basic/Program.cpp +++ b/lib/Basic/Program.cpp @@ -1,8 +1,8 @@ -//===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// +//===--- Program.cpp - Implement OS Program Concept -----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Punycode.cpp b/lib/Basic/Punycode.cpp index cfa64acc73b44..52cc1a6c9dba7 100644 --- a/lib/Basic/Punycode.cpp +++ b/lib/Basic/Punycode.cpp @@ -1,8 +1,8 @@ -//===--- Punycode.cpp - Unicode to Punycode transcoding ---------*- C++ -*-===// +//===--- Punycode.cpp - Unicode to Punycode transcoding -------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/PunycodeUTF8.cpp b/lib/Basic/PunycodeUTF8.cpp index 0c4fa405a9208..159abc1ba41c2 100644 --- a/lib/Basic/PunycodeUTF8.cpp +++ b/lib/Basic/PunycodeUTF8.cpp @@ -1,8 +1,8 @@ -//===--- PunycodeUTF8.cpp - Unicode to Punycode transcoding -----*- C++ -*-===// +//===--- PunycodeUTF8.cpp - Unicode to Punycode transcoding ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/QuotedString.cpp b/lib/Basic/QuotedString.cpp index 62e7a08c51c3c..41a0bc629b0a5 100644 --- a/lib/Basic/QuotedString.cpp +++ b/lib/Basic/QuotedString.cpp @@ -1,8 +1,8 @@ -//===--- QuotedString.cpp - Printing a string as a quoted string ---------===// +//===--- QuotedString.cpp - Printing a string as a quoted string ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Remangle.cpp b/lib/Basic/Remangle.cpp index 207cc8344ea2b..a355bff03df98 100644 --- a/lib/Basic/Remangle.cpp +++ b/lib/Basic/Remangle.cpp @@ -1,20 +1,20 @@ -//===--- Remangle.cpp - Swift re-mangling from a demangling tree ---------===// +//===--- Remangle.cpp - Swift re-mangling from a demangling tree ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This file implements the remangler, which turns a demangling parse // tree back into a mangled string. This is useful for tools which // want to extract subtrees from mangled strings. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "swift/Basic/Demangle.h" #include "swift/Basic/LLVM.h" @@ -70,6 +70,16 @@ static bool isNonAscii(StringRef str) { return false; } +static char mangleOperatorKind(OperatorKind operatorKind) { + switch (operatorKind) { + case OperatorKind::NotOperator: unreachable("invalid"); + case OperatorKind::Infix: return 'i'; + case OperatorKind::Prefix: return 'p'; + case OperatorKind::Postfix: return 'P'; + } + unreachable("invalid"); +} + static void mangleIdentifier(StringRef ident, OperatorKind operatorKind, bool usePunycode, DemanglerPrinter &out) { std::string punycodeBuf; @@ -99,15 +109,7 @@ static void mangleIdentifier(StringRef ident, OperatorKind operatorKind, // operator-fixity ::= 'i' // infix // where the count is the number of characters in the operator, // and where the individual operator characters are translated. - out << 'o' << [=] { - switch (operatorKind) { - case OperatorKind::NotOperator: unreachable("invalid"); - case OperatorKind::Infix: return 'i'; - case OperatorKind::Prefix: return 'p'; - case OperatorKind::Postfix: return 'P'; - } - unreachable("invalid"); - }(); + out << 'o' << mangleOperatorKind(operatorKind); // Mangle ASCII operators directly. out << ident.size(); @@ -698,6 +700,17 @@ void Remangler::mangleProtocolWitnessTable(Node *node) { mangleSingleChildNode(node); // protocol conformance } +void Remangler::mangleGenericProtocolWitnessTable(Node *node) { + Out << "WG"; + mangleSingleChildNode(node); // protocol conformance +} + +void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction( + Node *node) { + Out << "WI"; + mangleSingleChildNode(node); // protocol conformance +} + void Remangler::mangleProtocolWitnessTableAccessor(Node *node) { Out << "Wa"; mangleSingleChildNode(node); // protocol conformance @@ -713,14 +726,17 @@ void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) { mangleChildNodes(node); // type, protocol conformance } -void Remangler::mangleDependentProtocolWitnessTableGenerator(Node *node) { - Out << "WD"; - mangleSingleChildNode(node); // protocol conformance +void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) { + Out << "Wt"; + mangleChildNodes(node); // protocol conformance, identifier } -void Remangler::mangleDependentProtocolWitnessTableTemplate(Node *node) { - Out << "Wd"; - mangleSingleChildNode(node); // protocol conformance +void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) { + Out << "WT"; + assert(node->getNumChildren() == 3); + mangleChildNode(node, 0); // protocol conformance + mangleChildNode(node, 1); // identifier + mangleProtocolWithoutPrefix(node->begin()[2].get()); // type } void Remangler::mangleReabstractionThunkHelper(Node *node) { @@ -1160,6 +1176,11 @@ void Remangler::mangleErrorType(Node *node) { Out << "ERR"; } +void Remangler::mangleSILBoxType(Node *node) { + Out << 'X' << 'b'; + mangleSingleChildNode(node); +} + void Remangler::mangleMetatype(Node *node) { if (node->getNumChildren() == 1) { Out << 'M'; diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 43940d566c8ce..9bc484c5eb7a7 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/StringExtras.cpp b/lib/Basic/StringExtras.cpp index 0716959bf4c2c..299479f1660c3 100644 --- a/lib/Basic/StringExtras.cpp +++ b/lib/Basic/StringExtras.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,6 +27,13 @@ using namespace swift; using namespace camel_case; +bool swift::canBeArgumentLabel(StringRef identifier) { + if (identifier == "var" || identifier == "let" || identifier == "inout") + return false; + + return true; +} + PrepositionKind swift::getPrepositionKind(StringRef word) { #define DIRECTIONAL_PREPOSITION(Word) \ if (word.equals_lower(#Word)) \ @@ -47,9 +54,6 @@ PartOfSpeech swift::getPartOfSpeech(StringRef word) { #define VERB(Word) \ if (word.equals_lower(#Word)) \ return PartOfSpeech::Verb; -#define AUXILIARY_VERB(Word) \ - if (word.equals_lower(#Word)) \ - return PartOfSpeech::AuxiliaryVerb; #include "PartsOfSpeech.def" // Identify gerunds, which always end in "ing". @@ -511,16 +515,26 @@ static StringRef omitNeedlessWords(StringRef name, // name. auto nameWordRevIter = nameWords.rbegin(), nameWordRevIterBegin = nameWordRevIter, + firstMatchingNameWordRevIter = nameWordRevIter, nameWordRevIterEnd = nameWords.rend(); auto typeWordRevIter = typeWords.rbegin(), typeWordRevIterEnd = typeWords.rend(); + + bool anyMatches = false; + auto matched = [&] { + if (anyMatches) return; + + anyMatches = true; + firstMatchingNameWordRevIter = nameWordRevIter; + }; + while (nameWordRevIter != nameWordRevIterEnd && typeWordRevIter != typeWordRevIterEnd) { // If the names match, continue. auto nameWord = *nameWordRevIter; if (matchNameWordToTypeWord(nameWord, *typeWordRevIter)) { - anyMatches = true; + matched(); ++nameWordRevIter; ++typeWordRevIter; continue; @@ -535,7 +549,7 @@ static StringRef omitNeedlessWords(StringRef name, ++nextTypeWordRevIter; if (nextTypeWordRevIter != typeWordRevIterEnd && matchNameWordToTypeWord("Index", *nextTypeWordRevIter)) { - anyMatches = true; + matched(); ++nameWordRevIter; typeWordRevIter = nextTypeWordRevIter; ++typeWordRevIter; @@ -547,7 +561,7 @@ static StringRef omitNeedlessWords(StringRef name, if (matchNameWordToTypeWord(nameWord, "Index") && (matchNameWordToTypeWord("Int", *typeWordRevIter) || matchNameWordToTypeWord("Integer", *typeWordRevIter))) { - anyMatches = true; + matched(); ++nameWordRevIter; ++typeWordRevIter; continue; @@ -556,7 +570,7 @@ static StringRef omitNeedlessWords(StringRef name, // Special case: if the word in the name ends in 's', and we have // a collection element type, see if this is a plural. if (!typeName.CollectionElement.empty() && nameWord.size() > 2 && - nameWord.back() == 's') { + nameWord.back() == 's' && role != NameRole::BaseNameSelf) { // Check s. auto shortenedNameWord = name.substr(0, nameWordRevIter.base().getPosition()-1); @@ -564,7 +578,7 @@ static StringRef omitNeedlessWords(StringRef name, = omitNeedlessWords(shortenedNameWord, typeName.CollectionElement, NameRole::Partial, allPropertyNames, scratch); if (shortenedNameWord != newShortenedNameWord) { - anyMatches = true; + matched(); unsigned targetSize = newShortenedNameWord.size(); while (nameWordRevIter.base().getPosition() > targetSize) ++nameWordRevIter; @@ -583,6 +597,14 @@ static StringRef omitNeedlessWords(StringRef name, } } + // If we're matching the base name of a method against the type of + // 'Self', and we haven't matched anything yet, skip over words in + // the name. + if (role == NameRole::BaseNameSelf && !anyMatches) { + ++nameWordRevIter; + continue; + } + break; } @@ -599,12 +621,41 @@ static StringRef omitNeedlessWords(StringRef name, return name; } + // Don't strip just "Error". + if (nameWordRevIter != nameWordRevIterBegin) { + auto nameWordPrev = std::prev(nameWordRevIter); + if (nameWordPrev == nameWordRevIterBegin && *nameWordPrev == "Error") + return name; + } + switch (role) { case NameRole::Property: // Always strip off type information. name = name.substr(0, nameWordRevIter.base().getPosition()); break; + case NameRole::BaseNameSelf: + switch (getPartOfSpeech(*nameWordRevIter)) { + case PartOfSpeech::Verb: { + // Splice together the parts before and after the matched + // type. For example, if we matched "ViewController" in + // "dismissViewControllerAnimated", stitch together + // "dismissAnimated". + SmallString<16> newName = + name.substr(0, nameWordRevIter.base().getPosition()); + newName + += name.substr(firstMatchingNameWordRevIter.base().getPosition()); + name = scratch.copyString(newName); + break; + } + + case PartOfSpeech::Preposition: + case PartOfSpeech::Gerund: + case PartOfSpeech::Unknown: + return name; + } + break; + case NameRole::BaseName: case NameRole::FirstParameter: case NameRole::Partial: @@ -664,7 +715,6 @@ static StringRef omitNeedlessWords(StringRef name, break; case PartOfSpeech::Unknown: - case PartOfSpeech::AuxiliaryVerb: // Assume it's a noun or adjective; don't strip anything. break; } @@ -679,6 +729,7 @@ static StringRef omitNeedlessWords(StringRef name, switch (role) { case NameRole::BaseName: + case NameRole::BaseNameSelf: case NameRole::Property: // If we ended up with a keyword for a property name or base name, // do nothing. @@ -696,21 +747,9 @@ static StringRef omitNeedlessWords(StringRef name, return name; } -/// Determine whether the given word indicates a boolean result. -static bool nameIndicatesBooleanResult(StringRef name) { - for (auto word: camel_case::getWords(name)) { - // Auxiliary verbs indicate Boolean results. - if (getPartOfSpeech(word) == PartOfSpeech::AuxiliaryVerb) - return true; - - // Words that end in "s" indicate either Boolean results---it - // could be a verb in the present continuous tense---or some kind - // of plural, for which "is" would be inappropriate anyway. - if (word.back() == 's') - return true; - } - - return false; +/// Whether the given word is a plural s +static bool isPluralSuffix(StringRef word) { + return word == "s" || word == "es" || word == "ies"; } /// A form of toLowercaseWord that also lowercases acronyms. @@ -723,12 +762,21 @@ static StringRef toLowercaseWordAndAcronym(StringRef string, if (!clang::isUppercase(string[0])) return string; - // Lowercase until we hit the end there is an uppercase letter - // followed by a non-uppercase letter. + // Lowercase until we hit the an uppercase letter followed by a + // non-uppercase letter. llvm::SmallString<32> scratchStr; for (unsigned i = 0, n = string.size(); i != n; ++i) { // If the next character is not uppercase, stop. if (i < n - 1 && !clang::isUppercase(string[i+1])) { + // If the next non-uppercase character was not a letter, we seem + // to have a plural, we should still lowercase the character + // we're on. + if (!clang::isLetter(string[i+1]) || + isPluralSuffix(camel_case::getFirstWord(string.substr(i+1)))) { + scratchStr.push_back(clang::toLowercase(string[i])); + ++i; + } + scratchStr.append(string.substr(i)); break; } @@ -783,7 +831,17 @@ bool swift::omitNeedlessWords(StringRef &baseName, } } - // Treat zero-parameter methods and properties the same way. + // Strip the context type from the base name of a method. + if (!isProperty) { + StringRef newBaseName = ::omitNeedlessWords(baseName, contextType, + NameRole::BaseNameSelf, + nullptr, scratch); + if (newBaseName != baseName) { + baseName = newBaseName; + anyChanges = true; + } + } + if (paramTypes.empty()) { if (resultTypeMatchesContext) { StringRef newBaseName = ::omitNeedlessWords( @@ -798,16 +856,6 @@ bool swift::omitNeedlessWords(StringRef &baseName, } } - // Boolean properties should start with "is", unless their - // first word already implies a Boolean result. - if (resultType.isBoolean() && isProperty && - !nameIndicatesBooleanResult(baseName)) { - SmallString<32> newName("is"); - camel_case::appendSentenceCase(newName, baseName); - baseName = scratch.copyString(newName); - anyChanges = true; - } - return lowercaseAcronymsForReturn(); } @@ -857,7 +905,6 @@ bool swift::omitNeedlessWords(StringRef &baseName, break; case PartOfSpeech::Unknown: - case PartOfSpeech::AuxiliaryVerb: ++nameWordRevIter; break; } diff --git a/lib/Basic/TaskQueue.cpp b/lib/Basic/TaskQueue.cpp index 4335a8dba8a84..cedd7ec98d971 100644 --- a/lib/Basic/TaskQueue.cpp +++ b/lib/Basic/TaskQueue.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/ThreadSafeRefCounted.cpp b/lib/Basic/ThreadSafeRefCounted.cpp index 87898fc33a3f7..09f728fc7224d 100644 --- a/lib/Basic/ThreadSafeRefCounted.cpp +++ b/lib/Basic/ThreadSafeRefCounted.cpp @@ -1,8 +1,8 @@ -//===--- ThreadSafeRefCounted.h - Thread-safe Refcounting Base ------------===// +//===--- ThreadSafeRefCounted.cpp - Thread-safe Refcounting Base ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Timer.cpp b/lib/Basic/Timer.cpp new file mode 100644 index 0000000000000..98d64a45d2e9d --- /dev/null +++ b/lib/Basic/Timer.cpp @@ -0,0 +1,17 @@ +//===--- Timer.cpp - Shared timers for compilation phases -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/Timer.h" + +using namespace swift; + +SharedTimer::State SharedTimer::CompilationTimersEnabled = State::Initial; diff --git a/lib/Basic/UUID.cpp b/lib/Basic/UUID.cpp index 9ab4b70ccecc0..7391866fd161e 100644 --- a/lib/Basic/UUID.cpp +++ b/lib/Basic/UUID.cpp @@ -1,8 +1,8 @@ -//===--- UUID.h - UUID generation -----------------------------------------===// +//===--- UUID.cpp - UUID generation ---------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -41,7 +41,7 @@ Optional UUID::fromString(const char *s) { void UUID::toString(llvm::SmallVectorImpl &out) const { out.resize(UUID::StringBufferSize); - uuid_unparse(Value, out.data()); + uuid_unparse_upper(Value, out.data()); // Pop off the null terminator. assert(out.back() == '\0' && "did not null-terminate?!"); out.pop_back(); diff --git a/lib/Basic/Unicode.cpp b/lib/Basic/Unicode.cpp index 6f2d40d92d44f..658b90f111d4d 100644 --- a/lib/Basic/Unicode.cpp +++ b/lib/Basic/Unicode.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/UnicodeExtendedGraphemeClusters.cpp.gyb b/lib/Basic/UnicodeExtendedGraphemeClusters.cpp.gyb index 2a5ac3d48e4ee..4380c6524188d 100644 --- a/lib/Basic/UnicodeExtendedGraphemeClusters.cpp.gyb +++ b/lib/Basic/UnicodeExtendedGraphemeClusters.cpp.gyb @@ -7,7 +7,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,12 +17,9 @@ %{ -import re +from GYBUnicodeDataUtils import GraphemeClusterBreakPropertyTable, get_extended_grapheme_cluster_rules_matrix -from GYBUnicodeDataUtils import * - -grapheme_cluster_break_property_table = \ - GraphemeClusterBreakPropertyTable(unicodeGraphemeBreakPropertyFile) +break_table = GraphemeClusterBreakPropertyTable(unicodeGraphemeBreakPropertyFile) }% @@ -32,8 +29,7 @@ swift::unicode::GraphemeClusterBreakProperty swift::unicode::getGraphemeClusterBreakProperty(uint32_t C) { // FIXME: replace linear search with a trie lookup. -% for start_code_point,end_code_point,value in \ -% grapheme_cluster_break_property_table.property_value_ranges: +% for start_code_point, end_code_point, value in break_table.property_value_ranges: % if start_code_point == 0: if (C <= ${end_code_point}) % else: @@ -46,7 +42,7 @@ swift::unicode::getGraphemeClusterBreakProperty(uint32_t C) { } const uint16_t swift::unicode::ExtendedGraphemeClusterNoBoundaryRulesMatrix[] = { -% for row in get_extended_grapheme_cluster_rules_matrix(grapheme_cluster_break_property_table): +% for row in get_extended_grapheme_cluster_rules_matrix(break_table): ${row}, % end }; diff --git a/lib/Basic/Unix/TaskQueue.inc b/lib/Basic/Unix/TaskQueue.inc index 876103b1598f0..3183aa2b17f8e 100644 --- a/lib/Basic/Unix/TaskQueue.inc +++ b/lib/Basic/Unix/TaskQueue.inc @@ -1,8 +1,8 @@ -//===--- Unix/TaskQueue.inc - Unix-specific TaskQueue -----------*- C++ -*-===// +//===--- TaskQueue.inc - Unix-specific TaskQueue ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 90aa61220d197..f7f9b7a891d87 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -84,8 +84,8 @@ static void printFullRevisionString(raw_ostream &out) { void splitVersionComponents( SmallVectorImpl> &SplitComponents, StringRef &VersionString, SourceLoc Loc, - DiagnosticEngine *Diags) { - SourceLoc Start = Loc.isValid() ? Loc.getAdvancedLoc(1) : Loc; + DiagnosticEngine *Diags, bool skipQuote = false) { + SourceLoc Start = (Loc.isValid() && skipQuote) ? Loc.getAdvancedLoc(1) : Loc; SourceLoc End = Start; // Split the version string into tokens separated by the '.' character. @@ -125,7 +125,8 @@ Version Version::parseCompilerVersionString( } }; - splitVersionComponents(SplitComponents, VersionString, Loc, Diags); + splitVersionComponents(SplitComponents, VersionString, Loc, Diags, + /*skipQuote=*/true); uint64_t ComponentNumber; @@ -137,7 +138,7 @@ Version Version::parseCompilerVersionString( // Version components can't be empty. if (SplitComponent.empty()) { if (Diags) - Diags->diagnose(Range.Start, diag::empty_compiler_version_component); + Diags->diagnose(Range.Start, diag::empty_version_component); else llvm_unreachable("Found empty compiler version component"); continue; @@ -165,7 +166,7 @@ Version Version::parseCompilerVersionString( continue; } else if (Diags) { Diags->diagnose(Range.Start, - diag::compiler_version_component_not_number); + diag::version_component_not_number); } else { llvm_unreachable("Invalid character in _compiler_version build configuration"); } @@ -182,18 +183,25 @@ Version Version::parseCompilerVersionString( return CV; } -Version Version::parseVersionString(StringRef VersionString, - SourceLoc Loc, - DiagnosticEngine *Diags) { - Version CV; +Optional Version::parseVersionString(StringRef VersionString, + SourceLoc Loc, + DiagnosticEngine *Diags) { + Version TheVersion; SmallString<16> digits; llvm::raw_svector_ostream OS(digits); SmallVector, 5> SplitComponents; // Skip over quote character in string literal. + if (VersionString.empty()) { + if (Diags) + Diags->diagnose(Loc, diag::empty_version_string); + return None; + } + splitVersionComponents(SplitComponents, VersionString, Loc, Diags); uint64_t ComponentNumber; + bool isValidVersion = true; for (size_t i = 0; i < SplitComponents.size(); ++i) { StringRef SplitComponent; @@ -203,37 +211,55 @@ Version Version::parseVersionString(StringRef VersionString, // Version components can't be empty. if (SplitComponent.empty()) { if (Diags) - Diags->diagnose(Range.Start, diag::empty_compiler_version_component); - else - llvm_unreachable("Found empty compiler version component"); + Diags->diagnose(Range.Start, diag::empty_version_component); + + isValidVersion = false; continue; } // All other version components must be numbers. if (!SplitComponent.getAsInteger(10, ComponentNumber)) { - CV.Components.push_back(ComponentNumber); + TheVersion.Components.push_back(ComponentNumber); continue; - } else if (Diags) { - Diags->diagnose(Range.Start, - diag::compiler_version_component_not_number); } else { - llvm_unreachable("Invalid character in _compiler_version build configuration"); + if (Diags) + Diags->diagnose(Range.Start, + diag::version_component_not_number); + isValidVersion = false; } } - return CV; + return isValidVersion ? Optional(TheVersion) : None; } Version Version::getCurrentCompilerVersion() { #ifdef SWIFT_COMPILER_VERSION - return Version::parseVersionString( + auto currentVersion = Version::parseVersionString( SWIFT_COMPILER_VERSION, SourceLoc(), nullptr); + assert(currentVersion.hasValue() && + "Embedded Swift language version couldn't be parsed: '" + SWIFT_COMPILER_VERSION + "'"); + return currentVersion; #else return Version(); #endif } +Version Version::getCurrentLanguageVersion() { +#ifndef SWIFT_VERSION_STRING +#error Swift language version is not set! +#endif + auto currentVersion = Version::parseVersionString( + SWIFT_VERSION_STRING, SourceLoc(), nullptr); + assert(currentVersion.hasValue() && + "Embedded Swift language version couldn't be parsed: '" + SWIFT_VERSION_STRING + "'"); + return currentVersion.getValue(); +} + std::string Version::str() const { std::string VersionString; llvm::raw_string_ostream OS(VersionString); diff --git a/lib/ClangImporter/CFDatabase.def b/lib/ClangImporter/CFDatabase.def index 1d82be4f17b03..a18a3a368d508 100644 --- a/lib/ClangImporter/CFDatabase.def +++ b/lib/ClangImporter/CFDatabase.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/ClangImporter/CMakeLists.txt b/lib/ClangImporter/CMakeLists.txt index 90fcf4f0764e2..ec2930e042d07 100644 --- a/lib/ClangImporter/CMakeLists.txt +++ b/lib/ClangImporter/CMakeLists.txt @@ -17,6 +17,7 @@ add_swift_library(swiftClangImporter SwiftLookupTable.cpp LINK_LIBRARIES swiftAST + swiftParse ) diff --git a/lib/ClangImporter/ClangDiagnosticConsumer.cpp b/lib/ClangImporter/ClangDiagnosticConsumer.cpp index e1f1e8e034fca..3fc53e205fb52 100644 --- a/lib/ClangImporter/ClangDiagnosticConsumer.cpp +++ b/lib/ClangImporter/ClangDiagnosticConsumer.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/ClangImporter/ClangDiagnosticConsumer.h b/lib/ClangImporter/ClangDiagnosticConsumer.h index e9d2d3e504c41..d286b2fd197fc 100644 --- a/lib/ClangImporter/ClangDiagnosticConsumer.h +++ b/lib/ClangImporter/ClangDiagnosticConsumer.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index dae3477c671ee..e8b258d631909 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,6 +33,7 @@ #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Lexer.h" +#include "swift/Parse/Parser.h" #include "swift/Config.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" @@ -238,11 +239,10 @@ ClangImporter::ClangImporter(ASTContext &ctx, : ClangModuleLoader(tracker), Impl(*new Implementation(ctx, clangImporterOpts)) { - Impl.Retain(); } ClangImporter::~ClangImporter() { - Impl.Release(); + delete &Impl; } void ClangImporter::setTypeResolver(LazyResolver &resolver) { @@ -546,12 +546,9 @@ ClangImporter::create(ASTContext &ctx, ppOpts.addRemappedFile(Implementation::moduleImportBufferName, sourceBuffer.release()); - // Build Swift lookup tables, if requested. - if (importer->Impl.UseSwiftLookupTables) { - invocation->getFrontendOpts().ModuleFileExtensions.push_back( - - &importer->Impl); - } + // Install a Clang module file extension to build Swift name lookup tables. + invocation->getFrontendOpts().ModuleFileExtensions.push_back( + new Implementation::SwiftNameLookupExtension(importer->Impl)); // Create a compiler instance. auto PCHContainerOperations = @@ -631,6 +628,13 @@ ClangImporter::create(ASTContext &ctx, while (!importer->Impl.Parser->ParseTopLevelDecl(parsed)) { for (auto *D : parsed.get()) { importer->Impl.addBridgeHeaderTopLevelDecls(D); + + if (auto named = dyn_cast(D)) { + importer->Impl.addEntryToLookupTable( + instance.getSema(), + importer->Impl.BridgingHeaderLookupTable, + named); + } } } @@ -693,40 +697,25 @@ void ClangImporter::Implementation::addEntryToLookupTable( clang::NamedDecl *named) { // Determine whether this declaration is suppressed in Swift. - bool suppressDecl = false; - if (auto objcMethod = dyn_cast(named)) { - // If this member is a method that is a getter or setter for a - // property, don't add it into the table. property names and - // getter names (by choosing to only have a property). - // - // Note that this is suppressed for certain accessibility declarations, - // which are imported as getter/setter pairs and not properties. - if (objcMethod->isPropertyAccessor() && !isAccessibilityDecl(objcMethod)) { - suppressDecl = true; - } - } else if (auto objcProperty = dyn_cast(named)) { - // Suppress certain accessibility properties; they're imported as - // getter/setter pairs instead. - if (isAccessibilityDecl(objcProperty)) - suppressDecl = true; - } + if (shouldSuppressDeclImport(named)) return; - if (!suppressDecl) { - // If we have a name to import as, add this entry to the table. - clang::DeclContext *effectiveContext; - if (auto importedName = importFullName(named, None, &effectiveContext, - &clangSema)) { - table.addEntry(importedName.Imported, named, effectiveContext); + // If we have a name to import as, add this entry to the table. + clang::DeclContext *effectiveContext; + if (auto importedName = importFullName(named, None, &effectiveContext, + &clangSema)) { + table.addEntry(importedName.Imported, named, effectiveContext); - // Also add the alias, if needed. - if (importedName.Alias) - table.addEntry(importedName.Alias, named, effectiveContext); + // Also add the alias, if needed. + if (importedName.Alias) + table.addEntry(importedName.Alias, named, effectiveContext); - // Also add the subscript entry, if needed. - if (importedName.IsSubscriptAccessor) - table.addEntry(DeclName(SwiftContext, SwiftContext.Id_subscript, { }), - named, effectiveContext); - } + // Also add the subscript entry, if needed. + if (importedName.IsSubscriptAccessor) + table.addEntry(DeclName(SwiftContext, SwiftContext.Id_subscript, + ArrayRef()), + named, effectiveContext); + } else if (auto category = dyn_cast(named)) { + table.addCategory(category); } // Walk the members of any context that can have nested members. @@ -814,29 +803,30 @@ bool ClangImporter::Implementation::importHeader( // Force the import to occur. pp.LookAhead(0); + SmallVector parsedNamedDecls; clang::Parser::DeclGroupPtrTy parsed; while (!Parser->ParseTopLevelDecl(parsed)) { - if (parsed && (trackParsedSymbols || UseSwiftLookupTables)) { - for (auto *D : parsed.get()) { - if (trackParsedSymbols) - addBridgeHeaderTopLevelDecls(D); - - if (UseSwiftLookupTables) { - if (auto named = dyn_cast(D)) { - addEntryToLookupTable(getClangSema(), BridgingHeaderLookupTable, - named); - } - } - } + if (!parsed) continue; + + for (auto *D : parsed.get()) { + if (trackParsedSymbols) + addBridgeHeaderTopLevelDecls(D); + if (auto named = dyn_cast(D)) + parsedNamedDecls.push_back(named); } } + + // We can't do this as we're parsing because we may want to resolve naming + // conflicts between the things we've parsed. + for (auto *named : parsedNamedDecls) + addEntryToLookupTable(getClangSema(), BridgingHeaderLookupTable, named); + pp.EndSourceFile(); bumpGeneration(); - if (UseSwiftLookupTables) { - addMacrosToLookupTable(getClangASTContext(), getClangPreprocessor(), - BridgingHeaderLookupTable); - } + // Add any defined macros to the bridging header lookup table. + addMacrosToLookupTable(getClangASTContext(), getClangPreprocessor(), + BridgingHeaderLookupTable); // Wrap all Clang imports under a Swift import decl. for (auto &Import : BridgeHeaderTopLevelImports) { @@ -1125,8 +1115,7 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx, if (!ctx.LangOpts.EnableAppExtensionRestrictions) { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "ios"; }; - } - else { + } else { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "ios" || @@ -1137,13 +1126,11 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx, [](unsigned major, llvm::Optional minor) { return major <= 7; }; DeprecatedAsUnavailableMessage = "APIs deprecated as of iOS 7 and earlier are unavailable in Swift"; - } - else if (ctx.LangOpts.Target.isTvOS()) { + } else if (ctx.LangOpts.Target.isTvOS()) { if (!ctx.LangOpts.EnableAppExtensionRestrictions) { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "tvos"; }; - } - else { + } else { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "tvos" || @@ -1154,13 +1141,11 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx, [](unsigned major, llvm::Optional minor) { return major <= 7; }; DeprecatedAsUnavailableMessage = "APIs deprecated as of iOS 7 and earlier are unavailable in Swift"; - } - else if (ctx.LangOpts.Target.isWatchOS()) { + } else if (ctx.LangOpts.Target.isWatchOS()) { if (!ctx.LangOpts.EnableAppExtensionRestrictions) { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "watchos"; }; - } - else { + } else { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "watchos" || @@ -1175,8 +1160,7 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx, if (!ctx.LangOpts.EnableAppExtensionRestrictions) { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "macosx"; }; - } - else { + } else { PlatformAvailabilityFilter = [](StringRef Platform) { return Platform == "macosx" || @@ -1191,6 +1175,13 @@ ClangImporter::Implementation::Implementation(ASTContext &ctx, DeprecatedAsUnavailableMessage = "APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift"; } + + // Prepopulate the set of module prefixes. + // FIXME: Hard-coded list should move into the module map language. + if (OmitNeedlessWords) { + ModulePrefixes["Foundation"] = "NS"; + ModulePrefixes["ObjectiveC"] = "NS"; + } } @@ -1372,51 +1363,6 @@ ClangImporter::Implementation::exportName(Identifier name) { return ident; } -/// Parse a stringified Swift declaration name, e.g. "init(frame:)". -static StringRef parseDeclName(StringRef Name, - SmallVectorImpl &ArgNames, - bool &IsFunctionName) { - if (Name.back() != ')') { - IsFunctionName = false; - if (Lexer::isIdentifier(Name) && Name != "_") - return Name; - - return ""; - } - - IsFunctionName = true; - - StringRef BaseName, Parameters; - std::tie(BaseName, Parameters) = Name.split('('); - if (!Lexer::isIdentifier(BaseName) || BaseName == "_") - return ""; - - if (Parameters.empty()) - return ""; - Parameters = Parameters.drop_back(); // ')' - - if (Parameters.empty()) - return BaseName; - - if (Parameters.back() != ':') - return ""; - - do { - StringRef NextParam; - std::tie(NextParam, Parameters) = Parameters.split(':'); - - if (!Lexer::isIdentifier(NextParam)) - return ""; - Identifier NextParamID; - if (NextParam == "_") - ArgNames.push_back(""); - else - ArgNames.push_back(NextParam); - } while (!Parameters.empty()); - - return BaseName; -} - /// \brief Returns the common prefix of two strings at camel-case word /// granularity. /// @@ -1589,7 +1535,7 @@ StringRef ClangImporter::Implementation::getEnumConstantNamePrefix( } } - // Compute th e common prefix. + // Compute the common prefix. StringRef commonPrefix = (*ec)->getName(); bool followedByNonIdentifier = false; for (++ec; ec != ecEnd; ++ec) { @@ -1624,15 +1570,9 @@ StringRef ClangImporter::Implementation::getEnumConstantNamePrefix( checkPrefix = checkPrefix.drop_front(); } - // Account for the enum being imported using - // __attribute__((swift_private)). This is a little ad hoc, but it's a - // rare case anyway. - Identifier enumName = importFullName(decl, None, nullptr, &sema).Imported - .getBaseName(); - StringRef enumNameStr = enumName.str(); - if (enumNameStr.startswith("__") && !checkPrefix.startswith("__")) - enumNameStr = enumNameStr.drop_front(2); - + // Don't use importFullName() here, we want to ignore the swift_name + // and swift_private attributes. + StringRef enumNameStr = decl->getName(); StringRef commonWithEnum = getCommonPluralPrefix(checkPrefix, enumNameStr); size_t delta = commonPrefix.size() - checkPrefix.size(); @@ -2071,6 +2011,15 @@ considerErrorImport(ClangImporter::Implementation &importer, return None; } +/// Determine whether we are allowed to strip the module prefix from +/// an entity with the given name. +static bool canStripModulePrefix(StringRef name) { + if (auto known = getKnownFoundationEntity(name)) + return !nameConflictsWithStandardLibrary(*known); + + return true; +} + auto ClangImporter::Implementation::importFullName( const clang::NamedDecl *D, ImportNameOptions options, @@ -2119,37 +2068,6 @@ auto ClangImporter::Implementation::importFullName( } } - // Local function that forms a DeclName from the given strings. - auto formDeclName = [&](StringRef baseName, - ArrayRef argumentNames, - bool isFunction) -> DeclName { - // We cannot import when the base name is not an identifier. - if (!Lexer::isIdentifier(baseName)) - return DeclName(); - - // Get the identifier for the base name. - Identifier baseNameId = SwiftContext.getIdentifier(baseName); - - // For non-functions, just use the base name. - if (!isFunction) return baseNameId; - - // For functions, we need to form a complete name. - - // Convert the argument names. - SmallVector argumentNameIds; - for (auto argName : argumentNames) { - if (argumentNames.empty() || !Lexer::isIdentifier(argName)) { - argumentNameIds.push_back(Identifier()); - continue; - } - - argumentNameIds.push_back(SwiftContext.getIdentifier(argName)); - } - - // Build the result. - return DeclName(SwiftContext, baseNameId, argumentNameIds); - }; - // If we have a swift_name attribute, use that. if (auto *nameAttr = D->getAttr()) { bool skipCustomName = false; @@ -2191,7 +2109,8 @@ auto ClangImporter::Implementation::importFullName( if (baseName.empty()) return result; result.HasCustomName = true; - result.Imported = formDeclName(baseName, argumentNames, isFunctionName); + result.Imported = formDeclName(SwiftContext, baseName, argumentNames, + isFunctionName); if (method) { // Get the parameters. @@ -2231,11 +2150,32 @@ auto ClangImporter::Implementation::importFullName( case clang::DeclarationName::CXXOperatorName: case clang::DeclarationName::CXXUsingDirective: // Handling these is part of C++ interoperability. - return result; + llvm_unreachable("unhandled C++ interoperability"); case clang::DeclarationName::Identifier: // Map the identifier. baseName = D->getDeclName().getAsIdentifierInfo()->getName(); + + if (OmitNeedlessWords) { + // For Objective-C BOOL properties, use the name of the getter + // which, conventionally, has an "is" prefix. + if (auto property = dyn_cast(D)) { + if (isBoolType(clangSema.Context, property->getType())) + baseName = property->getGetterName().getNameForSlot(0); + } + } + + // For C functions, create empty argument names. + if (auto function = dyn_cast(D)) { + isFunction = true; + params = { function->param_begin(), function->param_end() }; + for (auto param : params) { + (void)param; + argumentNames.push_back(StringRef()); + } + if (function->isVariadic()) + argumentNames.push_back(StringRef()); + } break; case clang::DeclarationName::ObjCMultiArgSelector: @@ -2358,60 +2298,62 @@ auto ClangImporter::Implementation::importFullName( baseName = baseName.substr(removePrefix.size()); } + auto hasConflict = [&](const clang::IdentifierInfo *proposedName) -> bool { + // Test to see if there is a value with the same name as 'proposedName' + // in the same module as the decl + // FIXME: This will miss macros. + auto clangModule = getClangSubmoduleForDecl(D); + if (clangModule.hasValue() && clangModule.getValue()) + clangModule = clangModule.getValue()->getTopLevelModule(); + + auto isInSameModule = [&](const clang::Decl *D) -> bool { + auto declModule = getClangSubmoduleForDecl(D); + if (!declModule.hasValue()) + return false; + // Handle the bridging header case. This is pretty nasty since things + // can get added to it *later*, but there's not much we can do. + if (!declModule.getValue()) + return *clangModule == nullptr; + return *clangModule == declModule.getValue()->getTopLevelModule(); + }; + + // Allow this lookup to find hidden names. We don't want the + // decision about whether to rename the decl to depend on + // what exactly the user has imported. Indeed, if we're being + // asked to resolve a serialization cross-reference, the user + // may not have imported this module at all, which means a + // normal lookup wouldn't even find the decl! + // + // Meanwhile, we don't need to worry about finding unwanted + // hidden declarations from different modules because we do a + // module check before deciding that there's a conflict. + clang::LookupResult lookupResult(clangSema, proposedName, + clang::SourceLocation(), + clang::Sema::LookupOrdinaryName); + lookupResult.setAllowHidden(true); + lookupResult.suppressDiagnostics(); + + if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { + if (std::any_of(lookupResult.begin(), lookupResult.end(), isInSameModule)) + return true; + } + + lookupResult.clear(clang::Sema::LookupTagName); + if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { + if (std::any_of(lookupResult.begin(), lookupResult.end(), isInSameModule)) + return true; + } + + return false; + }; + // Objective-C protocols may have the suffix "Protocol" appended if // the non-suffixed name would conflict with another entity in the // same top-level module. SmallString<16> baseNameWithProtocolSuffix; if (auto objcProto = dyn_cast(D)) { if (objcProto->hasDefinition()) { - // Test to see if there is a value with the same name as the protocol - // in the same module. - // FIXME: This will miss macros. - auto clangModule = getClangSubmoduleForDecl(objcProto); - if (clangModule.hasValue() && clangModule.getValue()) - clangModule = clangModule.getValue()->getTopLevelModule(); - - auto isInSameModule = [&](const clang::Decl *D) -> bool { - auto declModule = getClangSubmoduleForDecl(D); - if (!declModule.hasValue()) - return false; - // Handle the bridging header case. This is pretty nasty since things - // can get added to it *later*, but there's not much we can do. - if (!declModule.getValue()) - return *clangModule == nullptr; - return *clangModule == declModule.getValue()->getTopLevelModule(); - }; - - // Allow this lookup to find hidden names. We don't want the - // decision about whether to rename the protocol to depend on - // what exactly the user has imported. Indeed, if we're being - // asked to resolve a serialization cross-reference, the user - // may not have imported this module at all, which means a - // normal lookup wouldn't even find the protocol! - // - // Meanwhile, we don't need to worry about finding unwanted - // hidden declarations from different modules because we do a - // module check before deciding that there's a conflict. - bool hasConflict = false; - clang::LookupResult lookupResult(clangSema, D->getDeclName(), - clang::SourceLocation(), - clang::Sema::LookupOrdinaryName); - lookupResult.setAllowHidden(true); - lookupResult.suppressDiagnostics(); - - if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { - hasConflict = std::any_of(lookupResult.begin(), lookupResult.end(), - isInSameModule); - } - if (!hasConflict) { - lookupResult.clear(clang::Sema::LookupTagName); - if (clangSema.LookupName(lookupResult, /*scope=*/nullptr)) { - hasConflict = std::any_of(lookupResult.begin(), lookupResult.end(), - isInSameModule); - } - } - - if (hasConflict) { + if (hasConflict(objcProto->getIdentifier())) { baseNameWithProtocolSuffix = baseName; baseNameWithProtocolSuffix += SWIFT_PROTOCOL_SUFFIX; baseName = baseNameWithProtocolSuffix; @@ -2421,6 +2363,7 @@ auto ClangImporter::Implementation::importFullName( // Typedef declarations might be CF types that will drop the "Ref" // suffix. + clang::ASTContext &clangCtx = clangSema.Context; bool aliasIsFunction = false; bool aliasIsInitializer = false; StringRef aliasBaseName; @@ -2428,14 +2371,22 @@ auto ClangImporter::Implementation::importFullName( if (auto typedefNameDecl = dyn_cast(D)) { auto swiftName = getCFTypeName(typedefNameDecl, &aliasBaseName); if (!swiftName.empty()) { - baseName = swiftName; + if (swiftName != baseName) { + assert(aliasBaseName == baseName); + if (!hasConflict(&clangCtx.Idents.get(swiftName))) + baseName = swiftName; + else + aliasBaseName = ""; + } else if (!aliasBaseName.empty()) { + if (hasConflict(&clangCtx.Idents.get(aliasBaseName))) + aliasBaseName = ""; + } } } // Local function to determine whether the given declaration is subject to // a swift_private attribute. - auto clangSemaPtr = &clangSema; - auto hasSwiftPrivate = [clangSemaPtr](const clang::NamedDecl *D) { + auto hasSwiftPrivate = [&clangSema](const clang::NamedDecl *D) { if (D->hasAttr()) return true; @@ -2443,7 +2394,7 @@ auto ClangImporter::Implementation::importFullName( // private if the parent enum is marked private. if (auto *ECD = dyn_cast(D)) { auto *ED = cast(ECD->getDeclContext()); - switch (classifyEnum(clangSemaPtr->getPreprocessor(), ED)) { + switch (classifyEnum(clangSema.getPreprocessor(), ED)) { case EnumKind::Constants: case EnumKind::Unknown: if (ED->hasAttr()) @@ -2469,9 +2420,10 @@ auto ClangImporter::Implementation::importFullName( if (auto objcProperty = dyn_cast(D)) { auto contextType = getClangDeclContextType(D->getDeclContext()); if (!contextType.isNull()) { - auto contextTypeName = getClangTypeNameForOmission(contextType); + auto contextTypeName = getClangTypeNameForOmission(clangCtx, + contextType); auto propertyTypeName = getClangTypeNameForOmission( - objcProperty->getType()); + clangCtx, objcProperty->getType()); // Find the property names. const InheritedNameSet *allPropertyNames = nullptr; if (!contextType.isNull()) { @@ -2492,7 +2444,7 @@ auto ClangImporter::Implementation::importFullName( // Objective-C methods. if (auto method = dyn_cast(D)) { (void)omitNeedlessWordsInFunctionName( - clangSema.getPreprocessor(), + clangSema, baseName, argumentNames, params, @@ -2506,6 +2458,37 @@ auto ClangImporter::Implementation::importFullName( method->isInstanceMethod(), omitNeedlessWordsScratch); } + + // Check whether the module in which the declaration resides has a + // module prefix. If so, strip that prefix off when present. + if (D->getDeclContext()->getRedeclContext()->isFileContext() && + D->getDeclName().getNameKind() == clang::DeclarationName::Identifier) { + // Find the original declaration, from which we can determine + // the owning module. + const clang::Decl *owningD = D->getCanonicalDecl(); + if (auto def = getDefinitionForClangTypeDecl(D)) { + if (*def) + owningD = *def; + } + + std::string moduleName; + if (auto module = owningD->getImportedOwningModule()) + moduleName = module->getTopLevelModuleName(); + else + moduleName = owningD->getASTContext().getLangOpts().CurrentModule; + auto prefixPos = ModulePrefixes.find(moduleName); + if (prefixPos != ModulePrefixes.end() && + canStripModulePrefix(baseName) && + baseName.startswith(prefixPos->second)) { + // Strip off the prefix. + baseName = baseName.substr(prefixPos->second.size()); + + // If the result is a value, lowercase it. + if (isa(D)) + baseName = camel_case::toLowercaseWord(baseName, + omitNeedlessWordsScratch); + } + } } // If this declaration has the swift_private attribute, prepend "__" to the @@ -2560,8 +2543,9 @@ auto ClangImporter::Implementation::importFullName( } } - result.Imported = formDeclName(baseName, argumentNames, isFunction); - result.Alias = formDeclName(aliasBaseName, aliasArgumentNames, + result.Imported = formDeclName(SwiftContext, baseName, argumentNames, + isFunction); + result.Alias = formDeclName(SwiftContext, aliasBaseName, aliasArgumentNames, aliasIsFunction); return result; } @@ -3004,6 +2988,84 @@ isAccessibilityConformingContext(const clang::DeclContext *ctx) { } +/// Determine whether the given method potentially conflicts with the +/// setter for a property in the given protocol. +static bool +isPotentiallyConflictingSetter(const clang::ObjCProtocolDecl *proto, + const clang::ObjCMethodDecl *method) { + auto sel = method->getSelector(); + if (sel.getNumArgs() != 1) + return false; + + clang::IdentifierInfo *setterID = sel.getIdentifierInfoForSlot(0); + if (!setterID || !setterID->getName().startswith("set")) + return false; + + for (auto *prop : proto->properties()) { + if (prop->getSetterName() == sel) + return true; + } + + return false; +} + +bool ClangImporter::Implementation::shouldSuppressDeclImport( + const clang::Decl *decl) { + if (auto objcMethod = dyn_cast(decl)) { + // If this member is a method that is a getter or setter for a + // property, don't add it into the table. property names and + // getter names (by choosing to only have a property). + // + // Note that this is suppressed for certain accessibility declarations, + // which are imported as getter/setter pairs and not properties. + if (objcMethod->isPropertyAccessor()) { + // Suppress the import of this method when the corresponding + // property is not suppressed. + return !shouldSuppressDeclImport( + objcMethod->findPropertyDecl(/*checkOverrides=*/false)); + } + + // If the method was declared within a protocol, check that it + // does not conflict with the setter of a property. + if (auto proto = dyn_cast(decl->getDeclContext())) + return isPotentiallyConflictingSetter(proto, objcMethod); + + return false; + } + + if (auto objcProperty = dyn_cast(decl)) { + // Suppress certain accessibility properties; they're imported as + // getter/setter pairs instead. + if (isAccessibilityDecl(objcProperty)) + return true; + + // Check whether there is a superclass method for the getter that + // is *not* suppressed, in which case we will need to suppress + // this property. + auto dc = objcProperty->getDeclContext(); + auto objcClass = dyn_cast(dc); + if (!objcClass) { + if (auto objcCategory = dyn_cast(dc)) + objcClass = objcCategory->getClassInterface(); + } + + if (objcClass) { + if (auto objcSuperclass = objcClass->getSuperClass()) { + if (auto getterMethod + = objcSuperclass->lookupInstanceMethod( + objcProperty->getGetterName())) { + if (!shouldSuppressDeclImport(getterMethod)) + return true; + } + } + } + + return false; + } + + return false; +} + bool ClangImporter::Implementation::isAccessibilityDecl(const clang::Decl *decl) { @@ -3118,159 +3180,6 @@ bool ClangImporter::Implementation::shouldImportAsInitializer( } #pragma mark Name lookup -void ClangImporter::lookupValue(Identifier name, VisibleDeclConsumer &consumer){ - auto &pp = Impl.Instance->getPreprocessor(); - auto &sema = Impl.Instance->getSema(); - - // Map the name. If we can't represent the Swift name in Clang, bail out now. - auto clangName = Impl.exportName(name); - if (!clangName) - return; - - // See if there's a preprocessor macro we can import by this name. - clang::IdentifierInfo *clangID = clangName.getAsIdentifierInfo(); - if (clangID && clangID->hasMacroDefinition()) { - if (auto clangMacro = pp.getMacroInfo(clangID)) { - if (auto valueDecl = Impl.importMacro(name, clangMacro)) { - consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); - } - } - } - - bool FoundType = false; - bool FoundAny = false; - auto processResults = [&](clang::LookupResult &result) { - SmallVector sortedResults{result.begin(), - result.end()}; - const clang::SourceManager &srcMgr = pp.getSourceManager(); - std::sort(sortedResults.begin(), sortedResults.end(), - [&](const clang::NamedDecl *lhs, - const clang::NamedDecl *rhs) -> bool { - clang::SourceLocation lhsLoc = lhs->getLocStart(); - clang::SourceLocation lhsExpLoc = srcMgr.getExpansionLoc(lhsLoc); - clang::SourceLocation rhsLoc = rhs->getLocStart(); - clang::SourceLocation rhsExpLoc = srcMgr.getExpansionLoc(rhsLoc); - if (lhsExpLoc == rhsExpLoc) - return srcMgr.isBeforeInTranslationUnit(srcMgr.getSpellingLoc(lhsLoc), - srcMgr.getSpellingLoc(rhsLoc)); - return srcMgr.isBeforeInTranslationUnit(lhsExpLoc, rhsExpLoc); - }); - - // FIXME: Filter based on access path? C++ access control? - for (auto decl : result) { - if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) { - if (auto valueDecl = dyn_cast(swiftDecl)) { - // If the importer gave us a declaration from the stdlib, make sure - // it does not show up in the lookup results for the imported module. - if (valueDecl->getDeclContext()->isModuleScopeContext() && - valueDecl->getModuleContext() == Impl.getStdlibModule()) - continue; - // Check that we didn't pick up something with a remapped name. - if (valueDecl->getName() != name) - continue; - - consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); - FoundType = FoundType || isa(valueDecl); - FoundAny = true; - } - } - } - }; - - - // Perform name lookup into the global scope. - // FIXME: Map source locations over. - clang::LookupResult lookupResult(sema, /*name=*/{}, clang::SourceLocation(), - clang::Sema::LookupOrdinaryName); - - auto lookupNameForSwift = [&](clang::DeclarationName clangNameToLookup) { - lookupResult.setLookupName(clangNameToLookup); - - lookupResult.clear(clang::Sema::LookupOrdinaryName); - if (sema.LookupName(lookupResult, /*Scope=*/nullptr)) - processResults(lookupResult); - - if (!FoundType) { - // Look up a tag name if we did not find a type with this name already. - // We don't want to introduce multiple types with same name. - lookupResult.clear(clang::Sema::LookupTagName); - if (sema.LookupName(lookupResult, /*Scope=*/nullptr)) - processResults(lookupResult); - } - - const auto *clangIDToLookup = clangNameToLookup.getAsIdentifierInfo(); - - // Look up protocol names as well. - lookupResult.clear(clang::Sema::LookupObjCProtocolName); - if (sema.LookupName(lookupResult, /*Scope=*/nullptr)) { - processResults(lookupResult); - - } else if (!FoundAny && - clangIDToLookup->getName().endswith(SWIFT_PROTOCOL_SUFFIX)) { - StringRef noProtoNameStr = clangIDToLookup->getName(); - noProtoNameStr = noProtoNameStr.drop_back(strlen(SWIFT_PROTOCOL_SUFFIX)); - auto protoIdent = &Impl.getClangASTContext().Idents.get(noProtoNameStr); - lookupResult.clear(clang::Sema::LookupObjCProtocolName); - lookupResult.setLookupName(protoIdent); - - if (sema.LookupName(lookupResult, /*Scope=*/nullptr)) - processResults(lookupResult); - } - - // If we *still* haven't found anything, try looking for 'Ref'. - // Eventually, this should be optimized by recognizing this case when - // generating the Clang module. - if (!FoundAny && clangIDToLookup) { - llvm::SmallString<128> buffer; - buffer += clangIDToLookup->getName(); - buffer += SWIFT_CFTYPE_SUFFIX; - auto refIdent = &Impl.Instance->getASTContext().Idents.get(buffer.str()); - - lookupResult.clear(clang::Sema::LookupOrdinaryName); - lookupResult.setLookupName(refIdent); - if (sema.LookupName(lookupResult, /*Scope=*/0)) { - // FIXME: Filter based on access path? C++ access control? - // FIXME: Sort this list, even though there's probably only one result. - for (auto decl : lookupResult) { - auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl()); - auto alias = dyn_cast_or_null(swiftDecl); - if (!alias) - continue; - - Type underlyingTy = alias->getUnderlyingType(); - TypeDecl *underlying = nullptr; - if (auto anotherAlias = - dyn_cast(underlyingTy.getPointer())) { - underlying = anotherAlias->getDecl(); - } else if (auto aliasedClass = underlyingTy->getAs()) { - underlying = aliasedClass->getDecl(); - } - - if (!underlying) - continue; - if (underlying->getName() == name) { - consumer.foundDecl(underlying, - DeclVisibilityKind::VisibleAtTopLevel); - } - } - } - } - }; - - // Actually do the lookup. - lookupNameForSwift(clangName); - - // If we haven't found anything and the name starts with "__", maybe it's a - // decl marked with the swift_private attribute. Try chopping off the prefix. - if (!FoundAny && clangID && clangID->getName().startswith("__") && - clangID->getName().size() > 2) { - StringRef unprefixedName = clangID->getName().drop_front(2); - auto unprefixedID = - &Impl.Instance->getASTContext().Idents.get(unprefixedName); - lookupNameForSwift(unprefixedID); - } -} - const clang::TypedefNameDecl * ClangImporter::Implementation::lookupTypedef(clang::DeclarationName name) { clang::Sema &sema = Instance->getSema(); @@ -3412,29 +3321,17 @@ class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer { class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer { swift::VisibleDeclConsumer &NextConsumer; - SmallVectorImpl &ExtensionResults; const ClangModuleUnit *ModuleFilter = nullptr; public: FilteringDeclaredDeclConsumer(swift::VisibleDeclConsumer &consumer, - SmallVectorImpl &ExtensionResults, const ClangModuleUnit *CMU) : NextConsumer(consumer), - ExtensionResults(ExtensionResults), ModuleFilter(CMU) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { if (isDeclaredInModule(ModuleFilter, VD)) NextConsumer.foundDecl(VD, Reason); - - // Also report the extensions declared in this module (whether the extended - // type is from this module or not). - if (auto NTD = dyn_cast(VD)) { - for (auto Ext : NTD->getExtensions()) { - if (isDeclaredInModule(ModuleFilter, Ext)) - ExtensionResults.push_back(Ext); - } - } } }; @@ -3624,60 +3521,21 @@ bool ClangImporter::lookupDeclsFromHeader(StringRef Filename, return true; // no info found about that header. } -void ClangImporter::lookupVisibleDecls(VisibleDeclConsumer &Consumer) const { - if (Impl.CurrentCacheState != Implementation::CacheState::Valid) { - do { - Impl.CurrentCacheState = Implementation::CacheState::InProgress; - Impl.CachedVisibleDecls.clear(); - - ClangVectorDeclConsumer clangConsumer; - auto &sema = Impl.getClangSema(); - sema.LookupVisibleDecls(sema.getASTContext().getTranslationUnitDecl(), - clang::Sema::LookupNameKind::LookupAnyName, - clangConsumer); - - // Sort all the Clang decls we find, so that we process them - // deterministically. This *shouldn't* be necessary, but the importer - // definitely still has ordering dependencies. - auto results = clangConsumer.getResults(); - llvm::array_pod_sort(results.begin(), results.end(), - [](clang::NamedDecl * const *lhs, - clang::NamedDecl * const *rhs) -> int { - return clang::DeclarationName::compare((*lhs)->getDeclName(), - (*rhs)->getDeclName()); - }); +void ClangImporter::lookupValue(DeclName name, VisibleDeclConsumer &consumer){ + // Look for values in the bridging header's lookup table. + Impl.lookupValue(Impl.BridgingHeaderLookupTable, name, consumer); - for (const clang::NamedDecl *clangDecl : results) { - if (Impl.CurrentCacheState != Implementation::CacheState::InProgress) - break; - if (Decl *imported = Impl.importDeclReal(clangDecl)) - Impl.CachedVisibleDecls.push_back(cast(imported)); - } - - // If we changed things /while/ we were caching, we need to start over - // and try again. Fortunately we record a map of decls we've already - // imported, so most of the work is just the lookup and then going - // through the list. - } while (Impl.CurrentCacheState != Implementation::CacheState::InProgress); - - auto &ClangPP = Impl.getClangPreprocessor(); - for (auto I = ClangPP.macro_begin(), E = ClangPP.macro_end(); I != E; ++I) { - if (!I->first->hasMacroDefinition()) - continue; - auto Name = Impl.importIdentifier(I->first); - if (Name.empty()) - continue; - if (auto *Imported = Impl.importMacro( - Name, ClangPP.getMacroDefinition(I->first).getMacroInfo())) { - Impl.CachedVisibleDecls.push_back(Imported); - } - } - - Impl.CurrentCacheState = Implementation::CacheState::Valid; + // Collect and sort the set of module names. + SmallVector moduleNames; + for (const auto &entry : Impl.LookupTables) { + moduleNames.push_back(entry.first()); } + llvm::array_pod_sort(moduleNames.begin(), moduleNames.end()); - for (auto VD : Impl.CachedVisibleDecls) - Consumer.foundDecl(VD, DeclVisibilityKind::VisibleAtTopLevel); + // Look for values in the module lookup tables. + for (auto moduleName : moduleNames) { + Impl.lookupValue(*Impl.LookupTables[moduleName].get(), name, consumer); + } } void ClangModuleUnit::lookupVisibleDecls(Module::AccessPathTy accessPath, @@ -3699,7 +3557,11 @@ void ClangModuleUnit::lookupVisibleDecls(Module::AccessPathTy accessPath, actualConsumer = &darwinBlacklistConsumer; } - owner.lookupVisibleDecls(*actualConsumer); + // Find the corresponding lookup table. + if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { + // Search it. + owner.Impl.lookupVisibleDecls(*lookupTable, *actualConsumer); + } } namespace { @@ -3717,19 +3579,28 @@ class VectorDeclPtrConsumer : public swift::VisibleDeclConsumer { void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl &results) const { VectorDeclPtrConsumer consumer(results); - SmallVector extensions; - FilteringDeclaredDeclConsumer filterConsumer(consumer, extensions, this); + FilteringDeclaredDeclConsumer filterConsumer(consumer, this); DarwinBlacklistDeclConsumer blacklistConsumer(filterConsumer, getClangASTContext()); const clang::Module *topLevelModule = clangModule->getTopLevelModule(); - if (DarwinBlacklistDeclConsumer::needsBlacklist(topLevelModule)) { - owner.lookupVisibleDecls(blacklistConsumer); - } else { - owner.lookupVisibleDecls(filterConsumer); - } - results.append(extensions.begin(), extensions.end()); + swift::VisibleDeclConsumer *actualConsumer = &filterConsumer; + if (DarwinBlacklistDeclConsumer::needsBlacklist(topLevelModule)) + actualConsumer = &blacklistConsumer; + + // Find the corresponding lookup table. + if (auto lookupTable = owner.Impl.findLookupTable(topLevelModule)) { + // Search it. + owner.Impl.lookupVisibleDecls(*lookupTable, *actualConsumer); + + // Add the extensions produced by importing categories. + for (auto category : lookupTable->categories()) { + if (auto extension = cast_or_null( + owner.Impl.importDecl(category))) + results.push_back(extension); + } + } } ImportDecl *swift::createImportDecl(ASTContext &Ctx, @@ -3788,10 +3659,6 @@ void ClangModuleUnit::lookupValue(Module::AccessPathTy accessPath, if (!Module::matchesAccessPath(accessPath, name)) return; - // There should be no multi-part top-level decls in a Clang module. - if (!name.isSimpleName()) - return; - // FIXME: Ignore submodules, which are empty for now. if (clangModule && clangModule->isSubModule()) return; @@ -3808,7 +3675,11 @@ void ClangModuleUnit::lookupValue(Module::AccessPathTy accessPath, consumer = &darwinBlacklistConsumer; } - owner.lookupValue(name.getBaseName(), *consumer); + // Find the corresponding lookup table. + if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { + // Search it. + owner.Impl.lookupValue(*lookupTable, name, *consumer); + } } void ClangImporter::loadExtensions(NominalTypeDecl *nominal, @@ -3908,131 +3779,6 @@ void ClangImporter::loadObjCMethods( } } -// FIXME: This should just be the implementation of -// llvm::array_pod_sort_comparator. The only difference is that it uses -// std::less instead of operator<. -// FIXME: Copied from IRGenModule.cpp. -template -static int pointerPODSortComparator(T * const *lhs, T * const *rhs) { - std::less lt; - if (lt(*lhs, *rhs)) - return -1; - if (lt(*rhs, *lhs)) - return -1; - return 0; -} - -static void lookupClassMembersImpl(ClangImporter::Implementation &Impl, - VisibleDeclConsumer &consumer, - DeclName name) { - // When looking for a subscript, we actually look for the getters - // and setters. - bool isSubscript = name.isSimpleName(Impl.SwiftContext.Id_subscript); - - // FIXME: Does not include methods from protocols. - auto importMethodsImpl = [&](const clang::ObjCMethodList &start) { - for (auto *list = &start; list != nullptr; list = list->getNext()) { - if (list->getMethod()->isUnavailable()) - continue; - - // If the method is a property accessor, we want the property. - const clang::NamedDecl *searchForDecl = list->getMethod(); - if (list->getMethod()->isPropertyAccessor() && - !Impl.isAccessibilityDecl(list->getMethod())) { - if (auto property = list->getMethod()->findPropertyDecl()) { - // ... unless we are enumerating all decls. In this case, if we see - // a getter, return a property. If we see a setter, we know that - // there is a getter, and we will visit it and return a property at - // that time. - if (!name && list->getMethod()->param_size() != 0) - continue; - searchForDecl = property; - } - } - - auto VD = cast_or_null(Impl.importDeclReal(searchForDecl)); - if (!VD) - continue; - - if (auto func = dyn_cast(VD)) { - if (auto storage = func->getAccessorStorageDecl()) { - consumer.foundDecl(storage, DeclVisibilityKind::DynamicLookup); - continue; - } else if (isSubscript || !name) { - auto known = Impl.Subscripts.find({func, nullptr}); - if (known != Impl.Subscripts.end()) { - consumer.foundDecl(known->second, - DeclVisibilityKind::DynamicLookup); - } - - // If we were looking only for subscripts, don't report the getter. - if (isSubscript) - continue; - } - } - - consumer.foundDecl(VD, DeclVisibilityKind::DynamicLookup); - } - }; - - auto importMethods = [=](const clang::Sema::GlobalMethods &methodListPair) { - if (methodListPair.first.getMethod()) - importMethodsImpl(methodListPair.first); - if (methodListPair.second.getMethod()) - importMethodsImpl(methodListPair.second); - }; - - clang::Sema &S = Impl.getClangSema(); - - if (isSubscript) { - clang::Selector sels[] = { - Impl.objectAtIndexedSubscript, - Impl.setObjectAtIndexedSubscript, - Impl.objectForKeyedSubscript, - Impl.setObjectForKeyedSubscript - }; - for (auto sel : sels) { - S.ReadMethodPool(sel); - importMethods(S.MethodPool[sel]); - } - - } else if (name) { - auto sel = Impl.exportSelector(name); - if (!sel.isNull()) { - S.ReadMethodPool(sel); - importMethods(S.MethodPool[sel]); - - // If this is a simple name, we only checked nullary selectors. Check - // unary ones as well. - // Note: If this is ever used to look up init methods, we'd need to do - // the reverse as well. - if (name.isSimpleName()) { - auto *II = Impl.exportName(name.getBaseName()).getAsIdentifierInfo(); - sel = Impl.getClangASTContext().Selectors.getUnarySelector(II); - assert(!sel.isNull()); - - S.ReadMethodPool(sel); - importMethods(S.MethodPool[sel]); - } - } - - } else { - // Force load all external methods. - // FIXME: Copied from Clang's SemaCodeComplete. - clang::ExternalASTSource *source = S.getExternalSource(); - for (uint32_t i = 0, n = source->GetNumExternalSelectors(); i != n; ++i) { - clang::Selector sel = source->GetExternalSelector(i); - if (sel.isNull() || S.MethodPool.count(sel)) - continue; - - S.ReadMethodPool(sel); - } - - for (auto entry : S.MethodPool) - importMethods(entry.second); - } -} - void ClangModuleUnit::lookupClassMember(Module::AccessPathTy accessPath, DeclName name, @@ -4043,19 +3789,11 @@ ClangModuleUnit::lookupClassMember(Module::AccessPathTy accessPath, VectorDeclConsumer consumer(results); - // If we have lookup tables, use them. - if (owner.Impl.UseSwiftLookupTables) { - // Find the corresponding lookup table. - if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { - // Search it. - owner.Impl.lookupObjCMembers(*lookupTable, name, consumer); - } - - return; + // Find the corresponding lookup table. + if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { + // Search it. + owner.Impl.lookupObjCMembers(*lookupTable, name, consumer); } - - // FIXME: Not limited by module. - lookupClassMembersImpl(owner.Impl, consumer, name); } void ClangModuleUnit::lookupClassMembers(Module::AccessPathTy accessPath, @@ -4064,18 +3802,64 @@ void ClangModuleUnit::lookupClassMembers(Module::AccessPathTy accessPath, if (clangModule && clangModule->isSubModule()) return; - if (owner.Impl.UseSwiftLookupTables) { - // Find the corresponding lookup table. - if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { - // Search it. - owner.Impl.lookupAllObjCMembers(*lookupTable, consumer); - } + // Find the corresponding lookup table. + if (auto lookupTable = owner.Impl.findLookupTable(clangModule)) { + // Search it. + owner.Impl.lookupAllObjCMembers(*lookupTable, consumer); + } +} +void ClangModuleUnit::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + // FIXME: Ignore submodules, which are empty for now. + if (clangModule && clangModule->isSubModule()) return; - } - // FIXME: Not limited by module. - lookupClassMembersImpl(owner.Impl, consumer, {}); + // Map the selector into a Clang selector. + auto clangSelector = owner.Impl.exportSelector(selector); + if (clangSelector.isNull()) return; + + // Collect all of the Objective-C methods with this selector. + SmallVector objcMethods; + auto &clangSema = owner.Impl.getClangSema(); + clangSema.CollectMultipleMethodsInGlobalPool(clangSelector, + objcMethods, + /*instance=*/true); + clangSema.CollectMultipleMethodsInGlobalPool(clangSelector, + objcMethods, + /*instance=*/false); + + // Import the methods. + auto &clangCtx = clangSema.getASTContext(); + for (auto objcMethod : objcMethods) { + // Verify that this method came from this module. + auto owningClangModule = getClangOwningModule(objcMethod, clangCtx); + if (owningClangModule) + owningClangModule = owningClangModule->getTopLevelModule(); + + if (owningClangModule != clangModule) continue; + + // If we found a property accessor, import the property. + if (objcMethod->isPropertyAccessor()) + (void)owner.Impl.importDecl(objcMethod->findPropertyDecl(true)); + + // Import it. + // FIXME: Retrying a failed import works around recursion bugs in the Clang + // importer. + auto imported = owner.Impl.importDecl(objcMethod); + if (!imported) imported = owner.Impl.importDecl(objcMethod); + if (!imported) continue; + + if (auto func = dyn_cast(imported)) + results.push_back(func); + + // If there is an alternate declaration, also look at it. + if (auto alternate = owner.Impl.getAlternateDecl(imported)) { + if (auto func = dyn_cast(alternate)) + results.push_back(func); + } + } } void ClangModuleUnit::collectLinkLibraries( @@ -4387,7 +4171,8 @@ void ClangImporter::getMangledName(raw_ostream &os, // --------------------------------------------------------------------------- clang::ModuleFileExtensionMetadata -ClangImporter::Implementation::getExtensionMetadata() const { +ClangImporter::Implementation::SwiftNameLookupExtension:: +getExtensionMetadata() const { clang::ModuleFileExtensionMetadata metadata; metadata.BlockName = "swift.lookup"; metadata.MajorVersion = SWIFT_LOOKUP_TABLE_VERSION_MAJOR; @@ -4396,16 +4181,20 @@ ClangImporter::Implementation::getExtensionMetadata() const { return metadata; } -llvm::hash_code ClangImporter::Implementation::hashExtension( - llvm::hash_code code) const { +llvm::hash_code +ClangImporter::Implementation::SwiftNameLookupExtension::hashExtension( + llvm::hash_code code) const { return llvm::hash_combine(code, StringRef("swift.lookup"), SWIFT_LOOKUP_TABLE_VERSION_MAJOR, - SWIFT_LOOKUP_TABLE_VERSION_MINOR); + SWIFT_LOOKUP_TABLE_VERSION_MINOR, + Impl.OmitNeedlessWords, + Impl.InferDefaultArguments); } std::unique_ptr -ClangImporter::Implementation::createExtensionWriter(clang::ASTWriter &writer) { - // Local function to populate the lookup table. +ClangImporter::Implementation::SwiftNameLookupExtension::createExtensionWriter( + clang::ASTWriter &writer) { + // Local function to populate the lookup table. auto populateTable = [this](clang::Sema &sema, SwiftLookupTable &table) { for (auto decl : sema.Context.getTranslationUnitDecl()->noload_decls()) { @@ -4416,12 +4205,12 @@ ClangImporter::Implementation::createExtensionWriter(clang::ASTWriter &writer) { auto named = dyn_cast(decl); if (!named) continue; - // Add this entry to the lookup tabke. - addEntryToLookupTable(sema, table, named); + // Add this entry to the lookup table. + Impl.addEntryToLookupTable(sema, table, named); } // Add macros to the lookup table. - addMacrosToLookupTable(sema.Context, sema.getPreprocessor(), table); + Impl.addMacrosToLookupTable(sema.Context, sema.getPreprocessor(), table); }; return std::unique_ptr( @@ -4429,27 +4218,26 @@ ClangImporter::Implementation::createExtensionWriter(clang::ASTWriter &writer) { } std::unique_ptr -ClangImporter::Implementation::createExtensionReader( +ClangImporter::Implementation::SwiftNameLookupExtension::createExtensionReader( const clang::ModuleFileExtensionMetadata &metadata, clang::ASTReader &reader, clang::serialization::ModuleFile &mod, const llvm::BitstreamCursor &stream) { - // Make sure we have a compatible block. + // Make sure we have a compatible block. Since these values are part + // of the hash, it should never be wrong. assert(metadata.BlockName == "swift.lookup"); - if (metadata.MajorVersion != SWIFT_LOOKUP_TABLE_VERSION_MAJOR || - metadata.MinorVersion != SWIFT_LOOKUP_TABLE_VERSION_MINOR || - metadata.UserInfo != version::getSwiftFullVersion()) - return nullptr; + assert(metadata.MajorVersion == SWIFT_LOOKUP_TABLE_VERSION_MAJOR); + assert(metadata.MinorVersion == SWIFT_LOOKUP_TABLE_VERSION_MINOR); // Check whether we already have an entry in the set of lookup tables. - auto &entry = LookupTables[mod.ModuleName]; + auto &entry = Impl.LookupTables[mod.ModuleName]; if (entry) return nullptr; // Local function used to remove this entry when the reader goes away. std::string moduleName = mod.ModuleName; auto onRemove = [this, moduleName]() { - LookupTables.erase(moduleName); + Impl.LookupTables.erase(moduleName); }; // Create the reader. @@ -4481,49 +4269,113 @@ SwiftLookupTable *ClangImporter::Implementation::findLookupTable( return known->second.get(); } +/// Determine whether the given Clang entry is visible. +/// +/// FIXME: this is an elaborate hack to badly reflect Clang's +/// submodule visibility into Swift. +static bool isVisibleClangEntry(clang::Preprocessor &pp, + StringRef name, + SwiftLookupTable::SingleEntry entry) { + if (auto clangDecl = entry.dyn_cast()) { + // For a declaration, check whether the declaration is hidden. + if (!clangDecl->isHidden()) return true; + + // Is any redeclaration visible? + for (auto redecl : clangDecl->redecls()) { + if (!cast(redecl)->isHidden()) return true; + } + + return false; + } + + // Check whether the macro is defined. + // FIXME: We could get the wrong macro definition here. + return pp.isMacroDefined(name); +} + +void ClangImporter::Implementation::lookupValue( + SwiftLookupTable &table, DeclName name, + VisibleDeclConsumer &consumer) { + auto clangTU = getClangASTContext().getTranslationUnitDecl(); + auto &clangPP = getClangPreprocessor(); + auto baseName = name.getBaseName().str(); + + for (auto entry : table.lookup(name.getBaseName().str(), clangTU)) { + // If the entry is not visible, skip it. + if (!isVisibleClangEntry(clangPP, baseName, entry)) continue; + + ValueDecl *decl; + + // If it's a Clang declaration, try to import it. + if (auto clangDecl = entry.dyn_cast()) { + decl = cast_or_null( + importDeclReal(clangDecl->getMostRecentDecl())); + if (!decl) continue; + } else { + // Try to import a macro. + auto clangMacro = entry.get(); + decl = importMacro(name.getBaseName(), clangMacro); + if (!decl) continue; + } + + // If we found a declaration from the standard library, make sure + // it does not show up in the lookup results for the imported + // module. + if (decl->getDeclContext()->isModuleScopeContext() && + decl->getModuleContext() == getStdlibModule()) + continue; + + // If the name matched, report this result. + if (decl->getFullName().matchesRef(name)) + consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel); + + // If there is an alternate declaration and the name matches, + // report this result. + if (auto alternate = getAlternateDecl(decl)) { + if (alternate->getFullName().matchesRef(name)) + consumer.foundDecl(alternate, DeclVisibilityKind::VisibleAtTopLevel); + } + } +} + +void ClangImporter::Implementation::lookupVisibleDecls( + SwiftLookupTable &table, + VisibleDeclConsumer &consumer) { + // Retrieve and sort all of the base names in this particular table. + auto baseNames = table.allBaseNames(); + llvm::array_pod_sort(baseNames.begin(), baseNames.end()); + + // Look for namespace-scope entities with each base name. + for (auto baseName : baseNames) { + lookupValue(table, SwiftContext.getIdentifier(baseName), consumer); + } +} + void ClangImporter::Implementation::lookupObjCMembers( SwiftLookupTable &table, DeclName name, VisibleDeclConsumer &consumer) { - bool isSubscript = name.getBaseName() == SwiftContext.Id_subscript; + auto &clangPP = getClangPreprocessor(); + auto baseName = name.getBaseName().str(); + + for (auto clangDecl : table.lookupObjCMembers(baseName)) { + // If the entry is not visible, skip it. + if (!isVisibleClangEntry(clangPP, baseName, clangDecl)) continue; - for (auto clangDecl : table.lookupObjCMembers(name.getBaseName().str())) { // Import the declaration. auto decl = cast_or_null(importDeclReal(clangDecl)); if (!decl) continue; - // Handle subscripts. - if (isSubscript) { - if (auto subscript = importSubscriptOf(decl)) - consumer.foundDecl(subscript, DeclVisibilityKind::DynamicLookup); - continue; - } + // If the name we found matches, report the declaration. + if (decl->getFullName().matchesRef(name)) + consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup); - // Did the name we found match? - if (!decl->getFullName().matchesRef(name)) continue; - - // Report this declaration. - consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup); - - // If we imported an Objective-C instance method from a root - // class, and there is no corresponding class method, also import - // it as a class method. - if (auto objcMethod = dyn_cast(clangDecl)) { - if (objcMethod->isInstanceMethod()) { - if (auto method = dyn_cast(decl)) { - if (auto objcClass = objcMethod->getClassInterface()) { - if (!objcClass->getSuperClass() && - !objcClass->getClassMethod(objcMethod->getSelector(), - /*AllowHidden=*/true)) { - if (auto classMethod = importClassMethodVersionOf(method)) { - consumer.foundDecl(cast(classMethod), - DeclVisibilityKind::DynamicLookup); - } - } - } - } - } + // Check for an alternate declaration; if it's name matches, + // report it. + if (auto alternate = getAlternateDecl(decl)) { + if (alternate->getFullName().matchesRef(name)) + consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup); } } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 19e7dcf88166a..5e2c7f5c916b3 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,6 +23,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" @@ -61,15 +62,6 @@ namespace inferred_attributes { } } -/// \brief Retrieve the type of 'self' for the given context. -static Type getSelfTypeForContext(DeclContext *dc) { - // For a protocol or extension thereof, the type is 'Self'. - // FIXME: Weird that we're producing an archetype for protocol Self, - // but the declared type of the context in non-protocol cases. - if (dc->isProtocolOrProtocolExtensionContext()) - return dc->getProtocolSelf()->getArchetype(); - return dc->getDeclaredTypeOfContext(); -} static bool isInSystemModule(DeclContext *D) { if (cast(D->getModuleScopeContext())->isSystemModule()) @@ -77,34 +69,6 @@ static bool isInSystemModule(DeclContext *D) { return false; } -/// Create an implicit 'self' decl for a method in the specified type. If -/// 'static' is true, then this is self for a static method in the type. -/// -/// Note that this decl is created, but it is returned with an incorrect -/// DeclContext that needs to be reset once the method exists. -/// -static VarDecl *createSelfDecl(DeclContext *DC, bool isStaticMethod, - bool isInOut = false) { - auto selfType = getSelfTypeForContext(DC); - - ASTContext &C = DC->getASTContext(); - - if (isStaticMethod) - selfType = MetatypeType::get(selfType); - - bool isLet = true; - if (auto *ND = selfType->getAnyNominal()) - isLet = !isInOut && !isa(ND) && !isa(ND); - - if (isInOut) - selfType = InOutType::get(selfType); - - VarDecl *selfDecl = new (C) ParamDecl(/*IsLet*/isLet, SourceLoc(), - Identifier(), SourceLoc(), C.Id_self, - selfType, DC); - selfDecl->setImplicit(); - return selfDecl; -} /// Create a typedpattern(namedpattern(decl)) static Pattern *createTypedNamedPattern(VarDecl *decl) { @@ -120,12 +84,12 @@ static Pattern *createTypedNamedPattern(VarDecl *decl) { return P; } -template -static bool verifyNameMapping(MappedTypeNameKind NameMappping, - const char (&left)[A], const char (&right)[B]) { - return NameMappping == MappedTypeNameKind::DoNothing || - strcmp(left, right) != 0; +#ifndef NDEBUG +static bool verifyNameMapping(MappedTypeNameKind NameMapping, + StringRef left, StringRef right) { + return NameMapping == MappedTypeNameKind::DoNothing || left != right; } +#endif /// \brief Map a well-known C type to a swift type from the standard library. /// @@ -333,26 +297,23 @@ static FuncDecl *makeRawValueTrivialGetter(ClangImporter::Implementation &Impl, StructDecl *optionSetDecl, ValueDecl *rawDecl) { ASTContext &C = Impl.SwiftContext; - auto optionSetType = optionSetDecl->getDeclaredTypeInContext(); auto rawType = rawDecl->getType(); - VarDecl *selfDecl = createSelfDecl(optionSetDecl, false); - Pattern *selfParam = createTypedNamedPattern(selfDecl); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), optionSetDecl); - Pattern *methodParam = TuplePattern::create(C, SourceLoc(),{},SourceLoc()); - methodParam->setType(TupleType::getEmpty(C)); - Pattern *params[] = {selfParam, methodParam}; + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createEmpty(C) + }; + Type toRawType = ParameterList::getFullType(rawType, params); FuncDecl *getterDecl = FuncDecl::create( C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), - DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, Type(), params, + DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, toRawType, + params, TypeLoc::withoutLoc(rawType), optionSetDecl); getterDecl->setImplicit(); - auto toRawArgType = TupleType::getEmpty(C); - Type toRawType = FunctionType::get(toRawArgType, rawType); - toRawType = FunctionType::get(optionSetType, toRawType); - getterDecl->setType(toRawType); getterDecl->setBodyResultType(rawType); getterDecl->setAccessibility(Accessibility::Public); @@ -360,9 +321,9 @@ static FuncDecl *makeRawValueTrivialGetter(ClangImporter::Implementation &Impl, if (Impl.hasFinishedTypeChecking()) return getterDecl; - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/ true); + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); auto valueRef = new (C) MemberRefExpr(selfRef, SourceLoc(), - rawDecl, SourceLoc(), + rawDecl, DeclNameLoc(), /*implicit*/ true); auto valueRet = new (C) ReturnStmt(SourceLoc(), valueRef); @@ -371,8 +332,7 @@ static FuncDecl *makeRawValueTrivialGetter(ClangImporter::Implementation &Impl, /*implicit*/ true); getterDecl->setBody(body); - // Add as an external definition. - C.addedExternalDecl(getterDecl); + C.addExternalDecl(getterDecl); return getterDecl; } @@ -389,27 +349,21 @@ static FuncDecl *makeRawValueTrivialSetter(ClangImporter::Implementation &Impl, ValueDecl *rawDecl) { // FIXME: Largely duplicated from the type checker. ASTContext &C = Impl.SwiftContext; - auto selfType = importedDecl->getDeclaredTypeInContext(); auto rawType = rawDecl->getType(); - VarDecl *selfDecl = new (C) ParamDecl(/*IsLet*/false, SourceLoc(), - Identifier(), SourceLoc(), - C.Id_self, selfType, - importedDecl); - selfDecl->setImplicit(); - Pattern *selfParam = createTypedNamedPattern(selfDecl); - - VarDecl *newValueDecl = new (C) ParamDecl(/*IsLet*/true, SourceLoc(), - Identifier(), SourceLoc(), - C.Id_value, rawType, importedDecl); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), importedDecl, + /*static*/false, /*inout*/true); + auto *newValueDecl = new (C) ParamDecl(/*IsLet*/true, SourceLoc(),SourceLoc(), + Identifier(), SourceLoc(), + C.Id_value, rawType, importedDecl); newValueDecl->setImplicit(); - Pattern *newValueParam = createTypedNamedPattern(newValueDecl); - newValueParam = new (C) ParenPattern(SourceLoc(), newValueParam, SourceLoc()); - newValueParam->setType(ParenType::get(C, rawType)); - - Pattern *params[] = {selfParam, newValueParam}; + + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createWithoutLoc(newValueDecl) + }; + Type voidTy = TupleType::getEmpty(C); - FuncDecl *setterDecl = FuncDecl::create( C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, Type(), params, @@ -417,9 +371,7 @@ static FuncDecl *makeRawValueTrivialSetter(ClangImporter::Implementation &Impl, setterDecl->setImplicit(); setterDecl->setMutating(); - Type fnTy = FunctionType::get(newValueParam->getType(), voidTy); - fnTy = FunctionType::get(selfType, fnTy); - setterDecl->setType(fnTy); + setterDecl->setType(ParameterList::getFullType(voidTy, params)); setterDecl->setBodyResultType(voidTy); setterDecl->setAccessibility(Accessibility::Public); @@ -427,11 +379,11 @@ static FuncDecl *makeRawValueTrivialSetter(ClangImporter::Implementation &Impl, if (Impl.hasFinishedTypeChecking()) return setterDecl; - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/ true); - auto dest = new (C) MemberRefExpr(selfRef, SourceLoc(), rawDecl, SourceLoc(), + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/ true); + auto dest = new (C) MemberRefExpr(selfRef, SourceLoc(), rawDecl, DeclNameLoc(), /*implicit*/ true); - auto paramRef = new (C) DeclRefExpr(newValueDecl, SourceLoc(), + auto paramRef = new (C) DeclRefExpr(newValueDecl, DeclNameLoc(), /*implicit*/true); auto assign = new (C) AssignExpr(dest, SourceLoc(), paramRef, @@ -441,8 +393,7 @@ static FuncDecl *makeRawValueTrivialSetter(ClangImporter::Implementation &Impl, /*implicit*/ true); setterDecl->setBody(body); - // Add as an external definition. - C.addedExternalDecl(setterDecl); + C.addExternalDecl(setterDecl); return setterDecl; } @@ -462,41 +413,27 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, auto enumTy = enumDecl->getDeclaredTypeInContext(); auto metaTy = MetatypeType::get(enumTy); - VarDecl *selfDecl = createSelfDecl(enumDecl, false); - Pattern *selfPattern = createTypedNamedPattern(selfDecl); + auto selfDecl = ParamDecl::createSelf(SourceLoc(), enumDecl, + /*static*/false, /*inout*/true); - auto param = new (C) ParamDecl(/*let*/ true, + auto param = new (C) ParamDecl(/*let*/ true, SourceLoc(), SourceLoc(), C.Id_rawValue, SourceLoc(), C.Id_rawValue, enumDecl->getRawType(), enumDecl); - Pattern *paramPattern = new (C) NamedPattern(param); - paramPattern->setType(enumDecl->getRawType()); - paramPattern->setImplicit(); - paramPattern = new (C) - TypedPattern(paramPattern, TypeLoc::withoutLoc(enumDecl->getRawType())); - paramPattern->setType(enumDecl->getRawType()); - paramPattern->setImplicit(); + auto paramPL = ParameterList::createWithoutLoc(param); - auto patternElt = TuplePatternElt(paramPattern); - patternElt.setLabel(C.Id_rawValue, SourceLoc()); - paramPattern = TuplePattern::create(C, SourceLoc(), patternElt, SourceLoc()); - paramPattern->setImplicit(); - auto typeElt = TupleTypeElt(enumDecl->getRawType(), C.Id_rawValue); - auto paramTy = TupleType::get(typeElt, C); - paramPattern->setType(paramTy); - - DeclName name(C, C.Id_init, C.Id_rawValue); + DeclName name(C, C.Id_init, paramPL); auto *ctorDecl = new (C) ConstructorDecl(name, enumDecl->getLoc(), OTK_Optional, SourceLoc(), - selfPattern, paramPattern, + selfDecl, paramPL, nullptr, SourceLoc(), enumDecl); ctorDecl->setImplicit(); ctorDecl->setAccessibility(Accessibility::Public); auto optEnumTy = OptionalType::get(enumTy); - auto fnTy = FunctionType::get(paramTy, optEnumTy); + auto fnTy = FunctionType::get(paramPL->getType(C), optEnumTy); auto allocFnTy = FunctionType::get(metaTy, fnTy); auto initFnTy = FunctionType::get(enumTy, fnTy); ctorDecl->setType(allocFnTy); @@ -506,13 +443,13 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, if (Impl.hasFinishedTypeChecking()) return ctorDecl; - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/true); - auto paramRef = new (C) DeclRefExpr(param, SourceLoc(), + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true); + auto paramRef = new (C) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true); auto reinterpretCast - = cast(getBuiltinValueDecl(C, C.getIdentifier("reinterpretCast"))); + = cast(getBuiltinValueDecl(C,C.getIdentifier("reinterpretCast"))); auto reinterpretCastRef - = new (C) DeclRefExpr(reinterpretCast, SourceLoc(), /*implicit*/ true); + = new (C) DeclRefExpr(reinterpretCast, DeclNameLoc(), /*implicit*/ true); auto reinterpreted = new (C) CallExpr(reinterpretCastRef, paramRef, /*implicit*/ true); auto assign = new (C) AssignExpr(selfRef, SourceLoc(), reinterpreted, @@ -522,7 +459,7 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, ctorDecl->setBody(body); - C.addedExternalDecl(ctorDecl); + C.addExternalDecl(ctorDecl); return ctorDecl; } @@ -540,17 +477,12 @@ static FuncDecl *makeEnumRawValueGetter(ClangImporter::Implementation &Impl, VarDecl *rawValueDecl) { ASTContext &C = Impl.SwiftContext; - VarDecl *selfDecl = createSelfDecl(enumDecl, false); - Pattern *selfPattern = createTypedNamedPattern(selfDecl); + auto selfDecl = ParamDecl::createSelf(SourceLoc(), enumDecl); - Pattern *methodParam = TuplePattern::create(C, SourceLoc(),{},SourceLoc()); - auto unitTy = TupleType::getEmpty(C); - methodParam->setType(unitTy); - - Pattern *params[] = {selfPattern, methodParam}; - - auto fnTy = FunctionType::get(unitTy, enumDecl->getRawType()); - fnTy = FunctionType::get(selfDecl->getType(), fnTy); + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createEmpty(C) + }; auto getterDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), @@ -558,7 +490,8 @@ static FuncDecl *makeEnumRawValueGetter(ClangImporter::Implementation &Impl, Type(), params, TypeLoc::withoutLoc(enumDecl->getRawType()), enumDecl); getterDecl->setImplicit(); - getterDecl->setType(fnTy); + getterDecl->setType(ParameterList::getFullType(enumDecl->getRawType(), + params)); getterDecl->setBodyResultType(enumDecl->getRawType()); getterDecl->setAccessibility(Accessibility::Public); @@ -569,11 +502,11 @@ static FuncDecl *makeEnumRawValueGetter(ClangImporter::Implementation &Impl, if (Impl.hasFinishedTypeChecking()) return getterDecl; - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/true); + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true); auto reinterpretCast = cast(getBuiltinValueDecl(C, C.getIdentifier("reinterpretCast"))); auto reinterpretCastRef - = new (C) DeclRefExpr(reinterpretCast, SourceLoc(), /*implicit*/ true); + = new (C) DeclRefExpr(reinterpretCast, DeclNameLoc(), /*implicit*/ true); auto reinterpreted = new (C) CallExpr(reinterpretCastRef, selfRef, /*implicit*/ true); auto ret = new (C) ReturnStmt(SourceLoc(), reinterpreted); @@ -581,7 +514,7 @@ static FuncDecl *makeEnumRawValueGetter(ClangImporter::Implementation &Impl, /*implicit*/ true); getterDecl->setBody(body); - C.addedExternalDecl(getterDecl); + C.addExternalDecl(getterDecl); return getterDecl; } @@ -590,32 +523,23 @@ static FuncDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl, VarDecl *importedFieldDecl, ClangNode clangNode = ClangNode()) { auto &C = Impl.SwiftContext; - auto selfDecl = createSelfDecl(importedDecl, /*is static*/ false); - auto selfPattern = createTypedNamedPattern(selfDecl); - - auto getterFnRetTypeLoc = TypeLoc::withoutLoc(importedFieldDecl->getType()); - auto getterMethodParam = TuplePattern::create(C, SourceLoc(), {}, SourceLoc()); - Pattern *getterParams[] = { selfPattern, getterMethodParam }; + auto selfDecl = ParamDecl::createSelf(SourceLoc(), importedDecl); + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createEmpty(C) + }; + + auto getterType = importedFieldDecl->getType(); auto getterDecl = FuncDecl::create(C, importedFieldDecl->getLoc(), StaticSpellingKind::None, SourceLoc(), DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, Type(), - getterParams, getterFnRetTypeLoc, + params, TypeLoc::withoutLoc(getterType), importedDecl, clangNode); getterDecl->setAccessibility(Accessibility::Public); - - auto voidTy = TupleType::getEmpty(C); - - // Create the field getter - auto getterFnTy = FunctionType::get(voidTy, importedFieldDecl->getType()); - - // Getter methods need to take self as the first argument. Wrap the - // function type to take the self type. - getterFnTy = FunctionType::get(selfDecl->getType(), getterFnTy); - - getterDecl->setType(getterFnTy); - getterDecl->setBodyResultType(importedFieldDecl->getType()); + getterDecl->setType(ParameterList::getFullType(getterType, params)); + getterDecl->setBodyResultType(getterType); return getterDecl; } @@ -625,43 +549,27 @@ static FuncDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl, VarDecl *importedFieldDecl, ClangNode clangNode = ClangNode()) { auto &C = Impl.SwiftContext; - auto inoutSelfDecl = createSelfDecl(importedDecl, - /*isStaticMethod*/ false, - /*isInOut*/ true); - auto inoutSelfPattern = createTypedNamedPattern(inoutSelfDecl); - - auto voidTy = TupleType::getEmpty(C); - - auto setterFnRetTypeLoc = TypeLoc::withoutLoc(voidTy); - - auto newValueDecl = new (C) ParamDecl(/*isLet */ true, SourceLoc(), + auto selfDecl = ParamDecl::createSelf(SourceLoc(), importedDecl, + /*isStatic*/false, /*isInOut*/true); + auto newValueDecl = new (C) ParamDecl(/*isLet */ true,SourceLoc(),SourceLoc(), Identifier(), SourceLoc(), C.Id_value, importedFieldDecl->getType(), importedDecl); - Pattern *setterNewValueParam = createTypedNamedPattern(newValueDecl); - // FIXME: Remove ParenPattern? - setterNewValueParam = new (C) ParenPattern(SourceLoc(), setterNewValueParam, - SourceLoc()); - setterNewValueParam->setType(ParenType::get(C, importedFieldDecl->getType())); + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createWithoutLoc(newValueDecl), + }; - Pattern *setterParams[] = { inoutSelfPattern, setterNewValueParam }; + auto voidTy = TupleType::getEmpty(C); auto setterDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, Type(), - setterParams, setterFnRetTypeLoc, + params, TypeLoc::withoutLoc(voidTy), importedDecl, clangNode); - - // Create the field setter - auto setterFnTy = FunctionType::get(importedFieldDecl->getType(), voidTy); - - // Setter methods need to take self as the first argument. Wrap the - // function type to take the self type. - setterFnTy = FunctionType::get(inoutSelfDecl->getType(), - setterFnTy); - setterDecl->setType(setterFnTy); + setterDecl->setType(ParameterList::getFullType(voidTy, params)); setterDecl->setBodyResultType(voidTy); setterDecl->setAccessibility(Accessibility::Public); setterDecl->setMutating(); @@ -710,52 +618,53 @@ makeUnionFieldAccessors(ClangImporter::Implementation &Impl, { auto selfDecl = getterDecl->getImplicitSelfDecl(); - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/ true); + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), + /*implicit*/ true); auto reinterpretCast = cast(getBuiltinValueDecl( C, C.getIdentifier("reinterpretCast"))); auto reinterpretCastRef - = new (C) DeclRefExpr(reinterpretCast, SourceLoc(), /*implicit*/ true); + = new (C) DeclRefExpr(reinterpretCast, DeclNameLoc(), /*implicit*/ true); auto reinterpreted = new (C) CallExpr(reinterpretCastRef, selfRef, /*implicit*/ true); auto ret = new (C) ReturnStmt(SourceLoc(), reinterpreted); auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc(), /*implicit*/ true); getterDecl->setBody(body); - C.addedExternalDecl(getterDecl); + C.addExternalDecl(getterDecl); } // Synthesize the setter body { auto inoutSelfDecl = setterDecl->getImplicitSelfDecl(); - auto inoutSelfRef = new (C) DeclRefExpr(inoutSelfDecl, SourceLoc(), + auto inoutSelfRef = new (C) DeclRefExpr(inoutSelfDecl, DeclNameLoc(), /*implicit*/ true); auto inoutSelf = new (C) InOutExpr(SourceLoc(), inoutSelfRef, InOutType::get(importedUnionDecl->getType()), /*implicit*/ true); - auto newValueDecl = setterDecl->getBodyParamPatterns()[1]->getSingleVar(); + auto newValueDecl = setterDecl->getParameterList(1)->get(0); - auto newValueRef = new (C) DeclRefExpr(newValueDecl, SourceLoc(), + auto newValueRef = new (C) DeclRefExpr(newValueDecl, DeclNameLoc(), /*implicit*/ true); auto addressofFn = cast(getBuiltinValueDecl( C, C.getIdentifier("addressof"))); auto addressofFnRef - = new (C) DeclRefExpr(addressofFn, SourceLoc(), /*implicit*/ true); + = new (C) DeclRefExpr(addressofFn, DeclNameLoc(), /*implicit*/ true); auto selfPointer = new (C) CallExpr(addressofFnRef, inoutSelf, /*implicit*/ true); auto initializeFn = cast(getBuiltinValueDecl( C, C.getIdentifier("initialize"))); auto initializeFnRef - = new (C) DeclRefExpr(initializeFn, SourceLoc(), /*implicit*/ true); - auto initalizeArgs = TupleExpr::createImplicit(C, + = new (C) DeclRefExpr(initializeFn, DeclNameLoc(), /*implicit*/ true); + auto initializeArgs = TupleExpr::createImplicit(C, { newValueRef, selfPointer }, {}); - auto initialize = new (C) CallExpr(initializeFnRef, initalizeArgs, + auto initialize = new (C) CallExpr(initializeFnRef, initializeArgs, /*implicit*/ true); auto body = BraceStmt::create(C, SourceLoc(), { initialize }, SourceLoc(), /*implicit*/ true); setterDecl->setBody(body); - C.addedExternalDecl(setterDecl); + C.addExternalDecl(setterDecl); } return { getterDecl, setterDecl }; @@ -1193,7 +1102,7 @@ StringRef ClangImporter::Implementation::getCFTypeName( if (auto pointee = CFPointeeInfo::classifyTypedef(decl)) { auto name = decl->getName(); - if (pointee.isRecord()) { + if (pointee.isRecord() || pointee.isTypedef()) { auto resultName = getImportedCFTypeName(name); if (secondaryName && name != resultName) *secondaryName = name; @@ -1201,12 +1110,6 @@ StringRef ClangImporter::Implementation::getCFTypeName( return resultName; } - if (pointee.isTypedef() && secondaryName) { - StringRef otherName = getImportedCFTypeName(name); - if (otherName != name) - *secondaryName = otherName; - } - return name; } @@ -1382,10 +1285,10 @@ namespace { return Type(); } - Type importCFClassType(const clang::TypedefNameDecl *decl, - Identifier className, CFPointeeInfo info) { + ClassDecl *importCFClassType(const clang::TypedefNameDecl *decl, + Identifier className, CFPointeeInfo info) { auto dc = Impl.importDeclContextOf(decl); - if (!dc) return Type(); + if (!dc) return nullptr; Type superclass = findCFSuperclass(decl, info); @@ -1437,7 +1340,7 @@ namespace { } } - return theClass->getDeclaredType(); + return theClass; } Decl *VisitTypedefNameDecl(const clang::TypedefNameDecl *Decl) { @@ -1446,6 +1349,7 @@ namespace { if (Name.empty()) return nullptr; + ValueDecl *alternateDecl = nullptr; Type SwiftType; if (Decl->getDeclContext()->getRedeclContext()->isTranslationUnit()) { bool IsError; @@ -1464,8 +1368,10 @@ namespace { if (auto pointee = CFPointeeInfo::classifyTypedef(Decl)) { // If the pointee is a record, consider creating a class type. if (pointee.isRecord()) { - SwiftType = importCFClassType(Decl, Name, pointee); - if (!SwiftType) return nullptr; + auto SwiftClass = importCFClassType(Decl, Name, pointee); + if (!SwiftClass) return nullptr; + + SwiftType = SwiftClass->getDeclaredInterfaceType(); NameMapping = MappedTypeNameKind::DefineOnly; // If there is an alias (i.e., that doesn't have "Ref"), @@ -1473,6 +1379,9 @@ namespace { if (importedName.Alias) Name = importedName.Alias.getBaseName(); + // Record the class as the alternate decl. + alternateDecl = SwiftClass; + // If the pointee is another CF typedef, create an extra typealias // for the name without "Ref", but not a separate type. } else if (pointee.isTypedef()) { @@ -1494,13 +1403,14 @@ namespace { return nullptr; // If there is an alias (i.e., that doesn't have "Ref"), - // create that separate typedef. + // use that as the name of the typedef later; create a separate + // typedef for the one with "Ref". if (importedName.Alias) { auto aliasWithoutRef = Impl.createDeclWithClangNode( Decl, Impl.importSourceLoc(Decl->getLocStart()), - importedName.Alias.getBaseName(), + Name, Impl.importSourceLoc(Decl->getLocation()), TypeLoc::withoutLoc(SwiftType), DC); @@ -1508,6 +1418,10 @@ namespace { aliasWithoutRef->computeType(); SwiftType = aliasWithoutRef->getDeclaredType(); NameMapping = MappedTypeNameKind::DefineOnly; + Name = importedName.Alias.getBaseName(); + + // Store this alternative declaration. + alternateDecl = aliasWithoutRef; } else { NameMapping = MappedTypeNameKind::DefineAndUse; } @@ -1577,6 +1491,9 @@ namespace { TypeLoc::withoutLoc(SwiftType), DC); Result->computeType(); + + if (alternateDecl) + Impl.AlternateDecls[Result] = alternateDecl; return Result; } @@ -1592,30 +1509,29 @@ namespace { auto &context = Impl.SwiftContext; // Create the 'self' declaration. - auto selfType = structDecl->getDeclaredTypeInContext(); - auto selfMetatype = MetatypeType::get(selfType); - auto selfDecl = createSelfDecl(structDecl, false); - Pattern *selfPattern = createTypedNamedPattern(selfDecl); - - // The default initializer takes no arguments. - auto paramPattern = TuplePattern::create(context, SourceLoc(), {}, - SourceLoc()); - auto emptyTy = TupleType::getEmpty(context); + auto selfDecl = ParamDecl::createSelf(SourceLoc(), structDecl, + /*static*/false, /*inout*/true); + + // self & param. + auto emptyPL = ParameterList::createEmpty(context); // Create the constructor. - DeclName name(context, context.Id_init, {}); + DeclName name(context, context.Id_init, emptyPL); auto constructor = new (context) ConstructorDecl(name, structDecl->getLoc(), - OTK_None, SourceLoc(), - selfPattern, paramPattern, + OTK_None, SourceLoc(), selfDecl, emptyPL, nullptr, SourceLoc(), structDecl); // Set the constructor's type. + auto selfType = structDecl->getDeclaredTypeInContext(); + auto selfMetatype = MetatypeType::get(selfType); + auto emptyTy = TupleType::getEmpty(context); auto fnTy = FunctionType::get(emptyTy, selfType); auto allocFnTy = FunctionType::get(selfMetatype, fnTy); auto initFnTy = FunctionType::get(selfType, fnTy); constructor->setType(allocFnTy); constructor->setInitializerType(initFnTy); + constructor->setAccessibility(Accessibility::Public); // Mark the constructor transparent so that we inline it away completely. @@ -1629,14 +1545,14 @@ namespace { // Construct the left-hand reference to self. Expr *lhs = new (context) DeclRefExpr(constructor->getImplicitSelfDecl(), - SourceLoc(), /*implicit=*/true); + DeclNameLoc(), /*implicit=*/true); // Construct the right-hand call to Builtin.zeroInitializer. Identifier zeroInitID = context.getIdentifier("zeroInitializer"); auto zeroInitializerFunc = cast(getBuiltinValueDecl(context, zeroInitID)); auto zeroInitializerRef = new (context) DeclRefExpr(zeroInitializerFunc, - SourceLoc(), + DeclNameLoc(), /*implicit*/ true); auto emptyTuple = TupleExpr::createEmpty(context, SourceLoc(), SourceLoc(), @@ -1668,53 +1584,45 @@ namespace { auto &context = Impl.SwiftContext; // Create the 'self' declaration. - auto selfType = structDecl->getDeclaredTypeInContext(); - auto selfMetatype = MetatypeType::get(selfType); - auto selfDecl = createSelfDecl(structDecl, false); - - Pattern *selfPattern = createTypedNamedPattern(selfDecl); + auto selfDecl = ParamDecl::createSelf(SourceLoc(), structDecl, + /*static*/false, /*inout*/true); // Construct the set of parameters from the list of members. - SmallVector paramPatterns; - SmallVector patternElts; - SmallVector tupleElts; - SmallVector params; - SmallVector argNames; + SmallVector valueParameters; for (auto var : members) { Identifier argName = wantCtorParamNames ? var->getName() : Identifier(); - auto param = new (context) ParamDecl(/*IsLet*/ true, + auto param = new (context) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName, SourceLoc(), var->getName(), var->getType(), structDecl); - argNames.push_back(argName); - params.push_back(param); - Pattern *pattern = createTypedNamedPattern(param); - paramPatterns.push_back(pattern); - patternElts.push_back(TuplePatternElt(pattern)); - patternElts.back().setLabel(argName, SourceLoc()); - tupleElts.push_back(TupleTypeElt(var->getType(), var->getName())); + valueParameters.push_back(param); } - auto paramPattern = TuplePattern::create(context, SourceLoc(), patternElts, - SourceLoc()); - auto paramTy = TupleType::get(tupleElts, context); - paramPattern->setType(paramTy); - paramTy = paramTy->getRelabeledType(context, argNames); + // self & param. + ParameterList *paramLists[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::create(context, valueParameters) + }; + // Create the constructor - DeclName name(context, context.Id_init, argNames); + DeclName name(context, context.Id_init, paramLists[1]); auto constructor = new (context) ConstructorDecl(name, structDecl->getLoc(), OTK_None, SourceLoc(), - selfPattern, paramPattern, + selfDecl, paramLists[1], nullptr, SourceLoc(), structDecl); // Set the constructor's type. + auto paramTy = paramLists[1]->getType(context); + auto selfType = structDecl->getDeclaredTypeInContext(); + auto selfMetatype = MetatypeType::get(selfType); auto fnTy = FunctionType::get(paramTy, selfType); auto allocFnTy = FunctionType::get(selfMetatype, fnTy); auto initFnTy = FunctionType::get(selfType, fnTy); constructor->setType(allocFnTy); constructor->setInitializerType(initFnTy); + constructor->setAccessibility(Accessibility::Public); // Make the constructor transparent so we inline it away completely. @@ -1733,13 +1641,14 @@ namespace { continue; // Construct left-hand side. - Expr *lhs = new (context) DeclRefExpr(selfDecl, SourceLoc(), + Expr *lhs = new (context) DeclRefExpr(selfDecl, DeclNameLoc(), /*Implicit=*/true); - lhs = new (context) MemberRefExpr(lhs, SourceLoc(), var, SourceLoc(), - /*Implicit=*/true); + lhs = new (context) MemberRefExpr(lhs, SourceLoc(), var, + DeclNameLoc(), /*Implicit=*/true); // Construct right-hand side. - auto rhs = new (context) DeclRefExpr(params[i], SourceLoc(), + auto rhs = new (context) DeclRefExpr(valueParameters[i], + DeclNameLoc(), /*Implicit=*/true); // Add assignment. @@ -1850,7 +1759,7 @@ namespace { // Construct the original constant. Enum constants without payloads look // like simple values, but actually have type 'MyEnum.Type -> MyEnum'. auto constantRef = new (Impl.SwiftContext) DeclRefExpr(original, - SourceLoc(), + DeclNameLoc(), /*implicit*/true); Type importedEnumTy = importedEnum->getDeclaredTypeInContext(); auto typeRef = TypeExpr::createImplicit(importedEnumTy, @@ -2159,7 +2068,7 @@ namespace { } // Add the type decl to ExternalDefinitions so that we can type-check - // raw values and IRGen can emit metadata for it. + // raw values and SILGen can emit witness tables for derived conformances. // FIXME: There might be better ways to do this. Impl.registerExternalDecl(result); return result; @@ -2518,8 +2427,6 @@ namespace { } Decl *VisitFunctionDecl(const clang::FunctionDecl *decl) { - decl = decl->getMostRecentDecl(); - auto dc = Impl.importDeclContextOf(decl); if (!dc) return nullptr; @@ -2534,7 +2441,7 @@ namespace { // Import the function type. If we have parameters, make sure their names // get into the resulting function type. - SmallVector bodyPatterns; + ParameterList *bodyParams = nullptr; Type type = Impl.importFunctionType(decl, decl->getReturnType(), { decl->param_begin(), @@ -2542,9 +2449,7 @@ namespace { decl->isVariadic(), decl->isNoReturn(), isInSystemModule(dc), - hasCustomName, - bodyPatterns, - name); + hasCustomName, bodyParams, name); if (!type) return nullptr; @@ -2552,18 +2457,14 @@ namespace { auto loc = Impl.importSourceLoc(decl->getLocation()); // If we had no argument labels to start with, add empty labels now. - if (name.isSimpleName()) { - llvm::SmallVector - argNames(bodyPatterns[0]->numTopLevelVariables(), Identifier()); - name = DeclName(Impl.SwiftContext, name.getBaseName(), argNames); - } + assert(!name.isSimpleName() && "Cannot have a simple name here"); // FIXME: Poor location info. auto nameLoc = Impl.importSourceLoc(decl->getLocation()); auto result = FuncDecl::create( Impl.SwiftContext, SourceLoc(), StaticSpellingKind::None, loc, name, nameLoc, SourceLoc(), SourceLoc(), - /*GenericParams=*/nullptr, type, bodyPatterns, + /*GenericParams=*/nullptr, type, bodyParams, TypeLoc::withoutLoc(resultTy), dc, decl); result->setBodyResultType(resultTy); @@ -2824,8 +2725,6 @@ namespace { importedName, {decl->param_begin(), decl->param_size()}, decl->isVariadic(), redundant); - if (result) - Impl.importAttributes(decl, result); if ((result || redundant) && member) { ++NumFactoryMethodsAsInitializers; @@ -2847,12 +2746,53 @@ namespace { Impl.SwiftContext.AllocateCopy(os.str()))); } + /// Record the initializer as an alternative declaration for the + /// member. + if (result) + Impl.AlternateDecls[member] = result; + return result; } + /// Determine if the given Objective-C instance method should also + /// be imported as a class method. + /// + /// Objective-C root class instance methods are also reflected as + /// class methods. + bool shouldAlsoImportAsClassMethod(FuncDecl *method) { + // Only instance methods. + if (!method->isInstanceMember()) return false; + + // Must be a method within a class or extension thereof. + auto classDecl = + method->getDeclContext()->isClassOrClassExtensionContext(); + if (!classDecl) return false; + + // The class must not have a superclass. + if (classDecl->getSuperclass()) return false; + + // There must not already be a class method with the same + // selector. + auto objcClass = + cast_or_null(classDecl->getClangDecl()); + if (!objcClass) return false; + + auto objcMethod = + cast_or_null(method->getClangDecl()); + if (!objcMethod) return false; + return !objcClass->getClassMethod(objcMethod->getSelector(), + /*AllowHidden=*/true); + } + + Decl *VisitObjCMethodDecl(const clang::ObjCMethodDecl *decl, + DeclContext *dc) { + return VisitObjCMethodDecl(decl, dc, false); + } + + private: Decl *VisitObjCMethodDecl(const clang::ObjCMethodDecl *decl, DeclContext *dc, - bool forceClassMethod = false) { + bool forceClassMethod) { // If we have an init method, import it as an initializer. if (Impl.isInitMethod(decl)) { // Cannot force initializers into class methods. @@ -2897,11 +2837,12 @@ namespace { return nullptr; // Add the implicit 'self' parameter patterns. - SmallVector bodyPatterns; + SmallVector bodyParams; auto selfVar = - createSelfDecl(dc, decl->isClassMethod() || forceClassMethod); - Pattern *selfPat = createTypedNamedPattern(selfVar); - bodyPatterns.push_back(selfPat); + ParamDecl::createSelf(SourceLoc(), dc, + /*isStatic*/ + decl->isClassMethod() || forceClassMethod); + bodyParams.push_back(ParameterList::createWithoutLoc(selfVar)); SpecialMethodKind kind = SpecialMethodKind::Regular; // FIXME: This doesn't handle implicit properties. @@ -2913,6 +2854,7 @@ namespace { // Import the type that this method will have. DeclName name = importedName.Imported; Optional errorConvention; + bodyParams.push_back(nullptr); auto type = Impl.importMethodType(decl, decl->getReturnType(), { decl->param_begin(), @@ -2920,7 +2862,7 @@ namespace { decl->isVariadic(), decl->hasAttr(), isInSystemModule(dc), - bodyPatterns, + &bodyParams.back(), importedName, name, errorConvention, @@ -2941,7 +2883,7 @@ namespace { Impl.SwiftContext, SourceLoc(), StaticSpellingKind::None, SourceLoc(), name, SourceLoc(), SourceLoc(), SourceLoc(), /*GenericParams=*/nullptr, Type(), - bodyPatterns, TypeLoc(), dc, decl); + bodyParams, TypeLoc(), dc, decl); result->setAccessibility(Accessibility::Public); @@ -3030,54 +2972,30 @@ namespace { !Impl.ImportedDecls[decl->getCanonicalDecl()]) Impl.ImportedDecls[decl->getCanonicalDecl()] = result; - importSpecialMethod(result, dc); + if (importedName.IsSubscriptAccessor) { + // If this was a subscript accessor, try to create a + // corresponding subscript declaration. + (void)importSubscript(result, decl); + } else if (shouldAlsoImportAsClassMethod(result)) { + // If we should import this instance method also as a class + // method, do so and mark the result as an alternate + // declaration. + if (auto imported = VisitObjCMethodDecl(decl, dc, + /*forceClassMethod=*/true)) + Impl.AlternateDecls[result] = cast(imported); + } else if (auto factory = importFactoryMethodAsConstructor( + result, decl, selector, dc)) { + // We imported the factory method as an initializer, so + // record it as an alternate declaration. + if (*factory) + Impl.AlternateDecls[result] = *factory; + } + } return result; } public: - /// \brief Given an imported method, try to import it as some kind of - /// special declaration, e.g., a constructor or subscript. - Decl *importSpecialMethod(Decl *decl, DeclContext *dc) { - // Check whether there's a method associated with this declaration. - auto objcMethod - = dyn_cast_or_null(decl->getClangDecl()); - if (!objcMethod) - return nullptr; - - // Only consider Objective-C methods... - switch (objcMethod->getMethodFamily()) { - case clang::OMF_None: - // Check for one of the subscripting selectors. - if (objcMethod->isInstanceMethod() && - (objcMethod->getSelector() == Impl.objectAtIndexedSubscript || - objcMethod->getSelector() == Impl.setObjectAtIndexedSubscript || - objcMethod->getSelector() == Impl.objectForKeyedSubscript || - objcMethod->getSelector() == Impl.setObjectForKeyedSubscript)) - return importSubscript(decl, objcMethod, dc); - - return nullptr; - - case clang::OMF_init: - case clang::OMF_initialize: - case clang::OMF_new: - case clang::OMF_alloc: - case clang::OMF_autorelease: - case clang::OMF_copy: - case clang::OMF_dealloc: - case clang::OMF_finalize: - case clang::OMF_mutableCopy: - case clang::OMF_performSelector: - case clang::OMF_release: - case clang::OMF_retain: - case clang::OMF_retainCount: - case clang::OMF_self: - // None of these methods have special consideration. - return nullptr; - } - } - - private: /// Record the function or initializer overridden by the given Swift method. void recordObjCOverride(AbstractFunctionDecl *decl) { // Figure out the class in which this method occurs. @@ -3103,15 +3021,25 @@ namespace { continue; // Set function override. - // FIXME: Proper type checking here! if (auto func = dyn_cast(decl)) { - func->setOverriddenDecl(cast(member)); + auto foundFunc = cast(member); + + // Require a selector match. + if (func->getObjCSelector() != foundFunc->getObjCSelector()) + continue; + + func->setOverriddenDecl(foundFunc); return; } // Set constructor override. auto ctor = cast(decl); auto memberCtor = cast(member); + + // Require a selector match. + if (ctor->getObjCSelector() != memberCtor->getObjCSelector()) + continue; + ctor->setOverriddenDecl(memberCtor); // Propagate 'required' to subclass initializers. @@ -3122,7 +3050,7 @@ namespace { } } } - + /// \brief Given an imported method, try to import it as a constructor. /// /// Objective-C methods in the 'init' family are imported as @@ -3312,22 +3240,22 @@ namespace { } // Add the implicit 'self' parameter patterns. - SmallVector bodyPatterns; - auto selfTy = getSelfTypeForContext(dc); - auto selfMetaVar = createSelfDecl(dc, true); - Pattern *selfPat = createTypedNamedPattern(selfMetaVar); - bodyPatterns.push_back(selfPat); + SmallVector bodyParams; + auto selfMetaVar = ParamDecl::createSelf(SourceLoc(), dc, /*static*/true); + auto selfTy = selfMetaVar->getType()->castTo()->getInstanceType(); + bodyParams.push_back(ParameterList::createWithoutLoc(selfMetaVar)); // Import the type that this method will have. Optional errorConvention; DeclName name = importedName.Imported; + bodyParams.push_back(nullptr); auto type = Impl.importMethodType(objcMethod, objcMethod->getReturnType(), args, variadic, objcMethod->hasAttr(), isInSystemModule(dc), - bodyPatterns, + &bodyParams.back(), importedName, name, errorConvention, @@ -3428,13 +3356,12 @@ namespace { if (known != Impl.Constructors.end()) return known->second; - VarDecl *selfVar = createSelfDecl(dc, false); - selfPat = createTypedNamedPattern(selfVar); + auto *selfVar = ParamDecl::createSelf(SourceLoc(), dc); // Create the actual constructor. auto result = Impl.createDeclWithClangNode(objcMethod, - name, SourceLoc(), failability, SourceLoc(), selfPat, - bodyPatterns.back(), /*GenericParams=*/nullptr, + name, SourceLoc(), failability, SourceLoc(), selfVar, + bodyParams.back(), /*GenericParams=*/nullptr, SourceLoc(), dc); // Make the constructor declaration immediately visible in its @@ -3578,33 +3505,18 @@ namespace { /// Build a declaration for an Objective-C subscript getter. FuncDecl *buildSubscriptGetterDecl(const FuncDecl *getter, Type elementTy, - DeclContext *dc, Pattern *indices) { + DeclContext *dc, ParamDecl *index) { auto &context = Impl.SwiftContext; auto loc = getter->getLoc(); - // Form the argument patterns. - SmallVector getterArgs; - - // 'self' - getterArgs.push_back(createTypedNamedPattern(createSelfDecl(dc, false))); - - // index, for subscript operations. - assert(indices); - indices = indices->clone(context); - auto pat = TuplePattern::create(context, loc, TuplePatternElt(indices), - loc); - pat->setType(TupleType::get(TupleTypeElt(indices->getType()), - context)); - getterArgs.push_back(pat); + // self & index. + ParameterList *getterArgs[] = { + ParameterList::createSelf(SourceLoc(), dc), + ParameterList::create(context, index) + }; // Form the type of the getter. - auto getterType = elementTy; - for (auto it = getterArgs.rbegin(), itEnd = getterArgs.rend(); - it != itEnd; ++it) { - getterType = FunctionType::get( - (*it)->getType()->getUnlabeledType(context), - getterType); - } + auto getterType = ParameterList::getFullType(elementTy, getterArgs); // If we're in a protocol, the getter thunk will be polymorphic. Type interfaceType; @@ -3633,10 +3545,9 @@ namespace { /// Build a declaration for an Objective-C subscript setter. FuncDecl *buildSubscriptSetterDecl(const FuncDecl *setter, Type elementTy, - DeclContext *dc, Pattern *indices) { + DeclContext *dc, ParamDecl *index) { auto &context = Impl.SwiftContext; auto loc = setter->getLoc(); - auto tuple = cast(setter->getBodyParamPatterns()[1]); // Objective-C subscript setters are imported with a function type // such as: @@ -3645,43 +3556,31 @@ namespace { // // Build a setter thunk with the latter signature that maps to the // former. - - // Form the argument patterns. - SmallVector setterArgs; + auto valueIndex = setter->getParameterList(1); // 'self' - setterArgs.push_back(createTypedNamedPattern(createSelfDecl(dc, false))); + auto selfDecl = ParamDecl::createSelf(SourceLoc(), dc); + auto paramVarDecl = new (context) ParamDecl(/*isLet=*/false, SourceLoc(), + SourceLoc(), Identifier(),loc, + valueIndex->get(0)->getName(), + elementTy, dc); - SmallVector ValueElts; - SmallVector ValueEltTys; - - auto paramVarDecl = new (context) ParamDecl( - /*isLet=*/false, SourceLoc(), Identifier(), loc, - tuple->getElement(0).getPattern()->getSingleVar()->getName(), - elementTy, dc); - auto valuePattern = createTypedNamedPattern(paramVarDecl); - ValueElts.push_back(TuplePatternElt(valuePattern)); - ValueEltTys.push_back(TupleTypeElt(valuePattern->getType())); - // Clone the indices for the thunk. - assert(indices); - indices = indices->clone(context); - ValueElts.push_back(TuplePatternElt(indices)); - ValueEltTys.push_back(TupleTypeElt(indices->getType())); - - // value - setterArgs.push_back(TuplePattern::create(context, loc, ValueElts, loc)); - setterArgs.back()->setType(TupleType::get(ValueEltTys, context)); - + auto valueIndicesPL = ParameterList::create(context, { + paramVarDecl, + index + }); + + // Form the argument lists. + ParameterList *setterArgs[] = { + ParameterList::createWithoutLoc(selfDecl), + valueIndicesPL + }; + // Form the type of the setter. - Type setterType = TupleType::getEmpty(context); - for (auto it = setterArgs.rbegin(), itEnd = setterArgs.rend(); - it != itEnd; ++it) { - setterType = FunctionType::get( - (*it)->getType()->getUnlabeledType(context), - setterType); - } + Type setterType = ParameterList::getFullType(TupleType::getEmpty(context), + setterArgs); // If we're in a protocol or extension thereof, the setter thunk // will be polymorphic. @@ -3694,7 +3593,8 @@ namespace { // Create the setter thunk. FuncDecl *thunk = FuncDecl::create( context, SourceLoc(), StaticSpellingKind::None, setter->getLoc(), - Identifier(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, setterType, + Identifier(), SourceLoc(), SourceLoc(), SourceLoc(), nullptr, + setterType, setterArgs, TypeLoc::withoutLoc(TupleType::getEmpty(context)), dc, setter->getClangNode()); thunk->setBodyResultType(TupleType::getEmpty(context)); @@ -3708,45 +3608,117 @@ namespace { return thunk; } - /// Hack: Handle the case where a subscript is read-only in the - /// main class interface (either explicitly or because of an adopted - /// protocol) and then the setter is added in a category/extension. - /// - /// \see importSubscript - // FIXME: This is basically the same as handlePropertyRedeclaration below. - void handleSubscriptRedeclaration(SubscriptDecl *original, - const SubscriptDecl *redecl) { - // If the subscript isn't from Clang, we can't safely update it. - if (!original->hasClangNode()) - return; + /// Retrieve the element type and of a subscript setter. + std::pair + decomposeSubscriptSetter(FuncDecl *setter) { + auto *PL = setter->getParameterList(1); + if (PL->size() != 2) + return { nullptr, nullptr }; - // If the original declaration was implicit, we may want to change that. - if (original->isImplicit() && !redecl->isImplicit() && - !redecl->getDeclContext()->isProtocolOrProtocolExtensionContext()) - original->setImplicit(false); + return { PL->get(0)->getType(), PL->get(1) }; + } - // The only other transformation we know how to do safely is add a - // setter. If the subscript is already settable, we're done. - if (original->isSettable()) + /// Rectify the (possibly different) types determined by the + /// getter and setter for a subscript. + /// + /// \param canUpdateType whether the type of subscript can be + /// changed from the getter type to something compatible with both + /// the getter and the setter. + /// + /// \returns the type to be used for the subscript, or a null type + /// if the types cannot be rectified. + Type rectifySubscriptTypes(Type getterType, Type setterType, + bool canUpdateType) { + // If the caller couldn't provide a setter type, there is + // nothing to rectify. + if (!setterType) return nullptr; + + // Trivial case: same type in both cases. + if (getterType->isEqual(setterType)) return getterType; + + // The getter/setter types are different. If we cannot update + // the type, we have to fail. + if (!canUpdateType) return nullptr; + + // Unwrap one level of optionality from each. + if (Type getterObjectType = getterType->getAnyOptionalObjectType()) + getterType = getterObjectType; + if (Type setterObjectType = setterType->getAnyOptionalObjectType()) + setterType = setterObjectType; + + // If they are still different, fail. + // FIXME: We could produce the greatest common supertype of the + // two types. + if (!getterType->isEqual(setterType)) return nullptr; + + // Create an implicitly-unwrapped optional of the object type, + // which subsumes both behaviors. + return ImplicitlyUnwrappedOptionalType::get(setterType); + } + + void recordObjCOverride(SubscriptDecl *subscript) { + // Figure out the class in which this subscript occurs. + auto classTy = + subscript->getDeclContext()->isClassOrClassExtensionContext(); + if (!classTy) return; - auto setter = redecl->getSetter(); - if (!setter) + auto superTy = classTy->getSuperclass(); + if (!superTy) return; - original->setComputedSetter(setter); + // Determine whether this subscript operation overrides another subscript + // operation. + SmallVector lookup; + subscript->getModuleContext() + ->lookupQualified(superTy, subscript->getFullName(), + NL_QualifiedDefault | NL_KnownNoDependency, + Impl.getTypeResolver(), lookup); + Type unlabeledIndices; + for (auto result : lookup) { + auto parentSub = dyn_cast(result); + if (!parentSub) + continue; + + // Compute the type of indices for our own subscript operation, lazily. + if (!unlabeledIndices) { + unlabeledIndices = subscript->getIndices()->getType(Impl.SwiftContext) + ->getUnlabeledType(Impl.SwiftContext); + } + + // Compute the type of indices for the subscript we found. + auto parentUnlabeledIndices = + parentSub->getIndices()->getType(Impl.SwiftContext) + ->getUnlabeledType(Impl.SwiftContext); + if (!unlabeledIndices->isEqual(parentUnlabeledIndices)) + continue; + + // The index types match. This is an override, so mark it as such. + subscript->setOverriddenDecl(parentSub); + auto getterThunk = subscript->getGetter(); + getterThunk->setOverriddenDecl(parentSub->getGetter()); + if (auto parentSetter = parentSub->getSetter()) { + if (auto setterThunk = subscript->getSetter()) + setterThunk->setOverriddenDecl(parentSetter); + } + + // FIXME: Eventually, deal with multiple overrides. + break; + } } /// \brief Given either the getter or setter for a subscript operation, /// create the Swift subscript declaration. SubscriptDecl *importSubscript(Decl *decl, - const clang::ObjCMethodDecl *objcMethod, - DeclContext *dc) { + const clang::ObjCMethodDecl *objcMethod) { assert(objcMethod->isInstanceMethod() && "Caller must filter"); + // If the method we're attempting to import has the + // swift_private attribute, don't import as a subscript. if (objcMethod->hasAttr()) return nullptr; + // Figure out where to look for the counterpart. const clang::ObjCInterfaceDecl *interface = nullptr; const clang::ObjCProtocolDecl *protocol = dyn_cast(objcMethod->getDeclContext()); @@ -3756,13 +3728,32 @@ namespace { const clang::ObjCMethodDecl * { if (interface) return interface->lookupInstanceMethod(Sel); - else - return protocol->lookupInstanceMethod(Sel); + + return protocol->lookupInstanceMethod(Sel); + }; + + auto findCounterpart = [&](clang::Selector sel) -> FuncDecl * { + // If the declaration we're starting from is in a class, first + // look for a class member with the appropriate selector. + if (auto classDecl + = decl->getDeclContext()->isClassOrClassExtensionContext()) { + auto swiftSel = Impl.importSelector(sel); + for (auto found : classDecl->lookupDirect(swiftSel, true)) { + if (auto foundFunc = dyn_cast(found)) + return foundFunc; + } + } + + // Find based on selector within the current type. + auto counterpart = lookupInstanceMethod(sel); + if (!counterpart) return nullptr; + + return cast_or_null(Impl.importDecl(counterpart)); }; + // Determine the selector of the counterpart. FuncDecl *getter = nullptr, *setter = nullptr; clang::Selector counterpartSelector; - if (objcMethod->getSelector() == Impl.objectAtIndexedSubscript) { getter = cast(decl); counterpartSelector = Impl.setObjectAtIndexedSubscript; @@ -3779,27 +3770,30 @@ namespace { llvm_unreachable("Unknown getter/setter selector"); } + // Find the counterpart. bool optionalMethods = (objcMethod->getImplementationControl() == clang::ObjCMethodDecl::Optional); - auto *counterpart = lookupInstanceMethod(counterpartSelector); - if (counterpart) { - auto *importedCounterpart = - cast_or_null(Impl.importDecl(counterpart)); + if (auto *counterpart = findCounterpart(counterpartSelector)) { + // If the counterpart to the method we're attempting to import has the + // swift_private attribute, don't import as a subscript. + if (auto importedFrom = counterpart->getClangDecl()) { + if (importedFrom->hasAttr()) + return nullptr; + + auto counterpartMethod + = dyn_cast(importedFrom); + if (optionalMethods) + optionalMethods = (counterpartMethod->getImplementationControl() == + clang::ObjCMethodDecl::Optional); + } - assert(!importedCounterpart || !importedCounterpart->isStatic()); + assert(!counterpart || !counterpart->isStatic()); if (getter) - setter = importedCounterpart; + setter = counterpart; else - getter = importedCounterpart; - - if (optionalMethods) - optionalMethods = (counterpart->getImplementationControl() == - clang::ObjCMethodDecl::Optional); - - if (counterpart->hasAttr()) - return nullptr; + getter = counterpart; } // Swift doesn't have write-only subscripting. @@ -3808,169 +3802,154 @@ namespace { // Check whether we've already created a subscript operation for // this getter/setter pair. - if (auto subscript = Impl.Subscripts[{getter, setter}]) - return subscript->getDeclContext() == dc? subscript : nullptr; - - // Compute the element type, looking through the implicit 'self' - // parameter and the normal function parameters. - auto elementTy - = getter->getType()->castTo()->getResult() - ->castTo()->getResult(); - - // Check the form of the getter. - FuncDecl *getterThunk = nullptr; - Pattern *getterIndices = nullptr; - auto &context = Impl.SwiftContext; + if (auto subscript = Impl.Subscripts[{getter, setter}]) { + return subscript->getDeclContext() == decl->getDeclContext() + ? subscript + : nullptr; + } // Find the getter indices and make sure they match. + ParamDecl *getterIndex; { - auto tuple = dyn_cast(getter->getBodyParamPatterns()[1]); - if (tuple && tuple->getNumElements() != 1) + auto params = getter->getParameterList(1); + if (params->size() != 1) return nullptr; - - getterIndices = tuple->getElement(0).getPattern(); + getterIndex = params->get(0); } - // Check the form of the setter. - FuncDecl *setterThunk = nullptr; - Pattern *setterIndices = nullptr; - if (setter) { - auto tuple = dyn_cast(setter->getBodyParamPatterns()[1]); - if (!tuple) - return nullptr; - - if (tuple->getNumElements() != 2) - return nullptr; + // Compute the element type based on the getter, looking through + // the implicit 'self' parameter and the normal function + // parameters. + auto elementTy + = getter->getType()->castTo()->getResult() + ->castTo()->getResult(); - // The setter must accept elements of the same type as the getter - // returns. - // FIXME: Adjust C++ references? - auto setterElementTy = tuple->getElement(0).getPattern()->getType(); - if (!elementTy->isEqual(setterElementTy)) { - auto nonOptionalElementTy = elementTy->getAnyOptionalObjectType(); - if (nonOptionalElementTy.isNull()) - nonOptionalElementTy = elementTy; - - auto nonOptionalSetterElementTy = - setterElementTy->getAnyOptionalObjectType(); - if (nonOptionalSetterElementTy.isNull()) - nonOptionalSetterElementTy = setterElementTy; - - if (!nonOptionalElementTy->isEqual(nonOptionalSetterElementTy)) - return nullptr; + // Local function to mark the setter unavailable. + auto makeSetterUnavailable = [&] { + if (setter && !setter->getAttrs().isUnavailable(Impl.SwiftContext)) + Impl.markUnavailable(setter, "use subscripting"); + }; - elementTy = - ImplicitlyUnwrappedOptionalType::get(nonOptionalElementTy); + // If we have a setter, rectify it with the getter. + ParamDecl *setterIndex; + bool getterAndSetterInSameType = false; + if (setter) { + // Whether there is an existing read-only subscript for which + // we have now found a setter. + SubscriptDecl *existingSubscript = Impl.Subscripts[{getter, nullptr}]; + + // Are the getter and the setter in the same type. + getterAndSetterInSameType = + (getter->getDeclContext() + ->isNominalTypeOrNominalTypeExtensionContext() + == setter->getDeclContext() + ->isNominalTypeOrNominalTypeExtensionContext()); + + // Whether we can update the types involved in the subscript + // operation. + bool canUpdateSubscriptType + = !existingSubscript && getterAndSetterInSameType; + + // Determine the setter's element type and indices. + Type setterElementTy; + std::tie(setterElementTy, setterIndex) = + decomposeSubscriptSetter(setter); + + // Rectify the setter element type with the getter's element type. + Type newElementTy = rectifySubscriptTypes(elementTy, setterElementTy, + canUpdateSubscriptType); + if (!newElementTy) + return decl == getter ? existingSubscript : nullptr; + + // Update the element type. + elementTy = newElementTy; + + // Make sure that the index types are equivalent. + // FIXME: Rectify these the same way we do for element types. + if (!setterIndex->getType()->isEqual(getterIndex->getType())) { + // If there is an existing subscript operation, we're done. + if (existingSubscript) + return decl == getter ? existingSubscript : nullptr; + + // Otherwise, just forget we had a setter. + // FIXME: This feels very, very wrong. + setter = nullptr; + setterIndex = nullptr; } - setterIndices = tuple->getElement(1).getPattern(); - - // The setter must use the same indices as the getter. - // FIXME: Adjust C++ references? - if (!setterIndices->getType()->isEqual(getterIndices->getType())) { - setter = nullptr; - setterIndices = nullptr; + // If there is an existing subscript within this context, we + // cannot create a new subscript. Update it if possible. + if (setter && existingSubscript && getterAndSetterInSameType) { + // Can we update the subscript by adding the setter? + if (existingSubscript->hasClangNode() && + !existingSubscript->isSettable()) { + // Create the setter thunk. + auto setterThunk = buildSubscriptSetterDecl( + setter, elementTy, setter->getDeclContext(), + setterIndex); + + // Set the computed setter. + existingSubscript->setComputedSetter(setterThunk); + + // Mark the setter as unavailable; one should use + // subscripting when it is present. + makeSetterUnavailable(); + } - // Check whether we've already created a subscript operation for - // this getter. - if (auto subscript = Impl.Subscripts[{getter, nullptr}]) - return subscript->getDeclContext() == dc? subscript : nullptr; + return decl == getter ? existingSubscript : nullptr; } } - getterThunk = buildSubscriptGetterDecl(getter, elementTy, dc, - getterIndices); + // The context into which the subscript should go. + bool associateWithSetter = setter && !getterAndSetterInSameType; + DeclContext *dc = associateWithSetter ? setter->getDeclContext() + : getter->getDeclContext(); + + // Build the thunks. + FuncDecl *getterThunk = buildSubscriptGetterDecl(getter, elementTy, dc, + getterIndex); + + FuncDecl *setterThunk = nullptr; if (setter) setterThunk = buildSubscriptSetterDecl(setter, elementTy, dc, - setterIndices); + setterIndex); // Build the subscript declaration. - auto bodyPatterns = - getterThunk->getBodyParamPatterns()[1]->clone(context); + auto &context = Impl.SwiftContext; + auto bodyParams = getterThunk->getParameterList(1)->clone(context); DeclName name(context, context.Id_subscript, { Identifier() }); auto subscript = Impl.createDeclWithClangNode(getter->getClangNode(), - name, decl->getLoc(), bodyPatterns, + name, decl->getLoc(), bodyParams, decl->getLoc(), TypeLoc::withoutLoc(elementTy), dc); + + /// Record the subscript as an alternative declaration. + Impl.AlternateDecls[associateWithSetter ? setter : getter] = subscript; + subscript->makeComputed(SourceLoc(), getterThunk, setterThunk, nullptr, SourceLoc()); - auto indicesType = bodyPatterns->getType(); - indicesType = indicesType->getRelabeledType(context, - name.getArgumentNames()); - - subscript->setType(FunctionType::get(indicesType, - subscript->getElementType())); + auto indicesType = bodyParams->getType(context); + + subscript->setType(FunctionType::get(indicesType, elementTy)); addObjCAttribute(subscript, None); // Optional subscripts in protocols. if (optionalMethods && isa(dc)) - subscript->getAttrs().add(new (Impl.SwiftContext) - OptionalAttr(true)); + subscript->getAttrs().add(new (Impl.SwiftContext) OptionalAttr(true)); // Note that we've created this subscript. Impl.Subscripts[{getter, setter}] = subscript; - Impl.Subscripts[{getterThunk, nullptr}] = subscript; + if (setter && !Impl.Subscripts[{getter, nullptr}]) + Impl.Subscripts[{getter, nullptr}] = subscript; // Make the getter/setter methods unavailable. if (!getter->getAttrs().isUnavailable(Impl.SwiftContext)) Impl.markUnavailable(getter, "use subscripting"); - if (setter && !setter->getAttrs().isUnavailable(Impl.SwiftContext)) - Impl.markUnavailable(setter, "use subscripting"); - - // Determine whether this subscript operation overrides another subscript - // operation. - // FIXME: This ends up looking in the superclass for entirely bogus - // reasons. Fix it. - auto containerTy = dc->getDeclaredTypeInContext(); - SmallVector lookup; - dc->lookupQualified(containerTy, name, - NL_QualifiedDefault | NL_KnownNoDependency, - Impl.getTypeResolver(), lookup); - Type unlabeledIndices; - for (auto result : lookup) { - auto parentSub = dyn_cast(result); - if (!parentSub) - continue; - - // Compute the type of indices for our own subscript operation, lazily. - if (!unlabeledIndices) { - unlabeledIndices = subscript->getIndices()->getType() - ->getUnlabeledType(Impl.SwiftContext); - } - - // Compute the type of indices for the subscript we found. - auto parentUnlabeledIndices = parentSub->getIndices()->getType() - ->getUnlabeledType(Impl.SwiftContext); - if (!unlabeledIndices->isEqual(parentUnlabeledIndices)) - continue; - - if (parentSub == subscript) - continue; - - const DeclContext *overrideContext = parentSub->getDeclContext(); - assert(dc != overrideContext && "subscript already exists"); - - if (overrideContext->getDeclaredTypeInContext()->isEqual(containerTy)) { - // We've encountered a redeclaration of the subscript. - // HACK: Just update the original declaration instead of importing a - // second subscript. - handleSubscriptRedeclaration(parentSub, subscript); - Impl.Subscripts[{getter, setter}] = parentSub; - return nullptr; - } - - // The index types match. This is an override, so mark it as such. - subscript->setOverriddenDecl(parentSub); - getterThunk->setOverriddenDecl(parentSub->getGetter()); - if (auto parentSetter = parentSub->getSetter()) { - if (setterThunk) - setterThunk->setOverriddenDecl(parentSetter); - } + makeSetterUnavailable(); - // FIXME: Eventually, deal with multiple overrides. - break; - } + // Wire up overrides. + recordObjCOverride(subscript); return subscript; } @@ -4074,31 +4053,11 @@ namespace { } } - static bool - isPotentiallyConflictingSetter(const clang::ObjCProtocolDecl *proto, - const clang::ObjCMethodDecl *method) { - auto sel = method->getSelector(); - if (sel.getNumArgs() != 1) - return false; - - clang::IdentifierInfo *setterID = sel.getIdentifierInfoForSlot(0); - if (!setterID || !setterID->getName().startswith("set")) - return false; - - for (auto *prop : proto->properties()) { - if (prop->getSetterName() == sel) - return true; - } - - return false; - } - /// Import members of the given Objective-C container and add them to the /// list of corresponding Swift members. void importObjCMembers(const clang::ObjCContainerDecl *decl, DeclContext *swiftContext, - SmallVectorImpl &members, - bool &hasMissingRequiredMember) { + SmallVectorImpl &members) { llvm::SmallPtrSet knownMembers; for (auto m = decl->decls_begin(), mEnd = decl->decls_end(); m != mEnd; ++m) { @@ -4107,92 +4066,23 @@ namespace { continue; auto member = Impl.importDecl(nd); - if (!member) { - if (auto method = dyn_cast(nd)) { - if (method->getImplementationControl() == - clang::ObjCMethodDecl::Required) - hasMissingRequiredMember = true; - } else if (auto prop = dyn_cast(nd)) { - if (prop->getPropertyImplementation() == - clang::ObjCPropertyDecl::Required) - hasMissingRequiredMember = true; - } - continue; - } + if (!member) continue; if (auto objcMethod = dyn_cast(nd)) { - // If there is a special declaration associated with this member, - // add it now. - if (auto special = importSpecialMethod(member, swiftContext)) { - if (knownMembers.insert(special).second) - members.push_back(special); - } - - // If this is a factory method, try to import it as a constructor. - if (auto factory = importFactoryMethodAsConstructor( - member, - objcMethod, - Impl.importSelector(objcMethod->getSelector()), - swiftContext)) { - if (*factory) - members.push_back(*factory); + // If there is an alternate declaration for this member, add it. + if (auto alternate = Impl.getAlternateDecl(member)) { + if (alternate->getDeclContext() == member->getDeclContext() && + knownMembers.insert(alternate).second) + members.push_back(alternate); } - // Objective-C root class instance methods are reflected on the - // metatype as well. - if (objcMethod->isInstanceMethod()) { - Type swiftTy = swiftContext->getDeclaredTypeInContext(); - auto swiftClass = swiftTy->getClassOrBoundGenericClass(); - if (swiftClass && !swiftClass->getSuperclass() && - !decl->getClassMethod(objcMethod->getSelector(), - /*AllowHidden=*/true)) { - auto classMember = VisitObjCMethodDecl(objcMethod, swiftContext, - true); - if (classMember) - members.push_back(classMember); - } - } - - // Import explicit properties as instance properties, not as separate - // getter and setter methods. - if (!Impl.isAccessibilityDecl(objcMethod)) { - // If this member is a method that is a getter or setter for a - // propertythat was imported, don't add it to the list of members - // so it won't be found by name lookup. This eliminates the - // ambiguity between property names and getter names (by choosing - // to only have a variable). - if (objcMethod->isPropertyAccessor()) { - auto prop = objcMethod->findPropertyDecl(/*checkOverrides=*/false); - assert(prop); - (void)Impl.importDecl(const_cast(prop)); - // We may have attached this member to an existing property even - // if we've failed to import a new property. - if (cast(member)->isAccessor()) - continue; - } else if (auto *proto = dyn_cast(decl)) { - if (isPotentiallyConflictingSetter(proto, objcMethod)) - continue; - } - } + // If this declaration shouldn't be visible, don't add it to + // the list. + if (Impl.shouldSuppressDeclImport(objcMethod)) continue; } members.push_back(member); } - - // Hack to deal with unannotated Objective-C protocols. If the protocol - // comes from clang and is not annotated and the protocol requirement - // itself is not annotated, then infer availability of the requirement - // based on its types. This makes it possible for a type to conform to an - // Objective-C protocol that is missing annotations but whose requirements - // use types that are less available than the conforming type. - auto *proto = dyn_cast(swiftContext); - if (!proto || proto->getAttrs().hasAttribute()) - return; - - for (Decl *member : members) { - inferProtocolMemberAvailability(Impl, swiftContext, member); - } - } static bool @@ -4220,10 +4110,7 @@ namespace { ArrayRef protocols, SmallVectorImpl &members, ASTContext &Ctx) { - Type swiftTy = dc->getDeclaredTypeInContext(); - auto swiftClass = swiftTy->getClassOrBoundGenericClass(); - bool isRoot = swiftClass && !swiftClass->getSuperclass(); - + assert(dc); const clang::ObjCInterfaceDecl *interfaceDecl = nullptr; const ClangModuleUnit *declModule; const ClangModuleUnit *interfaceModule; @@ -4324,13 +4211,10 @@ namespace { // Import the method. if (auto imported = Impl.importMirroredDecl(objcMethod, dc, proto)) { members.push_back(imported); - } - // Import instance methods of a root class also as class methods. - if (isRoot && objcMethod->isInstanceMethod()) { - if (auto classImport = Impl.importMirroredDecl(objcMethod, - dc, proto, true)) - members.push_back(classImport); + if (auto alternate = Impl.getAlternateDecl(imported)) + if (imported->getDeclContext() == alternate->getDeclContext()) + members.push_back(alternate); } } } @@ -4432,7 +4316,7 @@ namespace { auto superclass = cast(classDecl->getSuperclass()->getAnyNominal()); - // If we we have a superclass, import from it. + // If we have a superclass, import from it. if (auto superclassClangDecl = superclass->getClangDecl()) { if (isa(superclassClangDecl)) { inheritConstructors(superclass->getMembers(), kind); @@ -4880,6 +4764,8 @@ namespace { Decl *VisitObjCPropertyDecl(const clang::ObjCPropertyDecl *decl, DeclContext *dc) { + assert(dc); + auto name = Impl.importFullName(decl).Imported.getBaseName(); if (name.empty()) return nullptr; @@ -4901,8 +4787,13 @@ namespace { result->getFullName().getArgumentNames().empty()) return nullptr; - if (auto var = dyn_cast(result)) - overridden = var; + if (auto var = dyn_cast(result)) { + // If the selectors of the getter match in Objective-C, we have an + // override. + if (var->getObjCGetterSelector() == + Impl.importSelector(decl->getGetterName())) + overridden = var; + } } if (overridden) { @@ -5048,8 +4939,9 @@ classifyEnum(clang::Preprocessor &pp, const clang::EnumDecl *decl) { auto loc = decl->getLocStart(); if (loc.isMacroID()) { StringRef MacroName = pp.getImmediateMacroName(loc); - if (MacroName == "CF_ENUM" || MacroName == "OBJC_ENUM" || - MacroName == "SWIFT_ENUM" || MacroName == "__CF_NAMED_ENUM") + if (MacroName == "CF_ENUM" || MacroName == "__CF_NAMED_ENUM" || + MacroName == "OBJC_ENUM" || + MacroName == "SWIFT_ENUM" || MacroName == "SWIFT_ENUM_NAMED") return EnumKind::Enum; if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS") @@ -5332,8 +5224,8 @@ void ClangImporter::Implementation::importAttributes( if (auto MD = dyn_cast(MappedDecl)) { if (MD->getName().str() == "print" && MD->getDeclContext()->isTypeContext()) { - auto *formalParams = MD->getBodyParamPatterns()[1]; - if (formalParams->numTopLevelVariables() <= 1) { + auto *formalParams = MD->getParameterList(1); + if (formalParams->size() <= 1) { // Use a non-implicit attribute so it shows up in the generated // interface. MD->getAttrs().add( @@ -5377,11 +5269,57 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl, Result = converter.Visit(ClangDecl); HadForwardDeclaration = converter.hadForwardDeclaration(); } - if (!Result) + if (!Result) { + // If we couldn't import this Objective-C entity, determine + // whether it was a required member of a protocol. + bool hasMissingRequiredMember = false; + if (auto clangProto + = dyn_cast(ClangDecl->getDeclContext())) { + if (auto method = dyn_cast(ClangDecl)) { + if (method->getImplementationControl() + == clang::ObjCMethodDecl::Required) + hasMissingRequiredMember = true; + } else if (auto prop = dyn_cast(ClangDecl)) { + if (prop->getPropertyImplementation() + == clang::ObjCPropertyDecl::Required) + hasMissingRequiredMember = true; + } + + if (hasMissingRequiredMember) { + // Mark the protocol as having missing requirements. + if (auto proto = cast_or_null(importDecl(clangProto))) { + proto->setHasMissingRequirements(true); + } + } + } + return nullptr; + } + + // Finalize the imported declaration. + auto finalizeDecl = [&](Decl *result) { + importAttributes(ClangDecl, result); + + // Hack to deal with unannotated Objective-C protocols. If the protocol + // comes from clang and is not annotated and the protocol requirement + // itself is not annotated, then infer availability of the requirement + // based on its types. This makes it possible for a type to conform to an + // Objective-C protocol that is missing annotations but whose requirements + // use types that are less available than the conforming type. + auto dc = result->getDeclContext(); + auto *proto = dyn_cast(dc); + if (!proto || proto->getAttrs().hasAttribute()) + return; + + inferProtocolMemberAvailability(*this, dc, result); + }; - if (Result) - importAttributes(ClangDecl, Result); + if (Result) { + finalizeDecl(Result); + + if (auto alternate = getAlternateDecl(Result)) + finalizeDecl(alternate); + } #ifndef NDEBUG auto Canon = cast(ClangDecl->getCanonicalDecl()); @@ -5449,7 +5387,7 @@ void ClangImporter::Implementation::finishPendingActions() { RegisteredExternalDecls.clear(); } else { Decl *D = RegisteredExternalDecls.pop_back_val(); - SwiftContext.addedExternalDecl(D); + SwiftContext.addExternalDecl(D); if (auto typeResolver = getTypeResolver()) if (auto *nominal = dyn_cast(D)) if (!nominal->hasDelayedMembers()) @@ -5547,8 +5485,8 @@ Decl *ClangImporter::Implementation::importDeclAndCacheImpl( Decl * ClangImporter::Implementation::importMirroredDecl(const clang::NamedDecl *decl, DeclContext *dc, - ProtocolDecl *proto, - bool forceClassMethod) { + ProtocolDecl *proto) { + assert(dc); if (!decl) return nullptr; @@ -5557,47 +5495,50 @@ ClangImporter::Implementation::importMirroredDecl(const clang::NamedDecl *decl, "importing (mirrored)"); auto canon = decl->getCanonicalDecl(); - auto known = ImportedProtocolDecls.find({{canon, forceClassMethod}, dc }); + auto known = ImportedProtocolDecls.find({canon, dc }); if (known != ImportedProtocolDecls.end()) return known->second; SwiftDeclConverter converter(*this); Decl *result; if (auto method = dyn_cast(decl)) { - result = converter.VisitObjCMethodDecl(method, dc, forceClassMethod); + result = converter.VisitObjCMethodDecl(method, dc); } else if (auto prop = dyn_cast(decl)) { - assert(!forceClassMethod && "can't mirror properties yet"); result = converter.VisitObjCPropertyDecl(prop, dc); } else { llvm_unreachable("unexpected mirrored decl"); } if (result) { - if (!forceClassMethod) { - if (auto special = converter.importSpecialMethod(result, dc)) - result = special; - } - assert(result->getClangDecl() && result->getClangDecl() == canon); - result->setImplicit(); - // Map the Clang attributes onto Swift attributes. - importAttributes(decl, result); + auto updateMirroredDecl = [&](Decl *result) { + result->setImplicit(); + + // Map the Clang attributes onto Swift attributes. + importAttributes(decl, result); - if (proto->getAttrs().hasAttribute()) { - if (!result->getAttrs().hasAttribute()) { - VersionRange protoRange = + if (proto->getAttrs().hasAttribute()) { + if (!result->getAttrs().hasAttribute()) { + VersionRange protoRange = AvailabilityInference::availableRange(proto, SwiftContext); - applyAvailableAttribute(result, protoRange, SwiftContext); + applyAvailableAttribute(result, protoRange, SwiftContext); + } + } else { + // Infer the same availability for the mirrored declaration as + // we would for the protocol member it is mirroring. + inferProtocolMemberAvailability(*this, dc, result); } - } else { - // Infer the same availability for the mirrored declaration as we would for - // the protocol member it is mirroring. - inferProtocolMemberAvailability(*this, dc, result); - } + }; + + updateMirroredDecl(result); + + // Update the alternate declaration as well. + if (auto alternate = getAlternateDecl(result)) + updateMirroredDecl(alternate); } if (result || !converter.hadForwardDeclaration()) - ImportedProtocolDecls[{{canon, forceClassMethod}, dc}] = result; + ImportedProtocolDecls[{canon, dc}] = result; return result; } @@ -5727,32 +5668,19 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, SourceLoc(), name, type, dc); // Form the argument patterns. - SmallVector getterArgs; - + SmallVector getterArgs; + // 'self' if (dc->isTypeContext()) { - auto selfTy = dc->getDeclaredTypeInContext(); - if (isStatic) - selfTy = MetatypeType::get(selfTy); - - getterArgs.push_back( - Pattern::buildImplicitSelfParameter(SourceLoc(), - TypeLoc::withoutLoc(selfTy), - dc)); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), dc, isStatic); + getterArgs.push_back(ParameterList::createWithoutLoc(selfDecl)); } // empty tuple - getterArgs.push_back(TuplePattern::create(context, SourceLoc(), { }, - SourceLoc())); - getterArgs.back()->setType(TupleType::getEmpty(context)); + getterArgs.push_back(ParameterList::createEmpty(context)); // Form the type of the getter. - auto getterType = type; - for (auto it = getterArgs.rbegin(), itEnd = getterArgs.rend(); - it != itEnd; ++it) { - getterType = FunctionType::get((*it)->getType()->getUnlabeledType(context), - getterType); - } + auto getterType = ParameterList::getFullType(type, getterArgs); // Create the getter function declaration. auto func = FuncDecl::create(context, SourceLoc(), StaticSpellingKind::None, @@ -5849,8 +5777,8 @@ createUnavailableDecl(Identifier name, DeclContext *dc, Type type, void -ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t unused, - bool *hasMissingRequiredMembers) { +ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t unused) { + assert(D); assert(D->hasClangNode()); auto clangDecl = cast(D->getClangDecl()); @@ -5877,12 +5805,7 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t unused, ImportingEntityRAII Importing(*this); SmallVector members; - bool scratch; - if (!hasMissingRequiredMembers) - hasMissingRequiredMembers = &scratch; - *hasMissingRequiredMembers = false; - converter.importObjCMembers(clangDecl, DC, - members, *hasMissingRequiredMembers); + converter.importObjCMembers(clangDecl, DC, members); protos = takeImportedProtocols(D); if (auto clangClass = dyn_cast(clangDecl)) { @@ -5927,21 +5850,6 @@ ClangImporter::Implementation::getSpecialTypedefKind(clang::TypedefNameDecl *dec return iter->second; } -SubscriptDecl *ClangImporter::Implementation::importSubscriptOf(Decl *decl) { - SwiftDeclConverter converter(*this); - if (auto special = converter.importSpecialMethod(decl, decl->getDeclContext())) - return dyn_cast(special); - return nullptr; -} - -Decl *ClangImporter::Implementation::importClassMethodVersionOf( - FuncDecl *method) { - SwiftDeclConverter converter(*this); - auto objcMethod = cast(method->getClangDecl()); - return converter.VisitObjCMethodDecl(objcMethod, method->getDeclContext(), - true); -} - Identifier ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){ return Impl.importFullName(enumConstant).Imported.getBaseName(); diff --git a/lib/ClangImporter/ImportMacro.cpp b/lib/ClangImporter/ImportMacro.cpp index 0bb1555c9f559..6367eb695b857 100644 --- a/lib/ClangImporter/ImportMacro.cpp +++ b/lib/ClangImporter/ImportMacro.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -393,10 +393,25 @@ ValueDecl *ClangImporter::Implementation::importMacro(Identifier name, if (!macro) return nullptr; - // Look for the value for an already-imported macro. - auto known = ImportedMacros.find(macro); + // Look for macros imported with the same name. + auto known = ImportedMacros.find(name); if (known != ImportedMacros.end()) { - return known->second; + // Check whether this macro has already been imported. + for (const auto &entry : known->second) { + if (entry.first == macro) return entry.second; + } + + // Otherwise, check whether this macro is identical to a macro that has + // already been imported. + auto &clangPP = getClangPreprocessor(); + for (const auto &entry : known->second) { + // If the macro is equal to an existing macro, map down to the same + // declaration. + if (macro->isIdenticalTo(*entry.first, clangPP, true)) { + known->second.push_back({macro, entry.second}); + return entry.second; + } + } } ImportingEntityRAII ImportingEntity(*this); @@ -408,6 +423,6 @@ ValueDecl *ClangImporter::Implementation::importMacro(Identifier name, return nullptr; auto valueDecl = ::importMacro(*this, DC, name, macro, macro); - ImportedMacros[macro] = valueDecl; + ImportedMacros[name].push_back({macro, valueDecl}); return valueDecl; } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 55035c0158730..2854ac0c3b0e8 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,13 +23,14 @@ #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/Pattern.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Parse/Token.h" #include "swift/Basic/Fallthrough.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#include "clang/Lex/Preprocessor.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -329,7 +330,10 @@ namespace { pointee->getDecl()->getName() == "_NSZone") { Identifier Id_ObjectiveC = Impl.SwiftContext.Id_ObjectiveC; Module *objCModule = Impl.SwiftContext.getLoadedModule(Id_ObjectiveC); - Type wrapperTy = Impl.getNamedSwiftType(objCModule, "NSZone"); + Type wrapperTy = Impl.getNamedSwiftType( + objCModule, + Impl.SwiftContext.getSwiftName( + KnownFoundationEntity::NSZone)); if (wrapperTy) return wrapperTy; } @@ -721,11 +725,14 @@ namespace { } if (imported->hasName() && - imported->getName().str() == "NSString") { + imported->getName() + == Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSString)){ return { importedType, ImportHint::NSString }; } - if (imported->hasName() && imported->getName().str() == "NSArray") { + if (imported->hasName() && + imported->getName() + == Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSArray)) { // If we have type arguments, import them. ArrayRef typeArgs = type->getTypeArgs(); if (typeArgs.size() == 1) { @@ -741,7 +748,10 @@ namespace { return { importedType, ImportHint(ImportHint::NSArray, Type()) }; } - if (imported->hasName() && imported->getName().str() == "NSDictionary") { + if (imported->hasName() && + imported->getName() + == Impl.SwiftContext.getSwiftId( + KnownFoundationEntity::NSDictionary)) { // If we have type arguments, import them. ArrayRef typeArgs = type->getTypeArgs(); if (typeArgs.size() == 2) { @@ -768,7 +778,9 @@ namespace { ImportHint(ImportHint::NSDictionary, Type(), Type()) }; } - if (imported->hasName() && imported->getName().str() == "NSSet") { + if (imported->hasName() && + imported->getName() + == Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSSet)) { // If we have type arguments, import them. ArrayRef typeArgs = type->getTypeArgs(); if (typeArgs.size() == 1) { @@ -952,7 +964,8 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl, return Type(); // FIXME: Avoid string comparison by caching this identifier. - if (elementClass->getName().str() != "NSError") + if (elementClass->getName().str() != + impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSError)) return Type(); Module *foundationModule = impl.tryLoadFoundationModule(); @@ -961,7 +974,10 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl, != elementClass->getModuleContext()->getName()) return Type(); - return impl.getNamedSwiftType(foundationModule, "NSErrorPointer"); + return impl.getNamedSwiftType( + foundationModule, + impl.SwiftContext.getSwiftName( + KnownFoundationEntity::NSErrorPointer)); }; if (Type result = maybeImportNSErrorPointer()) return result; @@ -1326,15 +1342,13 @@ static OptionalTypeKind getParamOptionality( return OTK_ImplicitlyUnwrappedOptional; } -Type ClangImporter::Implementation::importFunctionType( - const clang::FunctionDecl *clangDecl, - clang::QualType resultType, - ArrayRef params, - bool isVariadic, bool isNoReturn, - bool isFromSystemModule, - bool hasCustomName, - SmallVectorImpl &bodyPatterns, - DeclName &name) { +Type ClangImporter::Implementation:: +importFunctionType(const clang::FunctionDecl *clangDecl, + clang::QualType resultType, + ArrayRef params, + bool isVariadic, bool isNoReturn, + bool isFromSystemModule, bool hasCustomName, + ParameterList *¶meterList, DeclName &name) { bool allowNSUIntegerAsInt = isFromSystemModule; if (allowNSUIntegerAsInt) { @@ -1378,10 +1392,7 @@ Type ClangImporter::Implementation::importFunctionType( return Type(); // Import the parameters. - SmallVector swiftArgParams; - SmallVector swiftBodyParams; - SmallVector argPatternElts; - SmallVector bodyPatternElts; + SmallVector parameters; unsigned index = 0; llvm::SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params); ArrayRef argNames = name.getArgumentNames(); @@ -1432,72 +1443,46 @@ Type ClangImporter::Implementation::importFunctionType( if (index < argNames.size()) name = argNames[index]; - // Compute the pattern to put into the body. - Pattern *bodyPattern; // It doesn't actually matter which DeclContext we use, so just use the // imported header unit. auto bodyVar = createDeclWithClangNode(param, /*IsLet*/ true, - SourceLoc(), name, + SourceLoc(), SourceLoc(), name, importSourceLoc(param->getLocation()), bodyName, swiftParamTy, ImportedHeaderUnit); - if (addNoEscapeAttr) { + if (addNoEscapeAttr) bodyVar->getAttrs().add( new (SwiftContext) NoEscapeAttr(/*IsImplicit=*/false)); - } - - bodyPattern = new (SwiftContext) NamedPattern(bodyVar); - bodyPattern->setType(swiftParamTy); - bodyPattern - = new (SwiftContext) TypedPattern(bodyPattern, - TypeLoc::withoutLoc(swiftParamTy)); - bodyPattern->setType(swiftParamTy); - bodyPatternElts.push_back(TuplePatternElt(bodyPattern)); - bodyPatternElts.back().setLabel(name, SourceLoc()); - // Add the tuple elements for the function types. - swiftArgParams.push_back(TupleTypeElt(swiftParamTy, name)); - swiftBodyParams.push_back(TupleTypeElt(swiftParamTy, bodyName)); + parameters.push_back(bodyVar); ++index; } // Append an additional argument to represent varargs. if (isVariadic) { - auto paramTy = BoundGenericType::get(SwiftContext.getArrayDecl(), Type(), - {SwiftContext.getAnyDecl()->getDeclaredType()}); - auto name = SwiftContext.getIdentifier("varargs"); - auto bodyVar = new (SwiftContext) ParamDecl(true, SourceLoc(), Identifier(), - SourceLoc(), name, paramTy, - ImportedHeaderUnit); - Pattern *bodyPattern = new (SwiftContext) NamedPattern(bodyVar); - bodyPattern->setType(paramTy); - bodyPattern = new (SwiftContext) TypedPattern(bodyPattern, - TypeLoc::withoutLoc(paramTy)); - bodyPattern->setType(paramTy); - bodyPatternElts.push_back(TuplePatternElt(Identifier(), SourceLoc(), - bodyPattern, true)); - swiftArgParams.push_back(TupleTypeElt(paramTy, Identifier(), - DefaultArgumentKind::None, true)); - swiftBodyParams.push_back(TupleTypeElt(paramTy, name, - DefaultArgumentKind::None, true)); + auto paramTy = BoundGenericType::get(SwiftContext.getArrayDecl(), Type(), + {SwiftContext.getAnyDecl()->getDeclaredType()}); + auto name = SwiftContext.getIdentifier("varargs"); + auto param = new (SwiftContext) ParamDecl(true, SourceLoc(), SourceLoc(), + Identifier(), + SourceLoc(), name, paramTy, + ImportedHeaderUnit); + + param->setVariadic(); + parameters.push_back(param); } - // Form the parameter tuples. - auto bodyParamsTy = TupleType::get(swiftBodyParams, SwiftContext); - - // Form the body patterns. - bodyPatterns.push_back(TuplePattern::create(SwiftContext, SourceLoc(), - bodyPatternElts, SourceLoc())); - bodyPatterns.back()->setType(bodyParamsTy); + // Form the parameter list. + parameterList = ParameterList::create(SwiftContext, parameters); FunctionType::ExtInfo extInfo; extInfo = extInfo.withIsNoReturn(isNoReturn); // Form the function type. - auto argTy = TupleType::get(swiftArgParams, SwiftContext); + auto argTy = parameterList->getType(SwiftContext); return FunctionType::get(argTy, swiftResultTy, extInfo); } @@ -1509,40 +1494,6 @@ static bool isObjCMethodResultAudited(const clang::Decl *decl) { decl->hasAttr()); } -namespace { - struct ErrorImportInfo { - ForeignErrorConvention::Kind Kind; - ForeignErrorConvention::IsOwned_t IsOwned; - ForeignErrorConvention::IsReplaced_t ReplaceParamWithVoid; - unsigned ParamIndex; - CanType ParamType; - CanType OrigResultType; - - ForeignErrorConvention asForeignErrorConvention() const { - assert(ParamType && "not fully initialized!"); - using FEC = ForeignErrorConvention; - switch (Kind) { - case FEC::ZeroResult: - return FEC::getZeroResult(ParamIndex, IsOwned, ReplaceParamWithVoid, - ParamType, OrigResultType); - case FEC::NonZeroResult: - return FEC::getNonZeroResult(ParamIndex, IsOwned, ReplaceParamWithVoid, - ParamType, OrigResultType); - case FEC::ZeroPreservedResult: - return FEC::getZeroPreservedResult(ParamIndex, IsOwned, - ReplaceParamWithVoid, ParamType); - case FEC::NilResult: - return FEC::getNilResult(ParamIndex, IsOwned, ReplaceParamWithVoid, - ParamType); - case FEC::NonNilError: - return FEC::getNonNilError(ParamIndex, IsOwned, ReplaceParamWithVoid, - ParamType); - } - llvm_unreachable("bad error convention"); - } - }; -} - /// Determine whether this is the name of an Objective-C collection /// with a single element type. static bool isObjCCollectionName(StringRef typeName) { @@ -1553,12 +1504,10 @@ static bool isObjCCollectionName(StringRef typeName) { /// Retrieve the name of the given Clang type for use when omitting /// needless words. OmissionTypeName ClangImporter::Implementation::getClangTypeNameForOmission( - clang::QualType type) { + clang::ASTContext &ctx, clang::QualType type) { if (type.isNull()) return OmissionTypeName(); - auto &ctx = getClangASTContext(); - // Dig through the type, looking for a typedef-name and stripping // references along the way. StringRef lastTypedefName; @@ -1653,7 +1602,8 @@ OmissionTypeName ClangImporter::Implementation::getClangTypeNameForOmission( return OmissionTypeName(className, None, "Object"); return OmissionTypeName(className, None, - getClangTypeNameForOmission(typeArgs[0]).Name); + getClangTypeNameForOmission(ctx, + typeArgs[0]).Name); } // Objective-C "id" type. @@ -1669,18 +1619,113 @@ OmissionTypeName ClangImporter::Implementation::getClangTypeNameForOmission( // Handle builtin types by importing them and getting the Swift name. if (auto builtinTy = type->getAs()) { - if (Type type = importType(clang::QualType(builtinTy, 0), - ImportTypeKind::Abstract, - /*allowNSUIntegerAsInt=*/true, - /*canFullyBridgeTypes=*/true, - OTK_None)) { - if (auto nominal = type->getAnyNominal()) { - OmissionTypeOptions options; - if (nominal->getName().str() == "Bool") - options |= OmissionTypeFlags::Boolean; - - return OmissionTypeName(nominal->getName().str(), options); + // Names of integer types. + static const char *intTypeNames[] = { + "UInt8", + "UInt16", + "UInt32", + "UInt64", + "UInt128" + }; + + /// Retrieve the name for an integer type based on its size. + auto getIntTypeName = [&](bool isSigned) -> StringRef { + switch (ctx.getTypeSize(builtinTy)) { + case 8: return StringRef(intTypeNames[0]).substr(isSigned ? 1 : 0); + case 16: return StringRef(intTypeNames[1]).substr(isSigned ? 1 : 0); + case 32: return StringRef(intTypeNames[2]).substr(isSigned ? 1 : 0); + case 64: return StringRef(intTypeNames[3]).substr(isSigned ? 1 : 0); + case 128: return StringRef(intTypeNames[4]).substr(isSigned ? 1 : 0); + default: llvm_unreachable("bad integer type size"); } + }; + + switch (builtinTy->getKind()) { + case clang::BuiltinType::Void: + return "Void"; + + case clang::BuiltinType::Bool: + return OmissionTypeName("Bool", OmissionTypeFlags::Boolean); + + case clang::BuiltinType::Float: + return "Float"; + + case clang::BuiltinType::Double: + return "Double"; + + case clang::BuiltinType::Char16: + return "UInt16"; + + case clang::BuiltinType::Char32: + return "UnicodeScalar"; + + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::WChar_U: + return getIntTypeName(false); + + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + case clang::BuiltinType::WChar_S: + return getIntTypeName(true); + + // Types that cannot be mapped into Swift, and probably won't ever be. + case clang::BuiltinType::Dependent: + case clang::BuiltinType::ARCUnbridgedCast: + case clang::BuiltinType::BoundMember: + case clang::BuiltinType::BuiltinFn: + case clang::BuiltinType::Overload: + case clang::BuiltinType::PseudoObject: + case clang::BuiltinType::UnknownAny: + return OmissionTypeName(); + + // FIXME: Types that can be mapped, but aren't yet. + case clang::BuiltinType::Half: + case clang::BuiltinType::LongDouble: + case clang::BuiltinType::NullPtr: + return OmissionTypeName(); + + // Objective-C types that aren't mapped directly; rather, pointers to + // these types will be mapped. + case clang::BuiltinType::ObjCClass: + case clang::BuiltinType::ObjCId: + case clang::BuiltinType::ObjCSel: + return OmissionTypeName(); + + // OpenCL types that don't have Swift equivalents. + case clang::BuiltinType::OCLImage1d: + case clang::BuiltinType::OCLImage1dArray: + case clang::BuiltinType::OCLImage1dBuffer: + case clang::BuiltinType::OCLImage2d: + case clang::BuiltinType::OCLImage2dArray: + case clang::BuiltinType::OCLImage2dDepth: + case clang::BuiltinType::OCLImage2dArrayDepth: + case clang::BuiltinType::OCLImage2dMSAA: + case clang::BuiltinType::OCLImage2dArrayMSAA: + case clang::BuiltinType::OCLImage2dMSAADepth: + case clang::BuiltinType::OCLImage2dArrayMSAADepth: + case clang::BuiltinType::OCLImage3d: + case clang::BuiltinType::OCLSampler: + case clang::BuiltinType::OCLEvent: + case clang::BuiltinType::OCLClkEvent: + case clang::BuiltinType::OCLQueue: + case clang::BuiltinType::OCLNDRange: + case clang::BuiltinType::OCLReserveID: + return OmissionTypeName(); + + // OpenMP types that don't have Swift equivalents. + case clang::BuiltinType::OMPArraySection: + return OmissionTypeName(); } } @@ -1705,7 +1750,7 @@ OmissionTypeName ClangImporter::Implementation::getClangTypeNameForOmission( /// Attempt to omit needless words from the given function name. bool ClangImporter::Implementation::omitNeedlessWordsInFunctionName( - clang::Preprocessor &pp, + clang::Sema &clangSema, StringRef &baseName, SmallVectorImpl &argumentNames, ArrayRef params, @@ -1717,6 +1762,8 @@ bool ClangImporter::Implementation::omitNeedlessWordsInFunctionName( bool returnsSelf, bool isInstanceMethod, StringScratchSpace &scratch) { + clang::ASTContext &clangCtx = clangSema.Context; + // Collect the parameter type names. StringRef firstParamName; SmallVector paramTypes; @@ -1738,9 +1785,12 @@ bool ClangImporter::Implementation::omitNeedlessWordsInFunctionName( // Figure out whether there will be a default argument for this // parameter. + StringRef argumentName; + if (i < argumentNames.size()) + argumentName = argumentNames[i]; bool hasDefaultArg - = canInferDefaultArgument( - pp, + = inferDefaultArgument( + clangSema.PP, param->getType(), getParamOptionality(param, !nonNullArgs.empty() && nonNullArgs[i], @@ -1749,9 +1799,9 @@ bool ClangImporter::Implementation::omitNeedlessWordsInFunctionName( knownMethod->getParamTypeInfo(i)) : None), SwiftContext.getIdentifier(baseName), numParams, - isLastParameter); + argumentName, isLastParameter) != DefaultArgumentKind::None; - paramTypes.push_back(getClangTypeNameForOmission(param->getType()) + paramTypes.push_back(getClangTypeNameForOmission(clangCtx, param->getType()) .withDefaultArgument(hasDefaultArg)); } @@ -1767,8 +1817,8 @@ bool ClangImporter::Implementation::omitNeedlessWordsInFunctionName( // Omit needless words. return omitNeedlessWords(baseName, argumentNames, firstParamName, - getClangTypeNameForOmission(resultType), - getClangTypeNameForOmission(contextType), + getClangTypeNameForOmission(clangCtx, resultType), + getClangTypeNameForOmission(clangCtx, contextType), paramTypes, returnsSelf, /*isProperty=*/false, allPropertyNames, scratch); } @@ -1793,21 +1843,22 @@ clang::QualType ClangImporter::Implementation::getClangDeclContextType( return clang::QualType(); } -bool ClangImporter::Implementation::canInferDefaultArgument( - clang::Preprocessor &pp, clang::QualType type, - OptionalTypeKind clangOptionality, Identifier baseName, - unsigned numParams, bool isLastParameter) { +DefaultArgumentKind ClangImporter::Implementation::inferDefaultArgument( + clang::Preprocessor &pp, clang::QualType type, + OptionalTypeKind clangOptionality, Identifier baseName, + unsigned numParams, StringRef argumentLabel, + bool isLastParameter) { // Don't introduce a default argument for setters with only a single // parameter. if (numParams == 1 && camel_case::getFirstWord(baseName.str()) == "set") - return false; + return DefaultArgumentKind::None; // Some nullable parameters default to 'nil'. if (clangOptionality == OTK_Optional) { // Nullable trailing closure parameters default to 'nil'. if (isLastParameter && (type->isFunctionPointerType() || type->isBlockPointerType())) - return true; + return DefaultArgumentKind::Nil; // NSZone parameters default to 'nil'. if (auto ptrType = type->getAs()) { @@ -1815,7 +1866,7 @@ bool ClangImporter::Implementation::canInferDefaultArgument( = ptrType->getPointeeType()->getAs()) { if (recType->isStructureOrClassType() && recType->getDecl()->getName() == "_NSZone") - return true; + return DefaultArgumentKind::Nil; } } } @@ -1826,11 +1877,46 @@ bool ClangImporter::Implementation::canInferDefaultArgument( auto enumName = enumTy->getDecl()->getName(); for (auto word : reversed(camel_case::getWords(enumName))) { if (camel_case::sameWordIgnoreFirstCase(word, "options")) - return true; + return DefaultArgumentKind::EmptyArray; } } - return false; + // NSDictionary arguments default to [:] if "options", "attributes", + // or "userInfo" occur in the argument label or (if there is no + // argument label) at the end of the base name. + if (auto objcPtrTy = type->getAs()) { + if (auto objcClass = objcPtrTy->getInterfaceDecl()) { + if (objcClass->getName() == "NSDictionary") { + StringRef searchStr = argumentLabel; + if (searchStr.empty() && !baseName.empty()) + searchStr = baseName.str(); + + bool sawInfo = false; + for (auto word : reversed(camel_case::getWords(searchStr))) { + if (camel_case::sameWordIgnoreFirstCase(word, "options")) + return DefaultArgumentKind::EmptyDictionary; + + if (camel_case::sameWordIgnoreFirstCase(word, "attributes")) + return DefaultArgumentKind::EmptyDictionary; + + if (camel_case::sameWordIgnoreFirstCase(word, "info")) { + sawInfo = true; + continue; + } + + if (sawInfo && camel_case::sameWordIgnoreFirstCase(word, "user")) + return DefaultArgumentKind::EmptyDictionary; + + if (argumentLabel.empty()) + break; + + sawInfo = false; + } + } + } + } + + return DefaultArgumentKind::None; } /// Adjust the result type of a throwing function based on the @@ -1893,7 +1979,7 @@ Type ClangImporter::Implementation::importMethodType( ArrayRef params, bool isVariadic, bool isNoReturn, bool isFromSystemModule, - SmallVectorImpl &bodyPatterns, + ParameterList **bodyParams, ImportedName importedName, DeclName &methodName, Optional &foreignErrorInfo, @@ -2001,28 +2087,17 @@ Type ClangImporter::Implementation::importMethodType( llvm::SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params); // Import the parameters. - SmallVector swiftArgParams; - SmallVector swiftBodyParams; - SmallVector bodyPatternElts; + SmallVector swiftParams; auto addEmptyTupleParameter = [&](Identifier argName) { // It doesn't actually matter which DeclContext we use, so just // use the imported header unit. auto type = TupleType::getEmpty(SwiftContext); - auto var = new (SwiftContext) ParamDecl(/*IsLet*/ true, + auto var = new (SwiftContext) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName, SourceLoc(), argName, type, ImportedHeaderUnit); - Pattern *pattern = new (SwiftContext) NamedPattern(var); - pattern->setType(type); - pattern = new (SwiftContext) TypedPattern(pattern, - TypeLoc::withoutLoc(type)); - pattern->setType(type); - - bodyPatternElts.push_back(TuplePatternElt(pattern)); - bodyPatternElts.back().setLabel(argName, SourceLoc()); - swiftArgParams.push_back(TupleTypeElt(type, argName)); - swiftBodyParams.push_back(TupleTypeElt(type, argName)); + swiftParams.push_back(var); }; // Determine the number of parameters. @@ -2127,30 +2202,11 @@ Type ClangImporter::Implementation::importMethodType( } ++nameIndex; - // Determine whether we have a default argument. - DefaultArgumentKind defaultArg = DefaultArgumentKind::None; - bool isLastParameter - = (paramIndex == params.size() - 1) || - (paramIndex == params.size() - 2 && - errorInfo && errorInfo->ParamIndex == params.size() - 1); - - if (InferDefaultArguments && - (kind == SpecialMethodKind::Regular || - kind == SpecialMethodKind::Constructor) && - canInferDefaultArgument(getClangPreprocessor(), - param->getType(), optionalityOfParam, - methodName.getBaseName(), numEffectiveParams, - isLastParameter)) { - defaultArg = DefaultArgumentKind::Normal; - } - - // Compute the pattern to put into the body. - Pattern *bodyPattern; // It doesn't actually matter which DeclContext we use, so just use the // imported header unit. auto bodyVar - = createDeclWithClangNode(param, - /*IsLet*/ true, SourceLoc(), name, + = createDeclWithClangNode(param, /*IsLet*/ true, + SourceLoc(), SourceLoc(), name, importSourceLoc(param->getLocation()), bodyName, swiftParamTy, ImportedHeaderUnit); @@ -2160,21 +2216,29 @@ Type ClangImporter::Implementation::importMethodType( new (SwiftContext) NoEscapeAttr(/*IsImplicit=*/false)); } - // Set up the body pattern. - bodyPattern = new (SwiftContext) NamedPattern(bodyVar); - bodyPattern->setType(swiftParamTy); - bodyPattern - = new (SwiftContext) TypedPattern(bodyPattern, - TypeLoc::withoutLoc(swiftParamTy)); - bodyPattern->setType(swiftParamTy); - TuplePatternElt patternElt(bodyPattern); - patternElt.setDefaultArgKind(defaultArg); - patternElt.setLabel(name, SourceLoc()); - bodyPatternElts.push_back(patternElt); - - // Add the tuple elements for the function types. - swiftArgParams.push_back(TupleTypeElt(swiftParamTy, name, defaultArg)); - swiftBodyParams.push_back(TupleTypeElt(swiftParamTy, bodyName, defaultArg)); + // Set up the parameter info. + auto paramInfo = bodyVar; + + // Determine whether we have a default argument. + if (InferDefaultArguments && + (kind == SpecialMethodKind::Regular || + kind == SpecialMethodKind::Constructor)) { + bool isLastParameter = (paramIndex == params.size() - 1) || + (paramIndex == params.size() - 2 && + errorInfo && errorInfo->ParamIndex == params.size() - 1); + + auto defaultArg = inferDefaultArgument(getClangPreprocessor(), + param->getType(), + optionalityOfParam, + methodName.getBaseName(), + numEffectiveParams, + name.empty() ? StringRef() + : name.str(), + isLastParameter); + if (defaultArg != DefaultArgumentKind::None) + paramInfo->setDefaultArgumentKind(defaultArg); + } + swiftParams.push_back(paramInfo); } // If we have a constructor with no parameters and a name with an @@ -2184,7 +2248,7 @@ Type ClangImporter::Implementation::importMethodType( addEmptyTupleParameter(argNames[0]); } - if (importedName.HasCustomName && argNames.size() != swiftBodyParams.size()) { + if (importedName.HasCustomName && argNames.size() != swiftParams.size()) { // Note carefully: we're emitting a warning in the /Clang/ buffer. auto &srcMgr = getClangASTContext().getSourceManager(); auto &rawDiagClient = Instance->getDiagnosticClient(); @@ -2193,19 +2257,15 @@ Type ClangImporter::Implementation::importMethodType( diagClient.resolveSourceLocation(srcMgr, clangDecl->getLocation()); if (methodLoc.isValid()) { SwiftContext.Diags.diagnose(methodLoc, diag::invalid_swift_name_method, - swiftBodyParams.size() < argNames.size(), - swiftBodyParams.size(), argNames.size()); + swiftParams.size() < argNames.size(), + swiftParams.size(), argNames.size()); } return Type(); } - // Form the parameter tuple. - auto bodyParamsTy = TupleType::get(swiftBodyParams, SwiftContext); - // Form the body patterns. - bodyPatterns.push_back(TuplePattern::create(SwiftContext, SourceLoc(), - bodyPatternElts, SourceLoc())); - bodyPatterns.back()->setType(bodyParamsTy); + // Form the parameter list. + *bodyParams = ParameterList::create(SwiftContext, swiftParams); FunctionType::ExtInfo extInfo; extInfo = extInfo.withIsNoReturn(isNoReturn); @@ -2219,8 +2279,8 @@ Type ClangImporter::Implementation::importMethodType( } // Form the function type. - auto argTy = TupleType::get(swiftArgParams, SwiftContext); - return FunctionType::get(argTy, swiftResultTy, extInfo); + return FunctionType::get((*bodyParams)->getType(SwiftContext), + swiftResultTy, extInfo); } Module *ClangImporter::Implementation::getStdlibModule() { diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 7ada117f13542..614e0f566e1e8 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1,8 +1,8 @@ -//===--- ImporterImpl.h - Import Clang Modules - Implementation------------===// +//===--- ImporterImpl.h - Import Clang Modules: Implementation --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -220,10 +220,31 @@ using api_notes::FactoryAsInitKind; /// \brief Implementation of the Clang importer. class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation - : public LazyMemberLoader, public clang::ModuleFileExtension + : public LazyMemberLoader { friend class ClangImporter; + class SwiftNameLookupExtension : public clang::ModuleFileExtension { + Implementation &Impl; + + public: + SwiftNameLookupExtension(Implementation &impl) : Impl(impl) { } + + clang::ModuleFileExtensionMetadata getExtensionMetadata() const override; + llvm::hash_code hashExtension(llvm::hash_code code) const override; + + std::unique_ptr + createExtensionWriter(clang::ASTWriter &writer) override; + + std::unique_ptr + createExtensionReader(const clang::ModuleFileExtensionMetadata &metadata, + clang::ASTReader &reader, + clang::serialization::ModuleFile &mod, + const llvm::BitstreamCursor &stream) override; + + }; + friend class SwiftNameLookupExtension; + public: /// \brief Describes how a particular C enumeration type will be imported /// into Swift. All of the possibilities have the same storage @@ -261,6 +282,16 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation ""; private: + /// The Swift lookup table for the bridging header. + SwiftLookupTable BridgingHeaderLookupTable; + + /// The Swift lookup tables, per module. + /// + /// Annoyingly, we list this table early so that it gets torn down after + /// the underlying Clang instances that reference it + /// (through the Swift name lookup module file extension). + llvm::StringMap> LookupTables; + /// \brief A count of the number of load module operations. /// FIXME: Horrible, horrible hack for \c loadModule(). unsigned ImportCounter = 0; @@ -292,12 +323,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// if type checking has begun. llvm::PointerIntPair typeResolver; - /// The Swift lookup table for the bridging header. - SwiftLookupTable BridgingHeaderLookupTable; - - /// The Swift lookup tables, per module. - llvm::StringMap> LookupTables; - public: /// \brief Mapping of already-imported declarations. llvm::DenseMap ImportedDecls; @@ -314,6 +339,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation llvm::SmallDenseMap SpecialTypedefNames; + /// A mapping from module names to the prefixes placed on global names + /// in that module, e.g., the Foundation module uses the "NS" prefix. + llvm::StringMap ModulePrefixes; + /// Is the given identifier a reserved name in Swift? static bool isSwiftReservedName(StringRef name); @@ -395,35 +424,33 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// \sa SuperfluousTypedefs llvm::DenseSet DeclsWithSuperfluousTypedefs; - using ClangDeclAndFlag = llvm::PointerIntPair; - /// \brief Mapping of already-imported declarations from protocols, which /// can (and do) get replicated into classes. - llvm::DenseMap, Decl *> + llvm::DenseMap, Decl *> ImportedProtocolDecls; - /// \brief Mapping of already-imported macros. - llvm::DenseMap ImportedMacros; + /// Mapping from identifiers to the set of macros that have that name along + /// with their corresponding Swift declaration. + /// + /// Multiple macro definitions can map to the same declaration if the + /// macros are identically defined. + llvm::DenseMap, 2>> + ImportedMacros; - /// Keeps track of active selector-basde lookups, so that we don't infinitely + /// Keeps track of active selector-based lookups, so that we don't infinitely /// recurse when checking whether a method with a given selector has already /// been imported. llvm::DenseMap, unsigned> ActiveSelectors; - // FIXME: An extra level of caching of visible decls, since lookup needs to - // be filtered by module after the fact. - SmallVector CachedVisibleDecls; - enum class CacheState { - Invalid, - InProgress, - Valid - } CurrentCacheState = CacheState::Invalid; + /// Whether we should suppress the import of the given Clang declaration. + static bool shouldSuppressDeclImport(const clang::Decl *decl); /// \brief Check if the declaration is one of the specially handled /// accessibility APIs. /// - /// These appaer as both properties and methods in ObjC and should be + /// These appear as both properties and methods in ObjC and should be /// imported as methods into Swift. static bool isAccessibilityDecl(const clang::Decl *objCMethodOrProp); @@ -487,8 +514,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation void bumpGeneration() { ++Generation; SwiftContext.bumpGeneration(); - CachedVisibleDecls.clear(); - CurrentCacheState = CacheState::Invalid; } /// \brief Cache of the class extensions. @@ -540,6 +565,19 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation ConstructorDecl *> Constructors; + /// A mapping from imported declarations to their "alternate" declarations, + /// for cases where a single Clang declaration is imported to two + /// different Swift declarations. + llvm::DenseMap AlternateDecls; + + /// Retrieve the alternative declaration for the given imported + /// Swift declaration. + ValueDecl *getAlternateDecl(Decl *decl) { + auto known = AlternateDecls.find(decl); + if (known == AlternateDecls.end()) return nullptr; + return known->second; + } + private: /// \brief NSObject, imported into Swift. Type NSObjectTy; @@ -734,16 +772,17 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Determine the imported CF type for the given typedef-name, or the empty /// string if this is not an imported CF type name. - StringRef getCFTypeName(const clang::TypedefNameDecl *decl, - StringRef *secondaryName = nullptr); + static StringRef getCFTypeName(const clang::TypedefNameDecl *decl, + StringRef *secondaryName = nullptr); /// Retrieve the type name of a Clang type for the purposes of /// omitting unneeded words. - OmissionTypeName getClangTypeNameForOmission(clang::QualType type); + static OmissionTypeName getClangTypeNameForOmission(clang::ASTContext &ctx, + clang::QualType type); /// Omit needless words in a function name. bool omitNeedlessWordsInFunctionName( - clang::Preprocessor &pp, + clang::Sema &clangSema, StringRef &baseName, SmallVectorImpl &argumentNames, ArrayRef params, @@ -918,14 +957,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /*SuperfluousTypedefsAreTransparent=*/false); } - /// Import the subscript declaration corresponding to the given - /// declaration, if there is one. - SubscriptDecl *importSubscriptOf(Decl *decl); - - /// Import the class-method version of the given Objective-C - /// instance method of a root class. - Decl *importClassMethodVersionOf(FuncDecl *method); - /// \brief Import a cloned version of the given declaration, which is part of /// an Objective-C protocol and currently must be a method or property, into /// the given declaration context. @@ -933,7 +964,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// \returns The imported declaration, or null if this declaration could not /// be represented in Swift. Decl *importMirroredDecl(const clang::NamedDecl *decl, DeclContext *dc, - ProtocolDecl *proto, bool forceClassMethod = false); + ProtocolDecl *proto); /// \brief Import the given Clang declaration context into Swift. /// @@ -1116,7 +1147,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// \param params The parameter types to the function. /// \param isVariadic Whether the function is variadic. /// \param isNoReturn Whether the function is noreturn. - /// \param bodyPatterns The patterns visible inside the function body. + /// \param parameterList The parameters visible inside the function body. /// /// \returns the imported function type, or null if the type cannot be /// imported. @@ -1126,20 +1157,21 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation bool isVariadic, bool isNoReturn, bool isFromSystemModule, bool hasCustomName, - SmallVectorImpl &bodyPatterns, + ParameterList *¶meterList, DeclName &name); Type importPropertyType(const clang::ObjCPropertyDecl *clangDecl, bool isFromSystemModule); - /// Determine whether we can infer a default argument for a parameter with - /// the given \c type and (Clang) optionality. - bool canInferDefaultArgument(clang::Preprocessor &pp, - clang::QualType type, - OptionalTypeKind clangOptionality, - Identifier baseName, - unsigned numParams, - bool isLastParameter); + /// Attempt to infer a default argument for a parameter with the + /// given Clang \c type, \c baseName, and optionality. + DefaultArgumentKind inferDefaultArgument(clang::Preprocessor &pp, + clang::QualType type, + OptionalTypeKind clangOptionality, + Identifier baseName, + unsigned numParams, + StringRef argumentLabel, + bool isLastParameter); /// Retrieve a bit vector containing the non-null argument /// annotations for the given declaration. @@ -1162,7 +1194,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// \param isNoReturn Whether the function is noreturn. /// \param isFromSystemModule Whether to apply special rules that only apply /// to system APIs. - /// \param bodyPatterns The patterns visible inside the function body. + /// \param bodyParams The patterns visible inside the function body. /// whether the created arg/body patterns are different (selector-style). /// \param importedName The name of the imported method. /// \param errorConvention Information about the method's error conventions. @@ -1176,7 +1208,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation ArrayRef params, bool isVariadic, bool isNoReturn, bool isFromSystemModule, - SmallVectorImpl &bodyPatterns, + ParameterList **bodyParams, ImportedName importedName, DeclName &name, Optional &errorConvention, @@ -1254,8 +1286,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation } virtual void - loadAllMembers(Decl *D, uint64_t unused, - bool *hasMissingRequiredMembers) override; + loadAllMembers(Decl *D, uint64_t unused) override; void loadAllConformances( @@ -1277,26 +1308,21 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation return D; } - // Module file extension overrides - - clang::ModuleFileExtensionMetadata getExtensionMetadata() const override; - llvm::hash_code hashExtension(llvm::hash_code code) const override; - - std::unique_ptr - createExtensionWriter(clang::ASTWriter &writer) override; - - std::unique_ptr - createExtensionReader(const clang::ModuleFileExtensionMetadata &metadata, - clang::ASTReader &reader, - clang::serialization::ModuleFile &mod, - const llvm::BitstreamCursor &stream) override; - /// Find the lookup table that corresponds to the given Clang module. /// /// \param clangModule The module, or null to indicate that we're talking /// about the directly-parsed headers. SwiftLookupTable *findLookupTable(const clang::Module *clangModule); + /// Look for namespace-scope values with the given name in the given + /// Swift lookup table. + void lookupValue(SwiftLookupTable &table, DeclName name, + VisibleDeclConsumer &consumer); + + /// Look for namespace-scope values in the given Swift lookup table. + void lookupVisibleDecls(SwiftLookupTable &table, + VisibleDeclConsumer &consumer); + /// Look for Objective-C members with the given name in the given /// Swift lookup table. void lookupObjCMembers(SwiftLookupTable &table, DeclName name, diff --git a/lib/ClangImporter/InferredAttributes.def b/lib/ClangImporter/InferredAttributes.def index b7eda9f2f9dcb..54a14a3805546 100644 --- a/lib/ClangImporter/InferredAttributes.def +++ b/lib/ClangImporter/InferredAttributes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,7 @@ // ClassName is the name of the class, i.e., NSManagedObject // AttributeSet is an OR of attribute names, i.e., requires_stored_property_inits // -// ===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #ifndef INFERRED_ATTRIBUTES # define INFERRED_ATTRIBUTES(ModuleName, ClassName, AttributeSet) diff --git a/lib/ClangImporter/MacroTable.def b/lib/ClangImporter/MacroTable.def index 0c4265d1221de..11fc68104b16e 100644 --- a/lib/ClangImporter/MacroTable.def +++ b/lib/ClangImporter/MacroTable.def @@ -1,8 +1,8 @@ -//===--- SuppressedMacros.def - Macros suppressed during import -*- C++ -*-===// +//===--- MacroTable.def - Macros suppressed during import -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,7 +13,7 @@ // This file defines the database of macros that should be suppressed during // API import. // -// ===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #ifndef SUPPRESS_MACRO /// Describes a macro that should be suppressed. diff --git a/lib/ClangImporter/MappedTypes.def b/lib/ClangImporter/MappedTypes.def index 6f6e822b59a7d..474a78b4e2183 100644 --- a/lib/ClangImporter/MappedTypes.def +++ b/lib/ClangImporter/MappedTypes.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -140,11 +140,15 @@ MAP_TYPE("BOOL", ObjCBool, 8, "ObjectiveC", "ObjCBool", false, DoNothing) MAP_TYPE("SEL", ObjCSel, 0, "ObjectiveC", "Selector", false, DoNothing) MAP_STDLIB_TYPE("id", ObjCId, 0, "AnyObject", false, DoNothing) MAP_STDLIB_TYPE("Class", ObjCClass, 0, "AnyClass", false, DoNothing) -MAP_STDLIB_TYPE("NSInteger", SignedWord, 0, "Int", false, DefineOnly) +MAP_STDLIB_TYPE( + Impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSInteger), + SignedWord, 0, "Int", false, DefineOnly) // Treat NSUInteger specially: exposing it as a typealias for "Int" would be // confusing. -MAP_STDLIB_TYPE("NSUInteger", UnsignedWord, 0, "Int", false, DoNothing) +MAP_STDLIB_TYPE( + Impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSUInteger), + UnsignedWord, 0, "Int", false, DoNothing) // CoreGraphics types. MAP_TYPE("CGFloat", CGFloat, 0, "CoreGraphics", "CGFloat", false, DoNothing) @@ -155,7 +159,9 @@ MAP_STDLIB_TYPE("CFIndex", SignedWord, 0, "Int", false, DefineAndUse) // Foundation types. // FIXME: NSStringEncoding doesn't work on 32-bit -MAP_STDLIB_TYPE("NSStringEncoding", UnsignedWord, 0, "UInt", false, DoNothing) +MAP_STDLIB_TYPE( + Impl.SwiftContext.getSwiftName(KnownFoundationEntity::NSStringEncoding), + UnsignedWord, 0, "UInt", false, DoNothing) #undef MAP_STDLIB_TYPE #undef MAP_TYPE diff --git a/lib/ClangImporter/SortedCFDatabase.def.gyb b/lib/ClangImporter/SortedCFDatabase.def.gyb index 0cfa84e9c9f05..af16cf242eeef 100644 --- a/lib/ClangImporter/SortedCFDatabase.def.gyb +++ b/lib/ClangImporter/SortedCFDatabase.def.gyb @@ -6,7 +6,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,6 +17,7 @@ %{ import re +import codecs prologueLines = "" epilogueLines = "" @@ -26,7 +27,7 @@ epilogueLines = "" lineForName = {} # Load the data file. -with open(CFDatabaseFile, 'rb') as f: +with codecs.open(CFDatabaseFile, encoding='utf-8', errors='strict') as f: for line in f: # Pass through preprocessor directives literally. # Assume that they all fall into either a strict prologue or epilogue. @@ -38,7 +39,7 @@ with open(CFDatabaseFile, 'rb') as f: continue # Otherwise, check for lines like FOO(BAR) - m = re.match('^\w+\((\w+)\)', line) + m = re.match('^\w+\((\w+)\)', line) if m: lineForName[m.group(1)] = line }% diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index d2369596ce0cb..42fff62d0b8f5 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -80,6 +80,13 @@ SwiftLookupTable::translateContext(clang::DeclContext *context) { return None; } +void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) { + assert(!Reader && "Cannot modify a lookup table stored on disk"); + + // Add the category. + Categories.push_back(category); +} + void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry, clang::DeclContext *effectiveContext) { assert(!Reader && "Cannot modify a lookup table stored on disk"); @@ -99,9 +106,16 @@ void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry, // Check whether this entry matches any existing entry. for (auto &existingEntry : entry.DeclsOrMacros) { + // If it matches an existing declaration, there's nothing to do. if (decl && isDeclEntry(existingEntry) && matchesExistingDecl(decl, mapStoredDecl(existingEntry))) return; + + // If it matches an existing macro, overwrite the existing entry. + if (macro && isMacroEntry(existingEntry)) { + existingEntry = encodeEntry(macro); + return; + } } // Add an entry to this context. @@ -132,17 +146,18 @@ auto SwiftLookupTable::findOrCreate(StringRef baseName) // Find entries for this base name. auto known = LookupTable.find(baseName); - // If we found somthing, we're done. + // If we found something, we're done. if (known != LookupTable.end()) return known; // If there's no reader, we've found all there is to find. if (!Reader) return known; - // Add an entry to the table so we don't look again. - known = LookupTable.insert({ baseName, { } }).first; - // Lookup this base name in the module file. - (void)Reader->lookup(baseName, known->second); + SmallVector results; + (void)Reader->lookup(baseName, results); + + // Add an entry to the table so we don't look again. + known = LookupTable.insert({ std::move(baseName), std::move(results) }).first; return known; } @@ -221,6 +236,22 @@ SwiftLookupTable::lookupObjCMembers(StringRef baseName) { return result; } +ArrayRef SwiftLookupTable::categories() { + if (!Categories.empty() || !Reader) return Categories; + + // Map categories known to the reader. + for (auto declID : Reader->categories()) { + auto category = + cast_or_null( + Reader->getASTReader().GetLocalDecl(Reader->getModuleFile(), declID)); + if (category) + Categories.push_back(category); + + } + + return Categories; +} + static void printName(clang::NamedDecl *named, llvm::raw_ostream &out) { // If there is a name, print it. if (!named->getDeclName().isEmpty()) { @@ -278,6 +309,8 @@ void SwiftLookupTable::deserializeAll() { for (auto baseName : Reader->getBaseNames()) { (void)lookup(baseName, nullptr); } + + (void)categories(); } void SwiftLookupTable::dump() const { @@ -324,6 +357,29 @@ void SwiftLookupTable::dump() const { llvm::errs() << "\n"; } } + + if (!Categories.empty()) { + llvm::errs() << "Categories: "; + interleave(Categories.begin(), Categories.end(), + [](clang::ObjCCategoryDecl *category) { + llvm::errs() << category->getClassInterface()->getName() + << "(" << category->getName() << ")"; + }, + [] { + llvm::errs() << ", "; + }); + llvm::errs() << "\n"; + } else if (Reader && !Reader->categories().empty()) { + llvm::errs() << "Categories: "; + interleave(Reader->categories().begin(), Reader->categories().end(), + [](clang::serialization::DeclID declID) { + llvm::errs() << "decl ID #" << declID; + }, + [] { + llvm::errs() << ", "; + }); + llvm::errs() << "\n"; + } } // --------------------------------------------------------------------------- @@ -343,11 +399,17 @@ namespace { /// name. BASE_NAME_TO_ENTITIES_RECORD_ID = clang::serialization::FIRST_EXTENSION_RECORD_ID, + + /// Record that contains the list of Objective-C category/extension IDs. + CATEGORIES_RECORD_ID }; using BaseNameToEntitiesTableRecordLayout = BCRecordLayout, BCBlob>; + using CategoriesRecordLayout + = llvm::BCRecordLayout; + /// Trait used to write the on-disk hash table for the base name -> entities /// mapping. class BaseNameToEntitiesTableWriterInfo { @@ -477,6 +539,19 @@ void SwiftLookupTableWriter::writeExtensionContents( BaseNameToEntitiesTableRecordLayout layout(stream); layout.emit(ScratchRecord, tableOffset, hashTableBlob); } + + // Write the categories, if there are any. + if (!table.Categories.empty()) { + SmallVector categoryIDs; + for (auto category : table.Categories) { + categoryIDs.push_back(Writer.getDeclID(category)); + } + + StringRef blob(reinterpret_cast(categoryIDs.data()), + categoryIDs.size() * sizeof(clang::serialization::DeclID)); + CategoriesRecordLayout layout(stream); + layout.emit(ScratchRecord, blob); + } } namespace { @@ -626,6 +701,7 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, auto cursor = stream; auto next = cursor.advance(); std::unique_ptr serializedTable; + ArrayRef categories; while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) return nullptr; @@ -660,6 +736,18 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, break; } + case CATEGORIES_RECORD_ID: { + // Already saw categories; input is malformed. + if (!categories.empty()) return nullptr; + + auto start = + reinterpret_cast(blobData.data()); + unsigned numElements + = blobData.size() / sizeof(clang::serialization::DeclID); + categories = llvm::makeArrayRef(start, numElements); + break; + } + default: // Unknown record, possibly for use by a future version of the // module format. @@ -674,7 +762,7 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, // Create the reader. return std::unique_ptr( new SwiftLookupTableReader(extension, reader, moduleFile, onRemove, - serializedTable.release())); + serializedTable.release(), categories)); } diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index 8124c1e331a2f..bfe1bc0fb927b 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -36,6 +36,7 @@ namespace clang { class NamedDecl; class DeclContext; class MacroInfo; +class ObjCCategoryDecl; } namespace swift { @@ -47,10 +48,10 @@ class SwiftLookupTableWriter; /// const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1; -/// Lookup table major version number. +/// Lookup table minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 0; +const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 2; /// A lookup table that maps Swift names to the set of Clang /// declarations with that particular name. @@ -162,6 +163,9 @@ class SwiftLookupTable { /// the C entities that have that name, in all contexts. llvm::DenseMap> LookupTable; + /// The list of Objective-C categories and extensions. + llvm::SmallVector Categories; + /// The reader responsible for lazily loading the contents of this table. SwiftLookupTableReader *Reader; @@ -196,6 +200,9 @@ class SwiftLookupTable { void addEntry(DeclName name, SingleEntry newEntry, clang::DeclContext *effectiveContext); + /// Add an Objective-C category or extension to the table. + void addCategory(clang::ObjCCategoryDecl *category); + /// Lookup the set of entities with the given base name. /// /// \param baseName The base name to search for. All results will @@ -214,6 +221,9 @@ class SwiftLookupTable { /// of context. SmallVector lookupObjCMembers(StringRef baseName); + /// Retrieve the set of Objective-C categories and extensions. + ArrayRef categories(); + /// Deserialize all entries. void deserializeAll(); @@ -245,15 +255,17 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader { std::function OnRemove; void *SerializedTable; + ArrayRef Categories; SwiftLookupTableReader(clang::ModuleFileExtension *extension, clang::ASTReader &reader, clang::serialization::ModuleFile &moduleFile, std::function onRemove, - void *serializedTable) + void *serializedTable, + ArrayRef categories) : ModuleFileExtensionReader(extension), Reader(reader), ModuleFile(moduleFile), OnRemove(onRemove), - SerializedTable(serializedTable) { } + SerializedTable(serializedTable), Categories(categories) { } public: /// Create a new lookup table reader for the given AST reader and stream @@ -280,6 +292,11 @@ class SwiftLookupTableReader : public clang::ModuleFileExtensionReader { /// \returns true if we found anything, false otherwise. bool lookup(StringRef baseName, SmallVectorImpl &entries); + + /// Retrieve the declaration IDs of the categories. + ArrayRef categories() const { + return Categories; + } }; } diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 6575cda5e30b2..ed3f6c014b125 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,8 +18,8 @@ using namespace swift::driver; using namespace llvm::opt; -Action::~Action() { - if (OwnsInputs) { +JobAction::~JobAction() { + if (getOwnsInputs()) { llvm::DeleteContainerPointers(Inputs); } } diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 7dfdffc5ca0a2..f73fca77057da 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,18 +40,18 @@ using namespace swift::sys; using namespace swift::driver; using namespace llvm::opt; -Compilation::Compilation(const Driver &D, const ToolChain &DefaultToolChain, - DiagnosticEngine &Diags, OutputLevel Level, +Compilation::Compilation(DiagnosticEngine &Diags, OutputLevel Level, std::unique_ptr InputArgs, std::unique_ptr TranslatedArgs, + InputFileList InputsWithTypes, StringRef ArgsHash, llvm::sys::TimeValue StartTime, unsigned NumberOfParallelCommands, bool EnableIncrementalBuild, bool SkipTaskExecution, bool SaveTemps) - : TheDriver(D), DefaultToolChain(DefaultToolChain), Diags(Diags), - Level(Level), InputArgs(std::move(InputArgs)), - TranslatedArgs(std::move(TranslatedArgs)), ArgsHash(ArgsHash), + : Diags(Diags), Level(Level), RawInputArgs(std::move(InputArgs)), + TranslatedArgs(std::move(TranslatedArgs)), + InputFilesWithTypes(std::move(InputsWithTypes)), ArgsHash(ArgsHash), BuildStartTime(StartTime), NumberOfParallelCommands(NumberOfParallelCommands), SkipTaskExecution(SkipTaskExecution), @@ -215,6 +215,43 @@ static void writeCompilationRecord(StringRef path, StringRef argsHash, } } +static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) { + FilelistInfo filelistInfo = job->getFilelistInfo(); + if (filelistInfo.path.empty()) + return true; + + std::error_code error; + llvm::raw_fd_ostream out(filelistInfo.path, error, llvm::sys::fs::F_None); + if (out.has_error()) { + out.clear_error(); + diags.diagnose(SourceLoc(), diag::error_unable_to_make_temporary_file, + error.message()); + return false; + } + + if (filelistInfo.whichFiles == FilelistInfo::Input) { + // FIXME: Duplicated from ToolChains.cpp. + for (const Job *input : job->getInputs()) { + const CommandOutput &outputInfo = input->getOutput(); + if (outputInfo.getPrimaryOutputType() == filelistInfo.type) { + for (auto &output : outputInfo.getPrimaryOutputFilenames()) + out << output << "\n"; + } else { + auto &output = outputInfo.getAnyOutputForType(filelistInfo.type); + if (!output.empty()) + out << output << "\n"; + } + } + } else { + const CommandOutput &outputInfo = job->getOutput(); + assert(outputInfo.getPrimaryOutputType() == filelistInfo.type); + for (auto &output : outputInfo.getPrimaryOutputFilenames()) + out << output << "\n"; + } + + return true; +} + int Compilation::performJobsImpl() { // Create a TaskQueue for execution. std::unique_ptr TQ; @@ -262,6 +299,11 @@ int Compilation::performJobsImpl() { return; } + // FIXME: Failing here should not take down the whole process. + bool success = writeFilelistIfNecessary(Cmd, Diags); + assert(success && "failed to write filelist"); + (void)success; + assert(Cmd->getExtraEnvironment().empty() && "not implemented for compilations with multiple jobs"); State.ScheduledCommands.insert(Cmd); @@ -575,6 +617,9 @@ int Compilation::performSingleCommand(const Job *Cmd) { break; } + if (!writeFilelistIfNecessary(Cmd, Diags)) + return 1; + if (Level == OutputLevel::Verbose) Cmd->printCommandLine(llvm::errs()); @@ -592,7 +637,31 @@ int Compilation::performSingleCommand(const Job *Cmd) { return ExecuteInPlace(ExecPath, argv); } +static bool writeAllSourcesFile(DiagnosticEngine &diags, StringRef path, + ArrayRef inputFiles) { + std::error_code error; + llvm::raw_fd_ostream out(path, error, llvm::sys::fs::F_None); + if (out.has_error()) { + out.clear_error(); + diags.diagnose(SourceLoc(), diag::error_unable_to_make_temporary_file, + error.message()); + return false; + } + + for (auto inputPair : inputFiles) { + if (!types::isPartOfSwiftCompilation(inputPair.first)) + continue; + out << inputPair.second->getValue() << "\n"; + } + + return true; +} + int Compilation::performJobs() { + if (AllSourceFilesPath) + if (!writeAllSourcesFile(Diags, AllSourceFilesPath, getInputFiles())) + return EXIT_FAILURE; + // If we don't have to do any cleanup work, just exec the subprocess. if (Level < OutputLevel::Parseable && (SaveTemps || TempFilePaths.empty()) && @@ -604,7 +673,7 @@ int Compilation::performJobs() { if (!TaskQueue::supportsParallelExecution() && NumberOfParallelCommands > 1) { Diags.diagnose(SourceLoc(), diag::warning_parallel_execution_not_supported); } - + int result = performJobsImpl(); if (!SaveTemps) { @@ -618,3 +687,22 @@ int Compilation::performJobs() { return result; } + +const char *Compilation::getAllSourcesPath() const { + if (!AllSourceFilesPath) { + SmallString<128> Buffer; + std::error_code EC = + llvm::sys::fs::createTemporaryFile("sources", "", Buffer); + if (EC) { + Diags.diagnose(SourceLoc(), + diag::error_unable_to_make_temporary_file, + EC.message()); + // FIXME: This should not take down the entire process. + llvm::report_fatal_error("unable to create list of input sources"); + } + auto *mutableThis = const_cast(this); + mutableThis->addTemporaryFile(Buffer.str()); + mutableThis->AllSourceFilesPath = getArgs().MakeArgString(Buffer); + } + return AllSourceFilesPath; +} diff --git a/lib/Driver/DependencyGraph.cpp b/lib/Driver/DependencyGraph.cpp index c57ce62a5bda9..ab58826a5e0dc 100644 --- a/lib/Driver/DependencyGraph.cpp +++ b/lib/Driver/DependencyGraph.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 86ad11daab494..3383e0f2495ec 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1,8 +1,8 @@ -//===-- Driver.cpp - Swift compiler driver --------------------------------===// +//===--- Driver.cpp - Swift compiler driver -------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -147,6 +147,13 @@ static void validateArgs(DiagnosticEngine &diags, const ArgList &Args) { } } } + + // Check for conflicting warning control flags + if (Args.hasArg(options::OPT_suppress_warnings) && + Args.hasArg(options::OPT_warnings_as_errors)) { + diags.diagnose(SourceLoc(), diag::error_conflicting_options, + "-warnings-as-errors", "-suppress-warnings"); + } } static void computeArgsHash(SmallString<32> &out, const DerivedArgList &args) { @@ -184,7 +191,7 @@ class Driver::InputInfoMap using InputInfoMap = Driver::InputInfoMap; static bool populateOutOfDateMap(InputInfoMap &map, StringRef argsHashStr, - const Driver::InputList &inputs, + const InputFileList &inputs, StringRef buildRecordPath) { // Treat a missing file as "no previous build". auto buffer = llvm::MemoryBuffer::getFile(buildRecordPath); @@ -384,7 +391,7 @@ std::unique_ptr Driver::buildCompilation( } // Construct the list of inputs. - InputList Inputs; + InputFileList Inputs; buildInputs(*TC, *TranslatedArgList, Inputs); if (Diags.hadAnyError()) @@ -486,16 +493,17 @@ std::unique_ptr Driver::buildCompilation( llvm_unreachable("Unknown OutputLevel argument!"); } - std::unique_ptr C(new Compilation(*this, *TC, Diags, Level, + std::unique_ptr C(new Compilation(Diags, Level, std::move(ArgList), std::move(TranslatedArgList), + std::move(Inputs), ArgsHash, StartTime, NumberOfParallelCommands, Incremental, DriverSkipExecution, SaveTemps)); - buildJobs(Actions, OI, OFM.get(), *C); + buildJobs(Actions, OI, OFM.get(), *TC, *C); // For updating code we need to go through all the files and pick up changes, // even if they have compiler errors. @@ -710,7 +718,7 @@ static bool checkInputExistence(const Driver &D, const DerivedArgList &Args, void Driver::buildInputs(const ToolChain &TC, const DerivedArgList &Args, - InputList &Inputs) const { + InputFileList &Inputs) const { types::ID InputType = types::TY_Nothing; Arg *InputTypeArg = nullptr; @@ -765,7 +773,7 @@ void Driver::buildInputs(const ToolChain &TC, static bool maybeBuildingExecutable(const OutputInfo &OI, const DerivedArgList &Args, - const Driver::InputList &Inputs) { + const InputFileList &Inputs) { switch (OI.LinkAction) { case LinkKind::Executable: return true; @@ -850,7 +858,8 @@ static bool isSDKTooOld(StringRef sdkPath, const llvm::Triple &target) { } void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, - const InputList &Inputs, OutputInfo &OI) const { + const InputFileList &Inputs, + OutputInfo &OI) const { // By default, the driver does not link its output; this will be updated // appropriately below if linking is required. @@ -1096,10 +1105,10 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, void Driver::buildActions(const ToolChain &TC, const DerivedArgList &Args, - const InputList &Inputs, + const InputFileList &Inputs, const OutputInfo &OI, const OutputFileMap *OFM, - InputInfoMap *OutOfDateMap, + const InputInfoMap *OutOfDateMap, ActionList &Actions) const { if (!SuppressNoInputFilesError && Inputs.empty()) { Diags.diagnose(SourceLoc(), diag::error_no_input_files); @@ -1122,6 +1131,8 @@ void Driver::buildActions(const ToolChain &TC, case types::TY_SIL: case types::TY_SIB: { // Source inputs always need to be compiled. + assert(types::isPartOfSwiftCompilation(InputType)); + CompileJobAction::InputInfo previousBuildState = { CompileJobAction::InputInfo::NeedsCascadingBuild, llvm::sys::TimeValue::MinTime() @@ -1194,15 +1205,14 @@ void Driver::buildActions(const ToolChain &TC, bool HandledHere = true; for (const InputPair &Input : Inputs) { types::ID InputType = Input.first; - if (InputType != types::TY_Swift && InputType != types::TY_SIL && - InputType != types::TY_SIB) { + if (!types::isPartOfSwiftCompilation(InputType)) { HandledHere = false; break; } } if (HandledHere) { // Create a single CompileJobAction and a single BackendJobAction. - std::unique_ptr CA(new CompileJobAction(types::TY_LLVM_BC)); + std::unique_ptr CA(new CompileJobAction(types::TY_LLVM_BC)); AllModuleInputs.push_back(CA.get()); int InputIndex = 0; @@ -1236,7 +1246,7 @@ void Driver::buildActions(const ToolChain &TC, } // Create a single CompileJobAction for all of the driver's inputs. - std::unique_ptr CA(new CompileJobAction(OI.CompilerOutputType)); + std::unique_ptr CA(new CompileJobAction(OI.CompilerOutputType)); for (const InputPair &Input : Inputs) { types::ID InputType = Input.first; const Arg *InputArg = Input.second; @@ -1252,7 +1262,7 @@ void Driver::buildActions(const ToolChain &TC, return; assert(OI.CompilerOutputType == types::TY_Nothing); - std::unique_ptr CA(new InterpretJobAction()); + std::unique_ptr CA(new InterpretJobAction()); for (const InputPair &Input : Inputs) { types::ID InputType = Input.first; const Arg *InputArg = Input.second; @@ -1283,7 +1293,7 @@ void Driver::buildActions(const ToolChain &TC, } } - std::unique_ptr MergeModuleAction; + std::unique_ptr MergeModuleAction; if (OI.ShouldGenerateModule && OI.CompilerMode != OutputInfo::Mode::SingleCompile && !AllModuleInputs.empty()) { @@ -1294,13 +1304,13 @@ void Driver::buildActions(const ToolChain &TC, } if (OI.shouldLink() && !AllLinkerInputs.empty()) { - Action *LinkAction = new LinkJobAction(AllLinkerInputs, OI.LinkAction); + auto *LinkAction = new LinkJobAction(AllLinkerInputs, OI.LinkAction); if (TC.getTriple().getObjectFormat() == llvm::Triple::ELF) { // On ELF platforms there's no built in autolinking mechanism, so we // pull the info we need from the .o files directly and pass them as an // argument input file to the linker. - Action *AutolinkExtractAction = + auto *AutolinkExtractAction = new AutolinkExtractJobAction(AllLinkerInputs); // Takes the same inputs as the linker, but doesn't own them. AutolinkExtractAction->setOwnsInputs(false); @@ -1311,7 +1321,7 @@ void Driver::buildActions(const ToolChain &TC, if (MergeModuleAction) { if (OI.DebugInfoKind == IRGenDebugInfoKind::Normal) { if (TC.getTriple().getObjectFormat() == llvm::Triple::ELF) { - Action *ModuleWrapAction = + auto *ModuleWrapAction = new ModuleWrapJobAction(MergeModuleAction.release()); LinkAction->addInput(ModuleWrapAction); } else @@ -1322,7 +1332,7 @@ void Driver::buildActions(const ToolChain &TC, Actions.push_back(LinkAction); if (TC.getTriple().isOSDarwin() && OI.DebugInfoKind > IRGenDebugInfoKind::None) { - Action *dSYMAction = new GenerateDSYMJobAction(LinkAction); + auto *dSYMAction = new GenerateDSYMJobAction(LinkAction); dSYMAction->setOwnsInputs(false); Actions.push_back(dSYMAction); } @@ -1381,7 +1391,8 @@ Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args) const { } void Driver::buildJobs(const ActionList &Actions, const OutputInfo &OI, - const OutputFileMap *OFM, Compilation &C) const { + const OutputFileMap *OFM, const ToolChain &TC, + Compilation &C) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); const DerivedArgList &Args = C.getArgs(); @@ -1403,7 +1414,7 @@ void Driver::buildJobs(const ActionList &Actions, const OutputInfo &OI, // outputs which are produced before the llvm passes (e.g. emit-sil). if (OI.isMultiThreading() && isa(A) && types::isAfterLLVM(A->getType())) { - NumOutputs += A->size(); + NumOutputs += cast(A)->size(); } else { ++NumOutputs; } @@ -1418,8 +1429,8 @@ void Driver::buildJobs(const ActionList &Actions, const OutputInfo &OI, } for (const Action *A : Actions) { - (void)buildJobsForAction(C, A, OI, OFM, C.getDefaultToolChain(), true, - JobCache); + (void)buildJobsForAction(C, cast(A), OI, OFM, TC, + /*TopLevel*/true, JobCache); } } @@ -1616,16 +1627,13 @@ handleCompileJobCondition(Job *J, CompileJobAction::InputInfo inputInfo, J->setCondition(condition); } -Job *Driver::buildJobsForAction(Compilation &C, const Action *A, +Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, const OutputInfo &OI, const OutputFileMap *OFM, const ToolChain &TC, bool AtTopLevel, JobCacheMap &JobCache) const { - assert(!isa(A) && "unexpected unprocessed input"); - const auto *JA = cast(A); - // 1. See if we've already got this cached. - std::pair Key(A, &TC); + std::pair Key(JA, &TC); { auto CacheIter = JobCache.find(Key); if (CacheIter != JobCache.end()) { @@ -1636,13 +1644,12 @@ Job *Driver::buildJobsForAction(Compilation &C, const Action *A, // 2. Build up the list of input jobs. ActionList InputActions; SmallVector InputJobs; - for (Action *Input : *A) { - if (isa(Input)) { - InputActions.push_back(Input); + for (Action *Input : *JA) { + if (auto *InputJobAction = dyn_cast(Input)) { + InputJobs.push_back(buildJobsForAction(C, InputJobAction, OI, OFM, + TC, false, JobCache)); } else { - InputJobs.push_back(buildJobsForAction(C, Input, OI, OFM, - C.getDefaultToolChain(), false, - JobCache)); + InputActions.push_back(Input); } } @@ -1849,33 +1856,21 @@ Job *Driver::buildJobsForAction(Compilation &C, const Action *A, // Put the header next to the primary output file. // FIXME: That's not correct if the user /just/ passed -emit-header // and not -emit-module. - llvm::SmallString<128> Path; - if (Output->getPrimaryOutputType() != types::TY_Nothing) - Path = Output->getPrimaryOutputFilenames()[0]; - else if (!Output->getBaseInput(0).empty()) - Path = llvm::sys::path::stem(Output->getBaseInput(0)); - else - Path = OI.ModuleName; - - bool isTempFile = C.isTemporaryFile(Path); - llvm::sys::path::replace_extension(Path, "h"); - Output->setAdditionalOutputForType(types::TY_ObjCHeader, Path); - if (isTempFile) - C.addTemporaryFile(Path); + addAuxiliaryOutput(C, *Output, types::TY_ObjCHeader, OI, + /*output file map*/nullptr); } } // 4. Construct a Job which produces the right CommandOutput. - std::unique_ptr ownedJob = TC.constructJob(*JA, std::move(InputJobs), - std::move(Output), - InputActions, C.getArgs(), - OI); + std::unique_ptr ownedJob = TC.constructJob(*JA, C, std::move(InputJobs), + InputActions, + std::move(Output), OI); Job *J = C.addJob(std::move(ownedJob)); // If we track dependencies for this job, we may be able to avoid running it. if (!J->getOutput().getAdditionalOutputForType(types::TY_SwiftDeps).empty()) { if (InputActions.size() == 1) { - auto compileJob = cast(A); + auto compileJob = cast(JA); bool alwaysRebuildDependents = C.getArgs().hasArg(options::OPT_driver_always_rebuild_dependents); handleCompileJobCondition(J, compileJob->getInputInfo(), BaseInput, @@ -1963,12 +1958,9 @@ static unsigned printActions(const Action *A, os << "\"" << IA->getInputArg().getValue() << "\""; } else { os << "{"; - for (auto it = A->begin(), ie = A->end(); it != ie;) { - os << printActions(*it, Ids); - ++it; - if (it != ie) - os << ", "; - } + interleave(*cast(A), + [&](const Action *Input) { os << printActions(Input, Ids); }, + [&] { os << ", "; }); os << "}"; } @@ -2019,7 +2011,24 @@ void Driver::printHelp(bool ShowHidden) const { } static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple) { - return llvm::Triple(DefaultTargetTriple); + llvm::Triple triple = llvm::Triple(DefaultTargetTriple); + + // armv6l and armv7l (which come from linux) are mapped to armv6 and + // armv7 (respectively) within llvm. When a Triple is created by llvm, + // the string is preserved, which keeps the 'l'. This extra character + // causes problems later down the line. + // By explicitly setting the architecture to the subtype that it aliases to, + // we remove that extra character while not introducing other side effects. + if (triple.getOS() == llvm::Triple::Linux) { + if (triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7) { + triple.setArchName("armv7"); + } + if (triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6) { + triple.setArchName("armv6"); + } + } + + return triple; } const ToolChain *Driver::getToolChain(const ArgList &Args) const { diff --git a/lib/Driver/FrontendUtil.cpp b/lib/Driver/FrontendUtil.cpp index 2964034f44539..d18e2c0266320 100644 --- a/lib/Driver/FrontendUtil.cpp +++ b/lib/Driver/FrontendUtil.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 3ea7b14d739ef..9e6a8c242be3a 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/OutputFileMap.cpp b/lib/Driver/OutputFileMap.cpp index 104be1d29c541..3906f74fe7bee 100644 --- a/lib/Driver/OutputFileMap.cpp +++ b/lib/Driver/OutputFileMap.cpp @@ -1,8 +1,8 @@ -//===-- OutputFileMap.cpp - Driver output file map -------------*- C++ -*--===// +//===--- OutputFileMap.cpp - Driver output file map -----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/ParseableOutput.cpp b/lib/Driver/ParseableOutput.cpp index a27ef83503d94..e4279b98e38bc 100644 --- a/lib/Driver/ParseableOutput.cpp +++ b/lib/Driver/ParseableOutput.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 0a7f5b107f206..ba38db7ddb4f2 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,7 +18,7 @@ //===----------------------------------------------------------------------===// #include "swift/Driver/ToolChain.h" - +#include "swift/Driver/Compilation.h" #include "swift/Driver/Driver.h" #include "swift/Driver/Job.h" #include "llvm/Option/ArgList.h" @@ -33,14 +33,46 @@ using namespace llvm::opt; const char * const ToolChain::SWIFT_EXECUTABLE_NAME; +ToolChain::JobContext::JobContext(Compilation &C, + ArrayRef Inputs, + ArrayRef InputActions, + const CommandOutput &Output, + const OutputInfo &OI) + : C(C), Inputs(Inputs), InputActions(InputActions), Output(Output), + OI(OI), Args(C.getArgs()) {} + +ArrayRef ToolChain::JobContext::getTopLevelInputFiles() const { + return C.getInputFiles(); +} +const char *ToolChain::JobContext::getAllSourcesPath() const { + return C.getAllSourcesPath(); +} + +const char * +ToolChain::JobContext::getTemporaryFilePath(const llvm::Twine &name, + StringRef suffix) const { + SmallString<128> buffer; + std::error_code EC = + llvm::sys::fs::createTemporaryFile(name, suffix, buffer); + if (EC) { + // FIXME: This should not take down the entire process. + llvm::report_fatal_error("unable to create temporary file for filelist"); + } + + C.addTemporaryFile(buffer.str()); + // We can't just reference the data in the TemporaryFiles vector because + // that could theoretically get copied to a new address. + return C.getArgs().MakeArgString(buffer.str()); +} + std::unique_ptr ToolChain::constructJob(const JobAction &JA, + Compilation &C, SmallVectorImpl &&inputs, - std::unique_ptr output, const ActionList &inputActions, - const llvm::opt::ArgList &args, + std::unique_ptr output, const OutputInfo &OI) const { - JobContext context{inputs, *output, inputActions, args, OI}; + JobContext context{C, inputs, inputActions, *output, OI}; auto invocationInfo = [&]() -> InvocationInfo { switch (JA.getKind()) { @@ -69,12 +101,12 @@ ToolChain::constructJob(const JobAction &JA, std::string relativePath = findProgramRelativeToSwift(invocationInfo.ExecutableName); if (!relativePath.empty()) { - executablePath = args.MakeArgString(relativePath); + executablePath = C.getArgs().MakeArgString(relativePath); } else { auto systemPath = llvm::sys::findProgramByName(invocationInfo.ExecutableName); if (systemPath) { - executablePath = args.MakeArgString(systemPath.get()); + executablePath = C.getArgs().MakeArgString(systemPath.get()); } else { // For debugging purposes. executablePath = invocationInfo.ExecutableName; @@ -85,7 +117,8 @@ ToolChain::constructJob(const JobAction &JA, return llvm::make_unique(JA, std::move(inputs), std::move(output), executablePath, std::move(invocationInfo.Arguments), - std::move(invocationInfo.ExtraEnvironment)); + std::move(invocationInfo.ExtraEnvironment), + std::move(invocationInfo.FilelistInfo)); } std::string diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 712ea6581652e..ef09cc36e273f 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1,8 +1,8 @@ -//===--- ToolChains.cpp - Job invocations (general and per-plaftorm) ------===// +//===--- ToolChains.cpp - Job invocations (general and per-platform) ------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -39,6 +39,8 @@ using namespace llvm::opt; /// The name of the Swift migrator binary. static const char * const SWIFT_UPDATE_NAME = "swift-update"; +/// The limit for passing a list of files on the command line. +static const size_t TOO_MANY_FILES = 128; static void addInputsOfType(ArgStringList &Arguments, ArrayRef Inputs, @@ -124,8 +126,10 @@ static void addCommonFrontendArgs(const ToolChain &TC, inputArgs.AddLastArg(arguments, options::OPT_parse_stdlib); inputArgs.AddLastArg(arguments, options::OPT_resource_dir); inputArgs.AddLastArg(arguments, options::OPT_solver_memory_threshold); + inputArgs.AddLastArg(arguments, options::OPT_suppress_warnings); inputArgs.AddLastArg(arguments, options::OPT_profile_generate); inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping); + inputArgs.AddLastArg(arguments, options::OPT_warnings_as_errors); // Pass on any build config options inputArgs.AddAllArgs(arguments, options::OPT_D); @@ -152,9 +156,12 @@ static void addCommonFrontendArgs(const ToolChain &TC, ToolChain::InvocationInfo ToolChain::constructInvocation(const CompileJobAction &job, const JobContext &context) const { - ArgStringList Arguments; + InvocationInfo II{SWIFT_EXECUTABLE_NAME}; + ArgStringList &Arguments = II.Arguments; - if (context.OI.CompilerMode != OutputInfo::Mode::UpdateCode) + if (context.OI.CompilerMode == OutputInfo::Mode::UpdateCode) + II.ExecutableName = SWIFT_UPDATE_NAME; + else Arguments.push_back("-frontend"); // Determine the frontend mode option. @@ -242,23 +249,39 @@ ToolChain::constructInvocation(const CompileJobAction &job, auto *IA = cast(context.InputActions[0]); const Arg &PrimaryInputArg = IA->getInputArg(); - bool FoundPrimaryInput = false; - - for (auto *A : make_range(context.Args.filtered_begin(options::OPT_INPUT), - context.Args.filtered_end())) { - // See if this input should be passed with -primary-file. - // FIXME: This will pick up non-source inputs too, like .o files. - if (!FoundPrimaryInput && PrimaryInputArg.getIndex() == A->getIndex()) { - Arguments.push_back("-primary-file"); - FoundPrimaryInput = true; + + if (context.Args.hasArg(options::OPT_driver_use_filelists) || + context.getTopLevelInputFiles().size() > TOO_MANY_FILES) { + Arguments.push_back("-filelist"); + Arguments.push_back(context.getAllSourcesPath()); + Arguments.push_back("-primary-file"); + PrimaryInputArg.render(context.Args, Arguments); + } else { + bool FoundPrimaryInput = false; + for (auto inputPair : context.getTopLevelInputFiles()) { + if (!types::isPartOfSwiftCompilation(inputPair.first)) + continue; + + // See if this input should be passed with -primary-file. + if (!FoundPrimaryInput && + PrimaryInputArg.getIndex() == inputPair.second->getIndex()) { + Arguments.push_back("-primary-file"); + FoundPrimaryInput = true; + } + Arguments.push_back(inputPair.second->getValue()); } - Arguments.push_back(A->getValue()); } break; } case OutputInfo::Mode::SingleCompile: { - for (const Action *A : context.InputActions) { - cast(A)->getInputArg().render(context.Args, Arguments); + if (context.Args.hasArg(options::OPT_driver_use_filelists) || + context.InputActions.size() > TOO_MANY_FILES) { + Arguments.push_back("-filelist"); + Arguments.push_back(context.getAllSourcesPath()); + } else { + for (const Action *A : context.InputActions) { + cast(A)->getInputArg().render(context.Args, Arguments); + } } break; } @@ -340,20 +363,25 @@ ToolChain::constructInvocation(const CompileJobAction &job, // Add the output file argument if necessary. if (context.Output.getPrimaryOutputType() != types::TY_Nothing) { - for (auto &FileName : context.Output.getPrimaryOutputFilenames()) { - Arguments.push_back("-o"); - Arguments.push_back(FileName.c_str()); + if (context.Args.hasArg(options::OPT_driver_use_filelists) || + context.Output.getPrimaryOutputFilenames().size() > TOO_MANY_FILES) { + Arguments.push_back("-output-filelist"); + Arguments.push_back(context.getTemporaryFilePath("outputs", "")); + II.FilelistInfo = {Arguments.back(), + context.Output.getPrimaryOutputType(), + FilelistInfo::Output}; + } else { + for (auto &FileName : context.Output.getPrimaryOutputFilenames()) { + Arguments.push_back("-o"); + Arguments.push_back(FileName.c_str()); + } } } if (context.Args.hasArg(options::OPT_embed_bitcode_marker)) Arguments.push_back("-embed-bitcode-marker"); - auto program = SWIFT_EXECUTABLE_NAME; - if (context.OI.CompilerMode == OutputInfo::Mode::UpdateCode) - program = SWIFT_UPDATE_NAME; - - return {program, Arguments}; + return II; } ToolChain::InvocationInfo @@ -530,24 +558,37 @@ ToolChain::constructInvocation(const BackendJobAction &job, ToolChain::InvocationInfo ToolChain::constructInvocation(const MergeModuleJobAction &job, const JobContext &context) const { - ArgStringList Arguments; + InvocationInfo II{SWIFT_EXECUTABLE_NAME}; + ArgStringList &Arguments = II.Arguments; - if (context.OI.CompilerMode != OutputInfo::Mode::UpdateCode) + if (context.OI.CompilerMode == OutputInfo::Mode::UpdateCode) + II.ExecutableName = SWIFT_UPDATE_NAME; + else Arguments.push_back("-frontend"); // We just want to emit a module, so pass -emit-module without any other // mode options. Arguments.push_back("-emit-module"); - size_t origLen = Arguments.size(); - (void)origLen; - addInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); - addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile); - assert(Arguments.size() - origLen >= - context.Inputs.size() + context.InputActions.size()); - assert((Arguments.size() - origLen == context.Inputs.size() || - !context.InputActions.empty()) && - "every input to MergeModule must generate a swiftmodule"); + if (context.Args.hasArg(options::OPT_driver_use_filelists) || + context.Inputs.size() > TOO_MANY_FILES) { + Arguments.push_back("-filelist"); + Arguments.push_back(context.getTemporaryFilePath("inputs", "")); + II.FilelistInfo = {Arguments.back(), types::TY_SwiftModuleFile, + FilelistInfo::Input}; + + addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile); + } else { + size_t origLen = Arguments.size(); + (void)origLen; + addInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); + addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile); + assert(Arguments.size() - origLen >= + context.Inputs.size() + context.InputActions.size()); + assert((Arguments.size() - origLen == context.Inputs.size() || + !context.InputActions.empty()) && + "every input to MergeModule must generate a swiftmodule"); + } // Tell all files to parse as library, which is necessary to load them as // serialized ASTs. @@ -573,11 +614,7 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job, Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); - auto program = SWIFT_EXECUTABLE_NAME; - if (context.OI.CompilerMode == OutputInfo::Mode::UpdateCode) - program = SWIFT_UPDATE_NAME; - - return {program, Arguments}; + return II; } ToolChain::InvocationInfo @@ -819,8 +856,18 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, const Driver &D = getDriver(); const llvm::Triple &Triple = getTriple(); - ArgStringList Arguments; - addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); + InvocationInfo II{"ld"}; + ArgStringList &Arguments = II.Arguments; + + if (context.Args.hasArg(options::OPT_driver_use_filelists) || + context.Inputs.size() > TOO_MANY_FILES) { + Arguments.push_back("-filelist"); + Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList")); + II.FilelistInfo = {Arguments.back(), types::TY_Object, FilelistInfo::Input}; + } else { + addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); + } + addInputsOfType(Arguments, context.InputActions, types::TY_Object); if (context.OI.DebugInfoKind == IRGenDebugInfoKind::Normal) { @@ -933,7 +980,7 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile(RuntimeLibPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name - llvm::sys::path::append(LibProfile, "clang", CLANG_VERSION_STRING); + llvm::sys::path::append(LibProfile, "clang", "lib", "darwin"); StringRef RT; if (Triple.isiOS()) { @@ -941,13 +988,28 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, RT = "tvos"; else RT = "ios"; - } - else if (Triple.isWatchOS()) + } else if (Triple.isWatchOS()) { RT = "watchos"; - else + } else { + assert(Triple.isMacOSX()); RT = "osx"; - llvm::sys::path::append(LibProfile, "lib", "darwin", - "libclang_rt.profile_" + RT + ".a"); + } + + StringRef Sim; + if (tripleIsAnySimulator(Triple)) { + Sim = "sim"; + } + + llvm::sys::path::append(LibProfile, + "libclang_rt.profile_" + RT + Sim + ".a"); + + // FIXME: Continue accepting the old path for simulator libraries for now. + if (!Sim.empty() && !llvm::sys::fs::exists(LibProfile)) { + llvm::sys::path::remove_filename(LibProfile); + llvm::sys::path::append(LibProfile, + "libclang_rt.profile_" + RT + ".a"); + } + Arguments.push_back(context.Args.MakeArgString(LibProfile)); } @@ -995,7 +1057,7 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); - return {"ld", Arguments}; + return II; } ToolChain::InvocationInfo @@ -1047,6 +1109,12 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); + if (getTriple().getOS() == llvm::Triple::Linux) { + if (getTriple().getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7 || + getTriple().getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6) { + Arguments.push_back("-Wl,-Bsymbolic"); + } + } break; } @@ -1082,12 +1150,14 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); + Arguments.push_back(context.Args.MakeArgString("--target=" + getTriple().str())); + if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile(RuntimeLibPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name - llvm::sys::path::append(LibProfile, "clang", CLANG_VERSION_STRING); + llvm::sys::path::append(LibProfile, "clang", "lib"); - llvm::sys::path::append(LibProfile, "lib", getTriple().getOSName(), + llvm::sys::path::append(LibProfile, getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".a"); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 7bc32e8f48452..af186282c1e83 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 03e737cc903e9..1273bb3ff0eed 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -123,3 +123,33 @@ bool types::isAfterLLVM(ID Id) { llvm_unreachable("Invalid type ID."); } } + +bool types::isPartOfSwiftCompilation(ID Id) { + switch (Id) { + case types::TY_Swift: + case types::TY_SIL: + case types::TY_RawSIL: + case types::TY_SIB: + case types::TY_RawSIB: + return true; + case types::TY_Assembly: + case types::TY_LLVM_IR: + case types::TY_LLVM_BC: + case types::TY_Object: + case types::TY_Dependencies: + case types::TY_ObjCHeader: + case types::TY_AutolinkFile: + case types::TY_Image: + case types::TY_dSYM: + case types::TY_SwiftModuleFile: + case types::TY_SwiftModuleDocFile: + case types::TY_SerializedDiagnostics: + case types::TY_ClangModuleFile: + case types::TY_SwiftDeps: + case types::TY_Nothing: + case types::TY_Remapping: + return false; + case types::TY_INVALID: + llvm_unreachable("Invalid type ID."); + } +} diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0f6ece20c8a53..02444b6c7c7fe 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1,8 +1,8 @@ -//===-- CompilerInvocation.cpp - CompilerInvocation methods ---------------===// +//===--- CompilerInvocation.cpp - CompilerInvocation methods --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,6 +22,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/Path.h" using namespace swift; @@ -90,6 +91,34 @@ static void debugFailWithCrash() { LLVM_BUILTIN_TRAP; } +static unsigned readFileList(std::vector &inputFiles, + const llvm::opt::Arg *filelistPath, + const llvm::opt::Arg *primaryFileArg = nullptr) { + bool foundPrimaryFile = false; + unsigned primaryFileIndex = 0; + StringRef primaryFile; + if (primaryFileArg) + primaryFile = primaryFileArg->getValue(); + + llvm::ErrorOr> buffer = + llvm::MemoryBuffer::getFile(filelistPath->getValue()); + assert(buffer && "can't read filelist; unrecoverable"); + + for (StringRef line : make_range(llvm::line_iterator(*buffer.get()), {})) { + inputFiles.push_back(line); + if (foundPrimaryFile) + continue; + if (line == primaryFile) + foundPrimaryFile = true; + else + ++primaryFileIndex; + } + + if (primaryFileArg) + assert(foundPrimaryFile && "primary file not found in filelist"); + return primaryFileIndex; +} + static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticEngine &Diags) { using namespace options; @@ -120,10 +149,12 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.DelayedFunctionBodyParsing |= Args.hasArg(OPT_delayed_function_body_parsing); Opts.EnableTesting |= Args.hasArg(OPT_enable_testing); + Opts.EnableResilience |= Args.hasArg(OPT_enable_resilience); Opts.PrintStats |= Args.hasArg(OPT_print_stats); Opts.PrintClangStats |= Args.hasArg(OPT_print_clang_stats); Opts.DebugTimeFunctionBodies |= Args.hasArg(OPT_debug_time_function_bodies); + Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation); Opts.PlaygroundTransform |= Args.hasArg(OPT_playground); if (Args.hasArg(OPT_disable_playground_transform)) @@ -141,16 +172,25 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } } - for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT, - OPT_primary_file), - Args.filtered_end())) { - if (A->getOption().matches(OPT_INPUT)) { - Opts.InputFilenames.push_back(A->getValue()); - } else if (A->getOption().matches(OPT_primary_file)) { - Opts.PrimaryInput = SelectedInput(Opts.InputFilenames.size()); - Opts.InputFilenames.push_back(A->getValue()); - } else { - llvm_unreachable("Unknown input-related argument!"); + if (const Arg *A = Args.getLastArg(OPT_filelist)) { + const Arg *primaryFileArg = Args.getLastArg(OPT_primary_file); + auto primaryFileIndex = readFileList(Opts.InputFilenames, A, + primaryFileArg); + if (primaryFileArg) + Opts.PrimaryInput = SelectedInput(primaryFileIndex); + assert(!Args.hasArg(OPT_INPUT) && "mixing -filelist with inputs"); + } else { + for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT, + OPT_primary_file), + Args.filtered_end())) { + if (A->getOption().matches(OPT_INPUT)) { + Opts.InputFilenames.push_back(A->getValue()); + } else if (A->getOption().matches(OPT_primary_file)) { + Opts.PrimaryInput = SelectedInput(Opts.InputFilenames.size()); + Opts.InputFilenames.push_back(A->getValue()); + } else { + llvm_unreachable("Unknown input-related argument!"); + } } } @@ -289,7 +329,12 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, else Opts.InputKind = InputFileKind::IFK_Swift; - Opts.OutputFilenames = Args.getAllArgValues(OPT_o); + if (const Arg *A = Args.getLastArg(OPT_output_filelist)) { + readFileList(Opts.OutputFilenames, A); + assert(!Args.hasArg(OPT_o) && "don't use -o with -output-filelist"); + } else { + Opts.OutputFilenames = Args.getAllArgValues(OPT_o); + } bool UserSpecifiedModuleName = false; { @@ -661,16 +706,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableExperimentalPatterns |= Args.hasArg(OPT_enable_experimental_patterns); - Opts.DisableSelfTypeMangling |= - Args.hasArg(OPT_disable_self_type_mangling); - - Opts.EnableResilience = false; - if (auto A = Args.getLastArg(OPT_enable_resilience, - OPT_disable_resilience)) { - Opts.EnableResilience - = A->getOption().matches(OPT_enable_resilience); - } - Opts.DisableAvailabilityChecking |= Args.hasArg(OPT_disable_availability_checking); @@ -697,7 +732,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Opts.DebuggerSupport) Opts.EnableDollarIdentifiers = true; Opts.Playground |= Args.hasArg(OPT_playground); + Opts.Swift3Migration |= Args.hasArg(OPT_swift3_migration); Opts.WarnOmitNeedlessWords = Args.hasArg(OPT_warn_omit_needless_words); + Opts.OmitNeedlessWords |= Args.hasArg(OPT_enable_omit_needless_words); Opts.EnableThrowWithoutTry |= Args.hasArg(OPT_enable_throw_without_try); @@ -880,6 +917,11 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Args.hasArg(OPT_show_diagnostics_after_fatal); Opts.UseColor |= Args.hasArg(OPT_color_diagnostics); Opts.FixitCodeForAllDiagnostics |= Args.hasArg(OPT_fixit_all); + Opts.SuppressWarnings |= Args.hasArg(OPT_suppress_warnings); + Opts.WarningsAsErrors |= Args.hasArg(OPT_warnings_as_errors); + + assert(!(Opts.WarningsAsErrors && Opts.SuppressWarnings) && + "conflicting arguments; should of been caught by driver"); return false; } @@ -999,8 +1041,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate); Opts.EmitProfileCoverageMapping |= Args.hasArg(OPT_profile_coverage_mapping); - Opts.UseNativeSuperMethod |= - Args.hasArg(OPT_use_native_super_method); + Opts.EnableGuaranteedClosureContexts |= + Args.hasArg(OPT_enable_guaranteed_closure_contexts); return false; } @@ -1079,6 +1121,13 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.LinkLibraries.push_back(LinkLibrary(A->getValue(), Kind)); } + if (auto valueNames = Args.getLastArg(OPT_disable_llvm_value_names, + OPT_enable_llvm_value_names)) { + Opts.HasValueNamesSetting = true; + Opts.ValueNames = + valueNames->getOption().matches(OPT_enable_llvm_value_names); + } + Opts.DisableLLVMOptzns |= Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableLLVMARCOpts |= Args.hasArg(OPT_disable_llvm_arc_opts); Opts.DisableLLVMSLPVectorizer |= Args.hasArg(OPT_disable_llvm_slp_vectorizer); @@ -1155,8 +1204,14 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, } } - Opts.ForceResilientSuperDispatch |= - Args.hasArg(OPT_force_resilient_super_dispatch); + if (Args.hasArg(OPT_strip_field_names)) { + Opts.StripFieldNames = true; + } + + if (Args.hasArg(OPT_strip_field_metadata)) { + Opts.StripFieldMetadata = true; + Opts.StripFieldNames = true; + } return false; } diff --git a/lib/Frontend/DiagnosticVerifier.cpp b/lib/Frontend/DiagnosticVerifier.cpp index 806530ff4b818..4c7155fe5f024 100644 --- a/lib/Frontend/DiagnosticVerifier.cpp +++ b/lib/Frontend/DiagnosticVerifier.cpp @@ -1,8 +1,8 @@ -//===- DiagnosticVerifier.cpp - Diagnostic Verifier (-verify) -------------===// +//===--- DiagnosticVerifier.cpp - Diagnostic Verifier (-verify) -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -39,6 +39,10 @@ namespace { // This is true if a '*' constraint is present to say that the diagnostic // may appear (or not) an uncounted number of times. bool mayAppear = false; + + // This is true if a '{{none}}' is present to mark that there should be no + // fixits at all. + bool noFixitsMayAppear = false; // This is the raw input buffer for the message text, the part in the // {{...}} @@ -358,6 +362,12 @@ bool DiagnosticVerifier::verifyFile(unsigned BufferID, // Prepare for the next round of checks. ExtraChecks = ExtraChecks.substr(EndLoc+2).ltrim(); + // Special case for specifying no fixits should appear. + if (FixItStr == "none") { + Expected.noFixitsMayAppear = true; + continue; + } + // Parse the pieces of the fix-it. size_t MinusLoc = FixItStr.find('-'); if (MinusLoc == StringRef::npos) { @@ -467,20 +477,17 @@ bool DiagnosticVerifier::verifyFile(unsigned BufferID, llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(IncorrectFixit, "expected fix-it not seen; actual fix-its: " + actual, fix); -#if 0 // TODO: There are still some bugs with this, and we don't have a - // policy of requiring a fixit specification on tests. - } else if (expected.Fixits.empty() && + } else if (expected.noFixitsMayAppear && !FoundDiagnostic.getFixIts().empty() && - !expected.mayAppear && - false) { + !expected.mayAppear) { // If there was no fixit specification, but some were produced, add a // fixit to add them in. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); - - llvm::SMFixIt fix(SMLoc::getFromPointer(expected.ExpectedEnd), - " " + actual); - addError(expected.ExpectedEnd, "expected fix-it not specified", fix); -#endif + auto replStartLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 8); // {{none}} length + auto replEndLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 1); + + llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); + addError(replStartLoc.getPointer(), "expected no fix-its; actual fix-it seen: " + actual, fix); } // Actually remove the diagnostic from the list, so we don't match it @@ -617,7 +624,7 @@ bool DiagnosticVerifier::verifyFile(unsigned BufferID, /// file and drop it back in place. void DiagnosticVerifier::autoApplyFixes(unsigned BufferID, ArrayRef diags) { - // Walk the list of diagnostics, pulling out any fixits into a array of just + // Walk the list of diagnostics, pulling out any fixits into an array of just // them. SmallVector FixIts; for (auto &diag : diags) diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 66a7a0e3bb966..8514add940dac 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1,8 +1,8 @@ -//===-- Frontend.cpp - frontend utility methods ---------------------------===// +//===--- Frontend.cpp - frontend utility methods --------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -69,6 +69,12 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) { if (Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) { Diagnostics.setShowDiagnosticsAfterFatalError(); } + if (Invocation.getDiagnosticOptions().SuppressWarnings) { + Diagnostics.setSuppressWarnings(true); + } + if (Invocation.getDiagnosticOptions().WarningsAsErrors) { + Diagnostics.setWarningsAsErrors(true); + } // If we are asked to emit a module documentation file, configure lexing and // parsing to remember comments. @@ -81,7 +87,10 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) { if (Invocation.getFrontendOptions().EnableSourceImport) { bool immediate = Invocation.getFrontendOptions().actionIsImmediate(); - Context->addModuleLoader(SourceLoader::create(*Context, !immediate, + bool enableResilience = Invocation.getFrontendOptions().EnableResilience; + Context->addModuleLoader(SourceLoader::create(*Context, + !immediate, + enableResilience, DepTracker)); } @@ -220,6 +229,8 @@ Module *CompilerInstance::getMainModule() { MainModule = Module::create(ID, *Context); if (Invocation.getFrontendOptions().EnableTesting) MainModule->setTestingEnabled(); + if (Invocation.getFrontendOptions().EnableResilience) + MainModule->setResilienceEnabled(); } return MainModule; } diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 73e80ab4f55d2..c6bf4586a5f94 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Frontend/PrintingDiagnosticConsumer.cpp b/lib/Frontend/PrintingDiagnosticConsumer.cpp index 9e9e71f2e80d3..f60e964b46417 100644 --- a/lib/Frontend/PrintingDiagnosticConsumer.cpp +++ b/lib/Frontend/PrintingDiagnosticConsumer.cpp @@ -1,8 +1,8 @@ -//===- PrintingDiagnosticConsumer.cpp - Print Text Diagnostics ------------===// +//===--- PrintingDiagnosticConsumer.cpp - Print Text Diagnostics ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Frontend/SerializedDiagnosticConsumer.cpp b/lib/Frontend/SerializedDiagnosticConsumer.cpp index 9f14db26bb729..2f3f34d27f8cd 100644 --- a/lib/Frontend/SerializedDiagnosticConsumer.cpp +++ b/lib/Frontend/SerializedDiagnosticConsumer.cpp @@ -1,8 +1,8 @@ -//===- SerializedDiagnosticConsumer.cpp - Serialize Diagnostics --*- C++ -*-===// +//===--- SerializedDiagnosticConsumer.cpp - Serialize Diagnostics ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -411,7 +411,7 @@ void SerializedDiagnosticConsumer::emitBlockInfoBlock() { Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, diff --git a/lib/IDE/CMakeLists.txt b/lib/IDE/CMakeLists.txt index fed7014ba1695..18d4b42a2461b 100644 --- a/lib/IDE/CMakeLists.txt +++ b/lib/IDE/CMakeLists.txt @@ -8,6 +8,7 @@ add_swift_library(swiftIDE SyntaxModel.cpp Utils.cpp SwiftSourceDocInfo.cpp + ReconstructType.cpp LINK_LIBRARIES swiftFrontend swiftClangImporter diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index a9ccafbed2743..197443ac65a64 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1,8 +1,8 @@ -//===- CodeCompletion.cpp - Code completion implementation ----------------===// +//===--- CodeCompletion.cpp - Code completion implementation --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -75,7 +75,7 @@ StringRef getCommandName(CodeCompletionCommandKind Kind) { CHECK_CASE(recommended) CHECK_CASE(recommendedover) #undef CHECK_CASE - llvm_unreachable("Can not handle this Kind."); + llvm_unreachable("Cannot handle this Kind."); } bool containsInterestedWords(StringRef Content, StringRef Splitter, @@ -284,7 +284,9 @@ std::string swift::ide::removeCodeCompletionTokens( if (C == '#' && Ptr <= End - 2 && Ptr[1] == '^') { do { Ptr++; - } while(*Ptr != '#'); + } while (Ptr < End && *Ptr != '#'); + if (Ptr == End) + break; continue; } CleanFile += C; @@ -326,7 +328,7 @@ static Stmt *findNearestStmt(const AbstractFunctionDecl *AFD, SourceLoc Loc, auto &SM = AFD->getASTContext().SourceMgr; assert(SM.rangeContainsTokenLoc(AFD->getSourceRange(), Loc)); StmtFinder Finder(SM, Loc, Kind); - // FIXME(thread-safety): the walker is is mutating the AST. + // FIXME(thread-safety): the walker is mutating the AST. const_cast(AFD)->walk(Finder); return Finder.getFoundStmt(); } @@ -443,8 +445,9 @@ CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) { case DeclKind::Module: return CodeCompletionDeclKind::Module; case DeclKind::TypeAlias: - case DeclKind::AssociatedType: return CodeCompletionDeclKind::TypeAlias; + case DeclKind::AssociatedType: + return CodeCompletionDeclKind::AssociatedType; case DeclKind::GenericTypeParam: return CodeCompletionDeclKind::GenericTypeParam; case DeclKind::Enum: @@ -536,6 +539,9 @@ void CodeCompletionResult::print(raw_ostream &OS) const { case CodeCompletionDeclKind::TypeAlias: Prefix.append("[TypeAlias]"); break; + case CodeCompletionDeclKind::AssociatedType: + Prefix.append("[AssociatedType]"); + break; case CodeCompletionDeclKind::GenericTypeParam: Prefix.append("[GenericTypeParam]"); break; @@ -1232,6 +1238,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeCallArg(CallExpr *E) override; void completeReturnStmt(CodeCompletionExpr *E) override; void completeAfterPound(CodeCompletionExpr *E, StmtKind ParentKind) override; + void completeGenericParams(TypeLoc TL) override; void addKeywords(CodeCompletionResultSink &Sink); void doneParsing() override; @@ -1258,7 +1265,7 @@ ArchetypeTransformer::ArchetypeTransformer(DeclContext *DC, Type Ty) : if (!D) return; SmallVector Scrach; - auto Params = D->getGenericParamTypes(); + auto Params = D->getInnermostGenericParamTypes(); auto Args = BaseTy->getAllGenericArgs(Scrach); assert(Params.size() == Args.size()); for (unsigned I = 0, N = Params.size(); I < N; I ++) { @@ -1326,6 +1333,7 @@ static bool isTopLevelContext(const DeclContext *DC) { case DeclContextKind::TopLevelCodeDecl: return true; case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: return false; default: continue; @@ -1584,7 +1592,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addImportModuleNames() { // FIXME: Add user-defined swift modules SmallVector Modules; - Ctx.getVisibleTopLevelClangeModules(Modules); + Ctx.getVisibleTopLevelClangModules(Modules); std::sort(Modules.begin(), Modules.end(), [](clang::Module* LHS , clang::Module* RHS) { return LHS->getTopLevelModuleName().compare_lower( @@ -1735,7 +1743,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } auto ItAndInserted = DeducedAssociatedTypeCache.insert({ NTD, Types }); - assert(ItAndInserted.second == true && "should not be in the map"); + assert(ItAndInserted.second && "should not be in the map"); return ItAndInserted.first->second; } @@ -1769,7 +1777,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { assert(VD->isStatic() || !(InsideStaticMethod && VD->getDeclContext() == CurrentMethod->getDeclContext()) && - "name lookup bug -- can not see an instance variable " + "name lookup bug -- cannot see an instance variable " "in a static function"); CommandWordsPairs Pairs; @@ -1796,31 +1804,21 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { addTypeAnnotation(Builder, VarType); } - void addPatternParameters(CodeCompletionResultBuilder &Builder, - const Pattern *P) { - if (auto *TP = dyn_cast(P)) { - bool NeedComma = false; - for (unsigned i = 0, end = TP->getNumElements(); i < end; ++i) { - TuplePatternElt TupleElt = TP->getElement(i); - if (NeedComma) - Builder.addComma(); - NeedComma = true; + void addParameters(CodeCompletionResultBuilder &Builder, + const ParameterList *params) { + bool NeedComma = false; + for (auto ¶m : *params) { + if (NeedComma) + Builder.addComma(); + NeedComma = true; - bool HasEllipsis = TupleElt.hasEllipsis(); - Type EltT = TupleElt.getPattern()->getType(); - if (HasEllipsis) - EltT = TupleTypeElt::getVarargBaseTy(EltT); + Type type = param->getType(); + if (param->isVariadic()) + type = ParamDecl::getVarargBaseTy(type); - Builder.addCallParameter(TupleElt.getPattern()->getBoundName(), - EltT, HasEllipsis); - } - return; + Builder.addCallParameter(param->getArgumentName(), type, + param->isVariadic()); } - - Type PType = P->getType(); - if (auto Parens = dyn_cast(PType.getPointer())) - PType = Parens->getUnderlyingType(); - Builder.addCallParameter(P->getBoundName(), PType, /*IsVarArg*/false); } void addPatternFromTypeImpl(CodeCompletionResultBuilder &Builder, Type T, @@ -1894,17 +1892,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { const AbstractFunctionDecl *AFD, bool includeDefaultArgs = true) { - const TuplePattern *BodyTuple = nullptr; - if (AFD) { - auto BodyPatterns = AFD->getBodyParamPatterns(); - // Skip over the implicit 'self'. - if (AFD->getImplicitSelfDecl()) { - BodyPatterns = BodyPatterns.slice(1); - } - - if (!BodyPatterns.empty()) - BodyTuple = dyn_cast(BodyPatterns.front()); - } + const ParameterList *BodyParams = nullptr; + if (AFD) + BodyParams = AFD->getParameterList(AFD->getImplicitSelfDecl() ? 1 : 0); bool modifiedBuilder = false; @@ -1921,6 +1911,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { case DefaultArgumentKind::Normal: case DefaultArgumentKind::Inherited: + case DefaultArgumentKind::Nil: + case DefaultArgumentKind::EmptyArray: + case DefaultArgumentKind::EmptyDictionary: if (includeDefaultArgs) break; continue; @@ -1941,11 +1934,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (NeedComma) Builder.addComma(); - if (BodyTuple) { + if (BodyParams) { // If we have a local name for the parameter, pass in that as well. - auto ParamPat = BodyTuple->getElement(i).getPattern(); - Builder.addCallParameter(Name, ParamPat->getBodyName(), ParamType, - TupleElt.isVararg()); + auto name = BodyParams->get(i)->getName(); + Builder.addCallParameter(Name, name, ParamType, TupleElt.isVararg()); } else { Builder.addCallParameter(Name, ParamType, TupleElt.isVararg()); } @@ -1961,9 +1953,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } modifiedBuilder = true; - if (BodyTuple) { - auto ParamPat = BodyTuple->getElement(0).getPattern(); - Builder.addCallParameter(Identifier(), ParamPat->getBodyName(), T, + if (BodyParams) { + auto name = BodyParams->get(0)->getName(); + Builder.addCallParameter(Identifier(), name, T, /*IsVarArg*/false); } else Builder.addCallParameter(Identifier(), T, /*IsVarArg*/false); @@ -1994,6 +1986,21 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Builder.addRightParen(); } + void addPoundSelector() { + // #selector is only available when the Objective-C runtime is. + if (!Ctx.LangOpts.EnableObjCInterop) return; + + CodeCompletionResultBuilder Builder( + Sink, + CodeCompletionResult::ResultKind::Keyword, + SemanticContextKind::ExpressionSpecific, + ExpectedTypes); + Builder.addTextChunk("selector"); + Builder.addLeftParen(); + Builder.addSimpleTypedParameter("@objc method", /*isVarArg=*/false); + Builder.addRightParen(); + } + void addFunctionCallPattern(const AnyFunctionType *AFT, const AbstractFunctionDecl *AFD = nullptr) { foundFunction(AFT); @@ -2057,7 +2064,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { case LookupKind::EnumElement: case LookupKind::Type: case LookupKind::TypeInDeclContext: - llvm_unreachable("can not have a method call while doing a " + llvm_unreachable("cannot have a method call while doing a " "type completion"); case LookupKind::ImportFromModule: IsImplicitlyCurriedInstanceMethod = false; @@ -2122,7 +2129,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // Build type annotation. { llvm::raw_svector_ostream OS(TypeStr); - for (unsigned i = FirstIndex + 1, e = FD->getBodyParamPatterns().size(); + for (unsigned i = FirstIndex + 1, e = FD->getParameterLists().size(); i != e; ++i) { ResultType->castTo()->getInput()->print(OS); ResultType = ResultType->castTo()->getResult(); @@ -2245,7 +2252,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } void addSubscriptCall(const SubscriptDecl *SD, DeclVisibilityKind Reason) { - assert(!HaveDot && "can not add a subscript after a dot"); + assert(!HaveDot && "cannot add a subscript after a dot"); CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, @@ -2254,7 +2261,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Builder.setAssociatedDecl(SD); setClangDeclKeywords(SD, Pairs, Builder); Builder.addLeftBracket(); - addPatternParameters(Builder, SD->getIndices()); + addParameters(Builder, SD->getIndices()); Builder.addRightBracket(); // Add a type annotation. @@ -2436,7 +2443,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (HaveDot) return; - // If instance type is type alias, showing users that the contructed + // If instance type is type alias, showing users that the constructed // type is the typealias instead of the underlying type of the alias. Optional Result = None; if (auto AT = MT->getInstanceType()) { @@ -2463,11 +2470,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } if (auto *FD = dyn_cast(D)) { - // We can not call operators with a postfix parenthesis syntax. + // We cannot call operators with a postfix parenthesis syntax. if (FD->isBinaryOperator() || FD->isUnaryOperator()) return; - // We can not call accessors. We use VarDecls and SubscriptDecls to + // We cannot call accessors. We use VarDecls and SubscriptDecls to // produce completions that refer to getters and setters. if (FD->isAccessor()) return; @@ -2525,11 +2532,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } if (auto *FD = dyn_cast(D)) { - // We can not call operators with a postfix parenthesis syntax. + // We cannot call operators with a postfix parenthesis syntax. if (FD->isBinaryOperator() || FD->isUnaryOperator()) return; - // We can not call accessors. We use VarDecls and SubscriptDecls to + // We cannot call accessors. We use VarDecls and SubscriptDecls to // produce completions that refer to getters and setters. if (FD->isAccessor()) return; @@ -2828,7 +2835,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // We allocate these expressions on the stack because we know they can't // escape and there isn't a better way to allocate scratch Expr nodes. UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::PostfixOperator, - expr->getSourceRange().End); + DeclNameLoc(expr->getSourceRange().End)); PostfixUnaryExpr opExpr(&UDRE, expr); Expr *tempExpr = &opExpr; @@ -2880,7 +2887,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // We allocate these expressions on the stack because we know they can't // escape and there isn't a better way to allocate scratch Expr nodes. UnresolvedDeclRefExpr UDRE(op->getName(), DeclRefKind::BinaryOperator, - SourceLoc()); + DeclNameLoc(SourceLoc())); sequence.drop_back(1).back() = &UDRE; CodeCompletionExpr CCE((SourceRange())); sequence.back() = &CCE; @@ -3265,10 +3272,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } } - static void collectArgumentExpection(unsigned Position, bool HasName, - ArrayRef Types, SourceLoc Loc, - std::vector &ExpectedTypes, - std::vector &ExpectedNames) { + static void collectArgumentExpectation(unsigned Position, bool HasName, + ArrayRef Types, SourceLoc Loc, + std::vector &ExpectedTypes, + std::vector &ExpectedNames) { SmallPtrSet seenTypes; SmallPtrSet seenNames; @@ -3298,8 +3305,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { ArrayRef Types, SourceLoc Loc) { std::vector ExpectedTypes; std::vector ExpectedNames; - collectArgumentExpection(Position, HasName, Types, Loc, ExpectedTypes, - ExpectedNames); + collectArgumentExpectation(Position, HasName, Types, Loc, ExpectedTypes, + ExpectedNames); addArgNameCompletionResults(ExpectedNames); if (!ExpectedTypes.empty()) { setExpectedTypes(ExpectedTypes); @@ -3311,7 +3318,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { static bool isPotentialSignatureMatch(ArrayRef TupleEles, ArrayRef ExprTypes, DeclContext *DC) { - // Not likely to be a mactch if users provide more arguments than expected. + // Not likely to be a match if users provide more arguments than expected. if (ExprTypes.size() >= TupleEles.size()) return false; for (unsigned I = 0; I < ExprTypes.size(); ++ I) { @@ -3376,16 +3383,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } static bool - collectArgumentExpectatation(DeclContext &DC, CallExpr *CallE, Expr *CCExpr, - std::vector &ExpectedTypes, - std::vector &ExpectedNames) { + collectArgumentExpectation(DeclContext &DC, CallExpr *CallE, Expr *CCExpr, + std::vector &ExpectedTypes, + std::vector &ExpectedNames) { SmallVector PossibleTypes; unsigned Position; bool HasName; if (collectPossibleArgTypes(DC, CallE, CCExpr, PossibleTypes, Position, HasName, true)) { - collectArgumentExpection(Position, HasName, PossibleTypes, - CCExpr->getStartLoc(), ExpectedTypes, ExpectedNames); + collectArgumentExpectation(Position, HasName, PossibleTypes, + CCExpr->getStartLoc(), ExpectedTypes, ExpectedNames); return !ExpectedTypes.empty() || !ExpectedNames.empty(); } return false; @@ -3669,7 +3676,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { if (FD->isBinaryOperator() || FD->isUnaryOperator()) return; - // We can not override individual accessors. + // We cannot override individual accessors. if (FD->isAccessor()) return; @@ -3943,6 +3950,12 @@ void CodeCompletionCallbacksImpl::completeAfterPound(CodeCompletionExpr *E, ParentStmtKind = ParentKind; } +void CodeCompletionCallbacksImpl::completeGenericParams(TypeLoc TL) { + CurDeclContext = P.CurDeclContext; + Kind = CompletionKind::GenericParams; + ParsedTypeLoc = TL; +} + void CodeCompletionCallbacksImpl::completeNominalMemberBeginning( SmallVectorImpl &Keywords) { assert(!InEnumElementRawValue); @@ -4065,6 +4078,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink) { case CompletionKind::UnresolvedMember: case CompletionKind::CallArg: case CompletionKind::AfterPound: + case CompletionKind::GenericParams: break; case CompletionKind::StmtOrExpr: @@ -4208,7 +4222,7 @@ class CodeCompletionTypeContextAnalyzer { case ExprKind::Call: { std::vector PotentialTypes; std::vector ExpectedNames; - CompletionLookup::collectArgumentExpectatation( + CompletionLookup::collectArgumentExpectation( *DC, cast(Parent), ParsedExpr, PotentialTypes, ExpectedNames); for (Type Ty : PotentialTypes) @@ -4578,6 +4592,18 @@ void CodeCompletionCallbacksImpl::doneParsing() { case CompletionKind::AfterPound: { Lookup.addPoundAvailable(ParentStmtKind); + Lookup.addPoundSelector(); + break; + } + + case CompletionKind::GenericParams: { + if (auto NM = ParsedTypeLoc.getType()->getAnyNominal()) { + if (auto Params = NM->getGenericParams()) { + for (auto GP : Params->getParams()) { + Lookup.addGenericTypeParamRef(GP, DeclVisibilityKind::GenericParameter); + } + } + } break; } } @@ -4747,6 +4773,7 @@ void swift::ide::copyCodeCompletionResults(CodeCompletionResultSink &targetSink, case CodeCompletionDeclKind::Enum: case CodeCompletionDeclKind::Protocol: case CodeCompletionDeclKind::TypeAlias: + case CodeCompletionDeclKind::AssociatedType: case CodeCompletionDeclKind::GenericTypeParam: return true; case CodeCompletionDeclKind::EnumElement: diff --git a/lib/IDE/CodeCompletionResultBuilder.h b/lib/IDE/CodeCompletionResultBuilder.h index b69793288a638..9b76dc1bfe3ae 100644 --- a/lib/IDE/CodeCompletionResultBuilder.h +++ b/lib/IDE/CodeCompletionResultBuilder.h @@ -1,8 +1,8 @@ -//===- CodeCompletionResultBuilder.h - Bulid completion results -----------===// +//===--- CodeCompletionResultBuilder.h - Build completion results ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -267,7 +267,7 @@ class CodeCompletionResultBuilder { void addSimpleNamedParameter(StringRef name) { CurrentNestingLevel++; addSimpleChunk(CodeCompletionString::Chunk::ChunkKind::CallParameterBegin); - // Use internal, since we don't want the name to be outisde the placeholder. + // Use internal, since we don't want the name to be outside the placeholder. addChunkWithText( CodeCompletionString::Chunk::ChunkKind::CallParameterInternalName, name); @@ -293,7 +293,7 @@ class CodeCompletionResultBuilder { if (!Name.empty()) { StringRef NameStr = Name.str(); - // 'self' is a keyword, we can not allow to insert it into the source + // 'self' is a keyword, we cannot allow to insert it into the source // buffer. bool IsAnnotation = (NameStr == "self"); diff --git a/lib/IDE/CommentConversion.cpp b/lib/IDE/CommentConversion.cpp index bcc7b595e937b..6004662eb9a2f 100644 --- a/lib/IDE/CommentConversion.cpp +++ b/lib/IDE/CommentConversion.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -100,7 +100,9 @@ struct CommentToXMLConverter { } void printCodeBlock(const CodeBlock *CB) { - OS << ""; + OS << "getLanguage()); + OS << "\">"; SmallVector CodeLines; CB->getLiteralContent().split(CodeLines, "\n"); for (auto Line : CodeLines) { diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp index e7f5190645721..ad764c54579cb 100644 --- a/lib/IDE/ModuleInterfacePrinting.cpp +++ b/lib/IDE/ModuleInterfacePrinting.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -472,7 +472,7 @@ void swift::ide::printSwiftSourceInterface(SourceFile &File, ASTPrinter &Printer, const PrintOptions &Options) { - // We print all comments before the fist line of Swift code. + // We print all comments before the first line of Swift code. printUntilFirstDeclStarts(File, Printer); File.print(Printer, Options); } diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index 4419c16a66c6a..8df697e2bee6d 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -111,6 +111,7 @@ static void toDisplayString(CodeCompletionResult *Result, case CodeCompletionDeclKind::Protocol: case CodeCompletionDeclKind::TypeAlias: + case CodeCompletionDeclKind::AssociatedType: case CodeCompletionDeclKind::GenericTypeParam: case CodeCompletionDeclKind::Constructor: case CodeCompletionDeclKind::Destructor: @@ -178,7 +179,7 @@ REPLCompletions::REPLCompletions() // Create a CodeCompletionConsumer. Consumer.reset(new REPLCodeCompletionConsumer(*this)); - // Cerate a factory for code completion callbacks that will feed the + // Create a factory for code completion callbacks that will feed the // Consumer. CompletionCallbacksFactory.reset( ide::makeCodeCompletionCallbacksFactory(CompletionContext, diff --git a/lib/IDE/ReconstructType.cpp b/lib/IDE/ReconstructType.cpp new file mode 100644 index 0000000000000..d77b444bc5292 --- /dev/null +++ b/lib/IDE/ReconstructType.cpp @@ -0,0 +1,2821 @@ +//===--- ReconstructType.cpp ----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// C++ Includes +#include // std::once +#include +#include + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/Target/TargetOptions.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DebuggerClient.h" +#include "swift/AST/IRGenOptions.h" +#include "swift/AST/Mangle.h" +#include "swift/AST/NameLookup.h" +#include "swift/AST/SearchPathOptions.h" +#include "swift/AST/Type.h" +#include "swift/AST/Types.h" +#include "swift/ASTSectionImporter/ASTSectionImporter.h" +#include "swift/Basic/Demangle.h" +#include "swift/Basic/LangOptions.h" +#include "swift/Basic/Platform.h" +#include "swift/Basic/SourceManager.h" +#include "swift/ClangImporter/ClangImporter.h" +#include "swift/ClangImporter/ClangImporterOptions.h" +#include "swift/Driver/Util.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Frontend/PrintingDiagnosticConsumer.h" +#include "swift/SIL/SILModule.h" +#include "swift/Serialization/SerializedModuleLoader.h" +#include "swift/Strings.h" + +#include "swift/IDE/Utils.h" + +typedef const std::string ConstString; +typedef void Log; +typedef swift::ASTContext SwiftASTContext; + +static std::string stringWithFormat(const std::string fmt_str, ...) { + int final_n, n = ((int)fmt_str.size()) * 2; + std::string str; + std::unique_ptr formatted; + va_list ap; + while(1) { + formatted.reset(new char[n]); + strcpy(&formatted[0], fmt_str.c_str()); + va_start(ap, fmt_str); + final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap); + va_end(ap); + if (final_n < 0 || final_n >= n) + n += abs(final_n - n + 1); + else + break; + } + return std::string(formatted.get()); +} + +static swift::TypeBase* +GetTemplateArgument (swift::TypeBase* type, + size_t arg_idx) +{ + if (type) + { + swift::CanType swift_can_type = type->getDesugaredType()->getCanonicalType(); + + const swift::TypeKind type_kind = swift_can_type->getKind(); + switch (type_kind) + { + case swift::TypeKind::UnboundGeneric: + { + swift::UnboundGenericType *unbound_generic_type = swift_can_type->getAs(); + if (!unbound_generic_type) + break; + swift::NominalTypeDecl *nominal_type_decl = unbound_generic_type->getDecl(); + if (!nominal_type_decl) + break; + swift::GenericParamList *generic_param_list = nominal_type_decl->getGenericParams(); + if (!generic_param_list) + break; + if (arg_idx >= generic_param_list->getAllArchetypes().size()) + break; + return generic_param_list->getAllArchetypes()[arg_idx]; + } + break; + case swift::TypeKind::BoundGenericClass: + case swift::TypeKind::BoundGenericStruct: + case swift::TypeKind::BoundGenericEnum: + { + swift::BoundGenericType *bound_generic_type = swift_can_type->getAs(); + if (!bound_generic_type) + break; + const llvm::ArrayRef& substitutions = bound_generic_type->getSubstitutions(nullptr,nullptr); + if (arg_idx >= substitutions.size()) + break; + const swift::Substitution& substitution = substitutions[arg_idx]; + return substitution.getReplacement().getPointer(); + } + case swift::TypeKind::PolymorphicFunction: + { + swift::PolymorphicFunctionType *polymorphic_func_type = swift_can_type->getAs(); + if (!polymorphic_func_type) + break; + if (arg_idx >= polymorphic_func_type->getGenericParameters().size()) + break; + return polymorphic_func_type->getGenericParameters()[arg_idx]->getArchetype(); + } + break; + default: + break; + } + } + + return nullptr; +} + +enum class MemberType : uint32_t { + Invalid, + BaseClass, + Field +}; + +struct MemberInfo { + swift::Type clang_type; + const std::string name; + uint64_t byte_size; + uint32_t byte_offset; + MemberType member_type; + bool is_fragile; + + MemberInfo(MemberType member_type) : + clang_type(), + name(), + byte_size(0), + byte_offset(0), + member_type(member_type), + is_fragile(false) + { + } +}; + +struct EnumElementInfo { + swift::Type clang_type; + ConstString name; + uint64_t byte_size; + uint32_t value; // The value for this enumeration element + uint32_t extra_value; // If not UINT32_MAX, then this value is an extra value + // that appears at offset 0 to tell one or more empty + // enums apart. This value will only be filled in if there + // are one or more enum elements that have a non-zero byte size + + EnumElementInfo() : + clang_type(), + name(), + byte_size(0), + extra_value(UINT32_MAX) + { + } +}; + +class DeclsLookupSource { +public: + typedef llvm::SmallVectorImpl ValueDecls; + +private: + class VisibleDeclsConsumer : public swift::VisibleDeclConsumer { + private: + std::vector m_decls; + public: + virtual void foundDecl(swift::ValueDecl *VD, swift::DeclVisibilityKind Reason) + { + m_decls.push_back(VD); + } + virtual ~VisibleDeclsConsumer() = default; + explicit operator bool() + { + return m_decls.size() > 0; + } + + decltype(m_decls)::const_iterator begin () + { + return m_decls.begin(); + } + + decltype(m_decls)::const_iterator end () + { + return m_decls.end(); + } + }; + + bool + lookupQualified (swift::ModuleDecl* entry, + swift::Identifier name, + unsigned options, + swift::LazyResolver *typeResolver, + ValueDecls& decls) { + if (!entry) + return false; + size_t decls_size = decls.size(); + entry->lookupQualified(swift::ModuleType::get(entry), name, options, typeResolver, decls); + return decls.size() > decls_size; + } + + bool + lookupValue (swift::ModuleDecl* entry, + swift::Identifier name, + swift::Module::AccessPathTy accessPath, + swift::NLKind lookupKind, + ValueDecls &decls) { + if (!entry) + return false; + size_t decls_size = decls.size(); + entry->lookupValue(accessPath, name, lookupKind, decls); + return decls.size() > decls_size; + } + +public: + enum class Type { + SwiftModule, + Crawler, + Decl, + Extension, + Invalid + }; + + typedef llvm::Optional PrivateDeclIdentifier; + + static DeclsLookupSource + GetDeclsLookupSource (swift::ASTContext& ast, + ConstString module_name, + bool allow_crawler = true) + { + assert(!module_name.empty()); + static ConstString g_ObjectiveCModule(swift::MANGLING_MODULE_OBJC); + static ConstString g_BuiltinModule("Builtin"); + static ConstString g_CModule(swift::MANGLING_MODULE_C); + if (allow_crawler) + { + if (module_name == g_ObjectiveCModule || module_name == g_CModule) + return DeclsLookupSource(&ast, module_name); + } + + swift::ModuleDecl * module = module_name == g_BuiltinModule ? + ast.TheBuiltinModule : + ast.getModuleByName(module_name); + if (module == nullptr) + return DeclsLookupSource(); + return DeclsLookupSource(module); + } + + static DeclsLookupSource + GetDeclsLookupSource (swift::NominalTypeDecl *decl) + { + assert(decl); + return DeclsLookupSource(decl); + } + + static DeclsLookupSource + GetDeclsLookupSource (DeclsLookupSource source, swift::NominalTypeDecl *decl) + { + assert(source._type == Type::SwiftModule); + assert(source._module); + assert(decl); + return DeclsLookupSource(source._module, decl); + } + + void lookupQualified(swift::Identifier name, + unsigned options, + swift::LazyResolver *typeResolver, + ValueDecls &result) + { + if (_type == Type::Crawler) + { + swift::ASTContext *ast_ctx = _crawler._ast; + if (ast_ctx) + { + VisibleDeclsConsumer consumer; + swift::ClangImporter *swift_clang_importer = (swift::ClangImporter *) + ast_ctx->getClangModuleLoader(); + if (!swift_clang_importer) + return; + swift_clang_importer->lookupValue(name, consumer); + if (consumer) + { + auto iter = consumer.begin(), end = consumer.end(); + while (iter != end) + { + result.push_back(*iter); + iter++; + } + return; + } + else + { + const bool allow_crawler = false; + if (_crawler._module) + GetDeclsLookupSource(*ast_ctx, ConstString(_crawler._module), + allow_crawler).lookupQualified(name, options, typeResolver, result); + } + } + } + else if (_type == Type::SwiftModule) + lookupQualified(_module, name, options, typeResolver, result); + return; + } + + void lookupValue(swift::Module::AccessPathTy path, + swift::Identifier name, + swift::NLKind kind, + ValueDecls &result) + { + if (_type == Type::Crawler) + { + swift::ASTContext *ast_ctx = _crawler._ast; + if (ast_ctx) + { + VisibleDeclsConsumer consumer; + swift::ClangImporter *swift_clang_importer = (swift::ClangImporter *) + ast_ctx->getClangModuleLoader(); + if (!swift_clang_importer) + return; + swift_clang_importer->lookupValue(name, consumer); + if (consumer) + { + auto iter = consumer.begin(), end = consumer.end(); + while (iter != end) + { + result.push_back(*iter); + iter++; + } + return; + } + else + { + const bool allow_crawler = false; + if (_crawler._module) + GetDeclsLookupSource(*ast_ctx, ConstString(_crawler._module), + allow_crawler).lookupValue(path, name, kind, + result); + } + } + } + else if (_type == Type::SwiftModule) + _module->lookupValue(path, name, kind, result); + return; + } + + void lookupMember (swift::DeclName id, + swift::Identifier priv_decl_id, + ValueDecls &result) + { + if (_type == Type::Decl) + return lookupMember(_decl, id, priv_decl_id, result); + if (_type == Type::SwiftModule) + return lookupMember(_module, id, priv_decl_id, result); + if (_type == Type::Extension) + return lookupMember(_extension._decl, id, priv_decl_id, result); + return; + } + + void + lookupMember (swift::DeclContext *decl_ctx, + swift::DeclName id, + swift::Identifier priv_decl_id, + ValueDecls &result) + { + if (_type == Type::Decl) + _decl->getModuleContext()->lookupMember(result, decl_ctx, id, priv_decl_id); + else if (_type == Type::SwiftModule) + _module->lookupMember(result, decl_ctx, id, priv_decl_id); + else if (_type == Type::Extension) + _extension._module->lookupMember(result, decl_ctx, id, priv_decl_id); + return; + } + + swift::TypeDecl * + lookupLocalType (llvm::StringRef key) + { + switch (_type) + { + case Type::SwiftModule: + return _module->lookupLocalType(key); + case Type::Decl: + return _decl->getModuleContext()->lookupLocalType(key); + case Type::Extension: + return _extension._module->lookupLocalType(key); + case Type::Invalid: + return nullptr; + case Type::Crawler: + return nullptr; + } + } + + ConstString + GetName () const + { + switch(_type) + { + case Type::Invalid: + return ConstString("Invalid"); + case Type::Crawler: + return ConstString("Crawler"); + case Type::SwiftModule: + return ConstString(_module->getName().get()); + case Type::Decl: + return ConstString(_decl->getName().get()); + case Type::Extension: + llvm::SmallString<64> builder; + builder.append("ext "); + builder.append(_extension._decl->getNameStr()); + builder.append(" in "); + builder.append(_module->getNameStr()); + return builder.str(); + } + } + + DeclsLookupSource (const DeclsLookupSource &rhs) : + _type(rhs._type) + { + switch (_type) + { + case Type::Invalid: + break; + case Type::Crawler: + _crawler._ast = rhs._crawler._ast; + _crawler._module = rhs._crawler._module; + break; + case Type::SwiftModule: + _module = rhs._module; + break; + case Type::Decl: + _decl = rhs._decl; + _extension._decl = rhs._extension._decl; + _extension._module = rhs._extension._module; + break; + case Type::Extension: + _extension._decl = rhs._extension._decl; + _extension._module = rhs._extension._module; + break; + } + } + + DeclsLookupSource& + operator = (const DeclsLookupSource& rhs) + { + if (this != &rhs) + { + _type = rhs._type; + switch (_type) + { + case Type::Invalid: + break; + case Type::Crawler: + _crawler._ast = rhs._crawler._ast; + _crawler._module = rhs._crawler._module; + break; + case Type::SwiftModule: + _module = rhs._module; + break; + case Type::Decl: + _decl = rhs._decl; + _extension._decl = rhs._extension._decl; + _extension._module = rhs._extension._module; + break; + case Type::Extension: + _extension._decl = rhs._extension._decl; + _extension._module = rhs._extension._module; + break; + } + } + return *this; + } + + void + Clear () + { + // no need to explicitly clean either pointer + _type = Type::Invalid; + } + + DeclsLookupSource () : + _type(Type::Invalid), + _module(nullptr) + {} + + operator bool () + { + switch (_type) + { + case Type::Invalid: + return false; + case Type::Crawler: + return _crawler._ast != nullptr; + case Type::SwiftModule: + return _module != nullptr; + case Type::Decl: + return _decl != nullptr; + case Type::Extension: + return (_extension._decl != nullptr) && (_extension._module != nullptr); + } + } + + bool + IsExtension () + { + return (this->operator bool()) && (_type == Type::Extension); + } + + swift::Type + GetQualifiedArchetype (size_t index, + swift::ASTContext* ast) + { + if (this->operator bool() && ast) + { + switch (_type) + { + case Type::Extension: + { + swift::TypeBase *type_ptr = _extension._decl->getType().getPointer(); + if (swift::MetatypeType *metatype_ptr = type_ptr->getAs()) + type_ptr = metatype_ptr->getInstanceType().getPointer(); + swift::TypeBase *archetype = GetTemplateArgument(type_ptr, index); + return swift::Type(archetype); + } + break; + default: + break; + } + } + return swift::Type(); + } + +private: + Type _type; + + union { + swift::ModuleDecl *_module; + struct { + swift::ASTContext* _ast; + const char* _module; + } _crawler; + swift::NominalTypeDecl *_decl; + struct { + swift::ModuleDecl *_module; // extension in this module + swift::NominalTypeDecl *_decl; // for this type + } _extension; + }; + + DeclsLookupSource(swift::ModuleDecl* _m) + { + if (_m) + { + _module = _m; + _type = Type::SwiftModule; + } + else + _type = Type::Invalid; + } + + DeclsLookupSource(swift::ASTContext* _a, + ConstString _m) + { + // it is fine for the ASTContext to be null, so don't actually even lldbassert there + if (_a) + { + _crawler._ast = _a; + _crawler._module = _m.data(); + _type = Type::Crawler; + } + else + _type = Type::Invalid; + } + + DeclsLookupSource (swift::NominalTypeDecl * _d) + { + if (_d) + { + _decl = _d; + _type = Type::Decl; + } + else + _type = Type::Invalid; + } + + DeclsLookupSource (swift::ModuleDecl *_m, + swift::NominalTypeDecl * _d) + { + if (_m && _d) + { + _extension._decl = _d; + _extension._module = _m; + _type = Type::Extension; + } + else + _type = Type::Invalid; + } +}; + +struct VisitNodeResult { + DeclsLookupSource _module; + std::vector _decls; + std::vector _types; + swift::TupleTypeElt _tuple_type_element; + std::string _error; + VisitNodeResult () : + _module(), + _decls(), + _types(), + _tuple_type_element(), + _error() + { + } + + bool + HasSingleType () + { + return _types.size() == 1 && _types.front(); + } + + swift::Type + GetFirstType () + { + // Must ensure there is a type prior to calling this + return _types.front(); + } + + void + Clear() + { + _module.Clear(); + _decls.clear(); + _types.clear(); + _tuple_type_element = swift::TupleTypeElt(); + _error = ""; + } + + bool + HasAnyDecls () + { + return !_decls.empty(); + } + + bool + HasAnyTypes () + { + return !_types.empty(); + } +}; + +static swift::Identifier +GetIdentifier (SwiftASTContext *ast, + const DeclsLookupSource::PrivateDeclIdentifier& priv_decl_id) +{ + do { + if (!ast) + break; + if (!priv_decl_id.hasValue()) + break; + return ast->getIdentifier(priv_decl_id.getValue().c_str()); + } while (false); + return swift::Identifier(); +} + +static bool +FindFirstNamedDeclWithKind (SwiftASTContext *ast, + const llvm::StringRef &name, + swift::DeclKind decl_kind, + VisitNodeResult &result, + DeclsLookupSource::PrivateDeclIdentifier priv_decl_id = DeclsLookupSource::PrivateDeclIdentifier()) + +{ + if (!result._decls.empty()) + { + swift::Decl *parent_decl = result._decls.back(); + if (parent_decl) + { + auto nominal_decl = llvm::dyn_cast(parent_decl); + + if (nominal_decl) + { + bool check_type_aliases = false; + + DeclsLookupSource lookup(DeclsLookupSource::GetDeclsLookupSource(nominal_decl)); + llvm::SmallVector decls; + lookup.lookupMember(ast->getIdentifier(name), + GetIdentifier(ast,priv_decl_id), + decls); + + for (auto decl : decls) + { + const swift::DeclKind curr_decl_kind = decl->getKind(); + + if (curr_decl_kind == decl_kind) + { + result._decls.back() = decl; + swift::Type decl_type; + if (decl->hasType()) + { + decl_type = decl->getType(); + swift::MetatypeType *meta_type = decl_type->getAs(); + if (meta_type) + decl_type = meta_type->getInstanceType(); + } + if (result._types.empty()) + result._types.push_back(decl_type); + else + result._types.back() = decl_type; + return true; + } else if (curr_decl_kind == swift::DeclKind::TypeAlias) + check_type_aliases = true; + } + + if (check_type_aliases) + { + for (auto decl : decls) + { + const swift::DeclKind curr_decl_kind = decl->getKind(); + + if (curr_decl_kind == swift::DeclKind::TypeAlias) + { + result._decls.back() = decl; + swift::Type decl_type; + if (decl->hasType()) + { + decl_type = decl->getType(); + swift::MetatypeType *meta_type = decl_type->getAs(); + if (meta_type) + decl_type = meta_type->getInstanceType(); + } + if (result._types.empty()) + result._types.push_back(decl_type); + else + result._types.back() = decl_type; + return true; + } + } + } + } + } + } + else if (result._module) + { + swift::Module::AccessPathTy access_path; + swift::Identifier name_ident(ast->getIdentifier(name)); + llvm::SmallVector decls; + if (priv_decl_id) + result._module.lookupMember(name_ident, ast->getIdentifier(priv_decl_id.getValue().c_str()), decls); + else + result._module.lookupQualified(name_ident, 0, NULL, decls); + if (!decls.empty()) + { + bool check_type_aliases = false; + // Look for an exact match first + for (auto decl : decls) + { + const swift::DeclKind curr_decl_kind = decl->getKind(); + if (curr_decl_kind == decl_kind) + { + result._decls.assign(1, decl); + if (decl->hasType()) + { + result._types.assign(1, decl->getType()); + swift::MetatypeType *meta_type = result._types.back()->getAs(); + if (meta_type) + result._types.back() = meta_type->getInstanceType(); + } + else + { + result._types.assign(1, swift::Type()); + } + return true; + } else if (curr_decl_kind == swift::DeclKind::TypeAlias) + check_type_aliases = true; + } + // If we didn't find any exact matches, accept any type aliases + if (check_type_aliases) + { + for (auto decl : decls) + { + if (decl->getKind() == swift::DeclKind::TypeAlias) + { + result._decls.assign(1, decl); + if (decl->hasType()) + { + result._types.assign(1, decl->getType()); + swift::MetatypeType *meta_type = result._types.back()->getAs(); + if (meta_type) + result._types.back() = meta_type->getInstanceType(); + } + else + { + result._types.assign(1, swift::Type()); + } + return true; + } + } + } + } + } + result.Clear(); + result._error = "Generic Error"; + return false; +} + +static size_t +FindNamedDecls (SwiftASTContext *ast, + const llvm::StringRef &name, + VisitNodeResult &result, + DeclsLookupSource::PrivateDeclIdentifier priv_decl_id = DeclsLookupSource::PrivateDeclIdentifier()) +{ + if (!result._decls.empty()) + { + swift::Decl *parent_decl = result._decls.back(); + result._decls.clear(); + result._types.clear(); + if (parent_decl) + { + auto nominal_decl = llvm::dyn_cast(parent_decl); + + if (nominal_decl) + { + DeclsLookupSource lookup(DeclsLookupSource::GetDeclsLookupSource(nominal_decl)); + llvm::SmallVector decls; + lookup.lookupMember(ast->getIdentifier(name), + GetIdentifier(ast,priv_decl_id), + decls); + if (decls.empty()) + { + result._error = stringWithFormat("no decl found in '%s' (DeclKind=%u)", + name.str().c_str(), + nominal_decl->getName().get(), + (uint32_t)nominal_decl->getKind()); + } + else + { + for (swift::ValueDecl *decl : decls) + { + if (decl->hasType()) + { + result._decls.push_back(decl); + swift::Type decl_type; + if (decl->hasType()) + { + decl_type = decl->getType(); + swift::MetatypeType *meta_type = decl_type->getAs(); + if (meta_type) + decl_type = meta_type->getInstanceType(); + } + result._types.push_back(decl_type); + } + } + return result._types.size(); + } + } + else + { + result._error = stringWithFormat("decl is not a nominal_decl (DeclKind=%u), lookup for '%s' failed", + (uint32_t)parent_decl->getKind(), + name.str().c_str()); + } + } + } + else if (result._module) + { + swift::Module::AccessPathTy access_path; + llvm::SmallVector decls; + if (priv_decl_id) + result._module.lookupMember(ast->getIdentifier(name), + ast->getIdentifier(priv_decl_id.getValue().c_str()), + decls); + else + result._module.lookupValue(access_path, ast->getIdentifier(name), swift::NLKind::QualifiedLookup, decls); + if (decls.empty()) + { + result._error = stringWithFormat("no decl named '%s' found in module '%s'", + name.str().c_str(), + result._module.GetName().data()); + } + else + { + for (auto decl : decls) + { + if (decl->hasType()) + { + result._decls.push_back(decl); + if (decl->hasType()) + { + result._types.push_back(decl->getType()); + swift::MetatypeType *meta_type = result._types.back()->getAs(); + if (meta_type) + result._types.back() = meta_type->getInstanceType(); + } + else + { + result._types.push_back(swift::Type()); + } + } + } + return result._types.size(); + } + } + result.Clear(); + result._error = "Generic error."; + return false; +} + +static const char * +SwiftDemangleNodeKindToCString(const swift::Demangle::Node::Kind node_kind) +{ +#define NODE(e) case swift::Demangle::Node::Kind::e: return #e; + + switch (node_kind) + { +#include "swift/Basic/DemangleNodes.def" + } + return "swift::Demangle::Node::Kind::???"; +#undef NODE +} + +static +swift::DeclKind +GetKindAsDeclKind (swift::Demangle::Node::Kind node_kind) +{ + switch (node_kind) + { + case swift::Demangle::Node::Kind::TypeAlias: + return swift::DeclKind::TypeAlias; + case swift::Demangle::Node::Kind::Structure: + return swift::DeclKind::Struct; + case swift::Demangle::Node::Kind::Class: + return swift::DeclKind::Class; + case swift::Demangle::Node::Kind::Allocator: + return swift::DeclKind::Constructor; + case swift::Demangle::Node::Kind::Function: + return swift::DeclKind::Func; + case swift::Demangle::Node::Kind::Enum: + return swift::DeclKind::Enum; + case swift::Demangle::Node::Kind::Protocol: + return swift::DeclKind::Protocol; + default: + printf ("Missing alias for %s.\n", SwiftDemangleNodeKindToCString(node_kind)); + assert (0); + } +} + +// This should be called with a function type & its associated Decl. If the type is not a function type, +// then we just return the original type, but we don't check that the Decl is the associated one. +// It is assumed you will get that right in calling this. +// Returns a version of the input type with the ExtInfo AbstractCC set correctly. +// This allows CompilerType::IsSwiftMethod to work properly off the swift Type. +// FIXME: we don't currently distinguish between Method & Witness. These types don't actually get used +// to make Calling Convention choices - originally we were leaving them all at Normal... But if we ever +// need to set it for that purpose we will have to fix that here. +static swift::TypeBase * +FixCallingConv (swift::Decl *in_decl, swift::TypeBase *in_type) +{ + if (!in_decl) + return in_type; + + swift::AnyFunctionType *func_type = llvm::dyn_cast(in_type); + if (func_type) + { + swift::DeclContext *decl_context = in_decl->getDeclContext(); + if (decl_context && decl_context->isTypeContext()) + { + // Add the ExtInfo: + swift::AnyFunctionType::ExtInfo new_info(func_type->getExtInfo().withSILRepresentation(swift::SILFunctionTypeRepresentation::Method)); + return func_type->withExtInfo(new_info); + } + } + return in_type; +} + +static void +VisitNode (SwiftASTContext *ast, + std::vector &nodes, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log); + + +static void +VisitNodeAddressor (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + // Addressors are apparently SIL-level functions of the form () -> RawPointer and they bear no connection to their original variable at the interface level + swift::CanFunctionType swift_can_func_type = swift::CanFunctionType::get(ast->TheEmptyTupleType, ast->TheRawPointerType); + result._types.push_back(swift_can_func_type.getPointer()); +} + +static void +VisitNodeGenerics (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + llvm::SmallVector nested_types; + VisitNodeResult associated_type_result; + VisitNodeResult archetype_ref_result; + VisitNodeResult archetype_type_result; + for (swift::Demangle::Node::iterator pos = cur_node->begin(), end = cur_node->end(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::ArchetypeRef: + nodes.push_back(*pos); + VisitNode (ast, nodes, archetype_ref_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::Archetype: + nodes.push_back(*pos); + VisitNode (ast, nodes, archetype_type_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::AssociatedType: + nodes.push_back(*pos); + VisitNode (ast, nodes, associated_type_result, generic_context, log); + if (associated_type_result.HasSingleType()) + nested_types.push_back(associated_type_result.GetFirstType()); + break; + default: + result._error = stringWithFormat("%s encountered in generics children", + SwiftDemangleNodeKindToCString(child_node_kind)); + break; + } + } + + if (archetype_ref_result.HasAnyDecls() || archetype_ref_result.HasAnyTypes()) + result = archetype_ref_result; + else + result = archetype_type_result; +} + +static void +VisitNodeArchetype(SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + const llvm::StringRef& archetype_name(cur_node->getText()); + VisitNodeResult protocol_list; + for (swift::Demangle::Node::iterator pos = cur_node->begin(), end = cur_node->end(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::ProtocolList: + nodes.push_back(*pos); + VisitNode (ast, nodes, protocol_list, generic_context, log); + break; + default: + result._error = stringWithFormat("%s encountered in generics children", + SwiftDemangleNodeKindToCString(child_node_kind)); + break; + } + } + + llvm::SmallVector conforms_to; + if (protocol_list.HasSingleType()) + conforms_to.push_back(protocol_list.GetFirstType()); + + if (ast) + { + result._types.push_back(swift::ArchetypeType::getNew(*ast, + nullptr, + (swift::AssociatedTypeDecl *)nullptr, + ast->getIdentifier(archetype_name), + conforms_to, swift::Type())); + } + else + { + result._error = "invalid ASTContext"; + } +} + + +static void +VisitNodeArchetypeRef(SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + const llvm::StringRef& archetype_name(cur_node->getText()); + swift::Type result_type; + for (const swift::Type &archetype : generic_context._types) + { + const swift::ArchetypeType *cast_archetype = llvm::dyn_cast(archetype.getPointer()); + + if (cast_archetype && !cast_archetype->getName().str().compare(archetype_name)) + { + result_type = archetype; + break; + } + } + + if (result_type) + result._types.push_back(result_type); + else + { + if (ast) + { + result._types.push_back(swift::ArchetypeType::getNew(*ast, + nullptr, + (swift::AssociatedTypeDecl *)nullptr, + ast->getIdentifier(archetype_name), + llvm::ArrayRef(), swift::Type())); + } + else + { + result._error = "invalid ASTContext"; + } + } +} + +static void +VisitNodeAssociatedTypeRef (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + swift::Demangle::NodePointer root = cur_node->getChild(0); + swift::Demangle::NodePointer ident = cur_node->getChild(1); + if (!root || !ident) + return; + nodes.push_back(root); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result._types.size() == 1) + { + swift::TypeBase* type = type_result._types[0].getPointer(); + if (type) + { + swift::ArchetypeType* archetype = type->getAs(); + if (archetype) + { + swift::Identifier identifier = ast->getIdentifier(ident->getText()); + if (archetype->hasNestedType(identifier)) + { + swift::Type nested = archetype->getNestedTypeValue(identifier); + if (nested) + { + result._types.push_back(nested); + result._module = type_result._module; + return; + } + } + } + } + } + result._types.clear(); + result._error = stringWithFormat("unable to find associated type %s in context", ident->getText().c_str()); +} + +static void +VisitNodeBoundGeneric (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() != cur_node->end()) + { + VisitNodeResult generic_type_result; + VisitNodeResult template_types_result; + + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Type: + case swift::Demangle::Node::Kind::Metatype: + nodes.push_back(*pos); + VisitNode (ast, nodes, generic_type_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::TypeList: + nodes.push_back(*pos); + VisitNode (ast, nodes, template_types_result, generic_context, log); + break; + default: + break; + } + } + + if (generic_type_result._types.size() == 1 && !template_types_result._types.empty()) + { + swift::NominalTypeDecl *nominal_type_decl = llvm::dyn_cast(generic_type_result._decls.front()); + swift::DeclContext * parent_decl = nominal_type_decl->getParent(); + swift::Type parent_type; + if (parent_decl->isTypeContext()) + parent_type = parent_decl->getDeclaredTypeOfContext(); + result._types.push_back(swift::Type(swift::BoundGenericType::get(nominal_type_decl, + parent_type, + template_types_result._types))); + + } + } +} + +static void +VisitNodeBuiltinTypeName (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + std::string builtin_name = cur_node->getText(); + + llvm::StringRef builtin_name_ref(builtin_name); + + if (builtin_name_ref.startswith("Builtin.")) + { + llvm::StringRef stripped_name_ref = builtin_name_ref.drop_front(strlen("Builtin.")); + llvm::SmallVector builtin_decls; + + result._module = DeclsLookupSource::GetDeclsLookupSource(*ast, ConstString("Builtin")); + + if (!FindNamedDecls(ast, stripped_name_ref, result)) + { + result.Clear(); + result._error = stringWithFormat("Couldn't find %s in the builtin module", + builtin_name.c_str()); + } + } + else + { + result._error = stringWithFormat("BuiltinTypeName %s doesn't start with Builtin.", + builtin_name.c_str()); + } +} + +static void +VisitNodeConstructor (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult kind_type_result; + VisitNodeResult type_result; + + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Enum: + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Structure: + nodes.push_back(*pos); + VisitNode (ast, nodes, kind_type_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::Type: + nodes.push_back(*pos); + VisitNode (ast, nodes, type_result, generic_context, log); + break; + default: + break; + } + } + + if (kind_type_result.HasSingleType() && type_result.HasSingleType()) + { + bool found = false; + const size_t n = FindNamedDecls(ast, llvm::StringRef("init"), kind_type_result); + if (n == 1) + { + found = true; + kind_type_result._types[0] = FixCallingConv(kind_type_result._decls[0], kind_type_result._types[0].getPointer()); + result = kind_type_result; + } + else if (n > 0) + { + const size_t num_kind_type_results = kind_type_result._types.size(); + for (size_t i=0; igetKind() == type_result._types.front()->getKind()) + { + // These are the same kind of type, we need to disambiguate them + switch (identifier_type->getKind()) + { + default: + break; + case swift::TypeKind::Function: + { + const swift::AnyFunctionType* identifier_func = identifier_type->getAs(); + const swift::AnyFunctionType* type_func = type_result._types.front()->getAs(); + if (swift::CanType(identifier_func->getResult()->getDesugaredType()->getCanonicalType()) == swift::CanType(type_func->getResult()->getDesugaredType()->getCanonicalType()) && + swift::CanType(identifier_func->getInput()->getDesugaredType()->getCanonicalType()) == swift::CanType(type_func->getInput()->getDesugaredType()->getCanonicalType())) + { + result._module = kind_type_result._module; + result._decls.push_back(kind_type_result._decls[i]); + result._types.push_back(FixCallingConv(kind_type_result._decls[i], kind_type_result._types[i].getPointer())); + found = true; + } + } + break; + } + } + } + } + // Didn't find a match, just return the raw function type + if (!found) + result = type_result; + + } +} + +static void +VisitNodeDestructor (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult kind_type_result; + + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Enum: + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Structure: + nodes.push_back(*pos); + VisitNode (ast, nodes, kind_type_result, generic_context, log); + break; + default: + break; + } + } + + if (kind_type_result.HasSingleType()) + { + bool found = false; + const size_t n = FindNamedDecls(ast, llvm::StringRef("deinit"), kind_type_result); + if (n == 1) + { + found = true; + kind_type_result._types[0] = FixCallingConv(kind_type_result._decls[0], + kind_type_result._types[0].getPointer()); + result = kind_type_result; + } + else if (n > 0) + { + // I can't think of a reason why we would get more than one decl called deinit here, but + // just in case, if it is a function type, we should remember it. + const size_t num_kind_type_results = kind_type_result._types.size(); + for (size_t i=0; igetKind()) + { + default: + break; + case swift::TypeKind::Function: + { + result._module = kind_type_result._module; + result._decls.push_back(kind_type_result._decls[i]); + result._types.push_back(FixCallingConv(kind_type_result._decls[i], + kind_type_result._types[i].getPointer())); + found = true; + } + break; + } + } + } + } + } +} + +static void +VisitNodeDeclContext (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + switch (cur_node->getNumChildren()) + { + default: + result._error = stringWithFormat("DeclContext had %llu children, giving up", + (unsigned long long)cur_node->getNumChildren()); + break; + case 0: + result._error = "empty DeclContext unusable"; + break; + case 1: + // nominal type + nodes.push_back(cur_node->getFirstChild()); + VisitNode (ast, nodes, result, generic_context, log); + break; + case 2: + // function type: decl-ctx + type + // FIXME: we should just be able to demangle the DeclCtx and resolve the function + // this is fragile and will easily break + swift::Demangle::NodePointer path = cur_node->getFirstChild(); + nodes.push_back(path); + VisitNodeResult found_decls; + VisitNode (ast, nodes, found_decls, generic_context, log); + swift::Demangle::NodePointer generics = cur_node->getChild(1); + if (generics->getChild(0) == nullptr) + break; + generics = generics->getFirstChild(); + if (generics->getKind() != swift::Demangle::Node::Kind::GenericType) + break; + if (generics->getChild(0) == nullptr) + break; + generics = generics->getFirstChild(); + // if (generics->getKind() != swift::Demangle::Node::Kind::ArchetypeList) + // break; + swift::AbstractFunctionDecl *func_decl = nullptr; + for (swift::Decl* decl : found_decls._decls) + { + func_decl = llvm::dyn_cast(decl); + if (!func_decl) + continue; + swift::GenericParamList *gen_params = func_decl->getGenericParams(); + if (!gen_params) + continue; + } + if (func_decl) + { + result._module = found_decls._module; + result._decls.push_back(func_decl); + result._types.push_back(func_decl->getType().getPointer()); + } + else + result._error = "could not find a matching function for the DeclContext"; + break; + } +} + +static void +VisitNodeExplicitClosure (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + // FIXME: closures are mangled as hanging off a function, but they really aren't + // so we cannot really do a lot about them, other than make a function type + // for whatever their advertised type is, and cross fingers + VisitNodeResult function_result; + uint64_t index = UINT64_MAX; + VisitNodeResult closure_type_result; + VisitNodeResult module_result; + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + default: + result._error = stringWithFormat("%s encountered in ExplicitClosure children", + SwiftDemangleNodeKindToCString(child_node_kind)); + break; + case swift::Demangle::Node::Kind::Module: + nodes.push_back((*pos)); + VisitNode (ast, nodes, module_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::Function: + nodes.push_back((*pos)); + VisitNode (ast, nodes, function_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::Number: + index = (*pos)->getIndex(); + break; + case swift::Demangle::Node::Kind::Type: + nodes.push_back((*pos)); + VisitNode (ast, nodes, closure_type_result, generic_context, log); + break; + } + } + if (closure_type_result.HasSingleType()) + result._types.push_back(closure_type_result._types.front()); + else + result._error = "multiple potential candidates to be this closure's type"; + // FIXME: closures are not lookupable by compiler team's decision + // ("You cannot perform lookup into local contexts." x3) + // so we at least store the module the closure came from to enable + // further local types lookups + if (module_result._module) + result._module = module_result._module; +} + +static void +VisitNodeExtension (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult module_result; + VisitNodeResult type_result; + std::string error; + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + default: + result._error = stringWithFormat("%s encountered in extension children", SwiftDemangleNodeKindToCString(child_node_kind)); + break; + + case swift::Demangle::Node::Kind::Module: + nodes.push_back((*pos)); + VisitNode(ast, nodes, module_result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Enum: + case swift::Demangle::Node::Kind::Structure: + nodes.push_back((*pos)); + VisitNode(ast, nodes, type_result, generic_context, log); + break; + } + } + + if (module_result._module) + { + if (type_result._decls.size() == 1) + { + swift::Decl *decl = type_result._decls[0]; + swift::NominalTypeDecl *nominal_decl = llvm::dyn_cast_or_null(decl); + if (nominal_decl) + { + result._module = DeclsLookupSource::GetDeclsLookupSource(module_result._module, nominal_decl); + } + else + result._error = "unable to find nominal type for extension"; + } + else + result._error = "unable to find unique type for extension"; + } + else + result._error = "unable to find module name for extension"; +} + +static bool +AreBothFunctionTypes (swift::TypeKind a, + swift::TypeKind b) +{ + bool is_first = false, is_second = false; + if (a >= swift::TypeKind::First_AnyFunctionType && + a <= swift::TypeKind::Last_AnyFunctionType) + is_first = true; + if (b >= swift::TypeKind::First_AnyFunctionType && + b <= swift::TypeKind::Last_AnyFunctionType) + is_second = true; + return (is_first && is_second); +} + +static bool +CompareFunctionTypes (const swift::AnyFunctionType *f, + const swift::AnyFunctionType *g, + bool *input_matches = nullptr, + bool *output_matches = nullptr) +{ + bool in_matches = false, out_matches = false; + if (nullptr == f) + return (nullptr == g); + if (nullptr == g) + return false; + + auto f_input = f->getInput().getCanonicalTypeOrNull(); + auto g_input = g->getInput().getCanonicalTypeOrNull(); + + auto f_output = f->getResult().getCanonicalTypeOrNull(); + auto g_output = g->getResult().getCanonicalTypeOrNull(); + + if (f_input == g_input) + { + in_matches = true; + if (f_output == g_output) + out_matches = true; + } + + if (input_matches) + *input_matches = in_matches; + if (output_matches) + *output_matches = out_matches; + + return (in_matches && out_matches); +} + + + +// VisitNodeFunction gets used for Function, Variable and Allocator: +static void +VisitNodeFunction (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult identifier_result; + VisitNodeResult type_result; + VisitNodeResult decl_scope_result; + swift::Demangle::Node::iterator end = cur_node->end(); + bool found_univocous = false; + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + if (found_univocous) + break; + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + default: + result._error = stringWithFormat("%s encountered in function children", + SwiftDemangleNodeKindToCString(child_node_kind)); + break; + + // TODO: any other possible containers? + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Enum: + case swift::Demangle::Node::Kind::Module: + case swift::Demangle::Node::Kind::Structure: + nodes.push_back((*pos)); + VisitNode (ast, nodes, decl_scope_result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Identifier: + case swift::Demangle::Node::Kind::InfixOperator: + case swift::Demangle::Node::Kind::PrefixOperator: + case swift::Demangle::Node::Kind::PostfixOperator: + FindNamedDecls(ast, (*pos)->getText(), decl_scope_result); + if (decl_scope_result._decls.size() == 0) + { + result._error = stringWithFormat("demangled identifier %s could not be found by name lookup", + (*pos)->getText().c_str()); + break; + } + std::copy(decl_scope_result._decls.begin(), + decl_scope_result._decls.end(), + back_inserter(identifier_result._decls)); + std::copy(decl_scope_result._types.begin(), + decl_scope_result._types.end(), + back_inserter(identifier_result._types)); + identifier_result._module = decl_scope_result._module; + if (decl_scope_result._decls.size() == 1) + found_univocous = true; + break; + + case swift::Demangle::Node::Kind::Type: + nodes.push_back((*pos)); + VisitNode (ast, nodes, type_result, generic_context, log); + break; + } + } + + // if (node_kind == swift::Demangle::Node::Kind::Allocator) + // { + // // For allocators we don't have an identifier for the name, we will + // // need to extract it from the class or struct in "identifier_result" + // //Find + // if (identifier_result.HasSingleType()) + // { + // // This contains the class or struct + // llvm::StringRef init_name("init"); + // + // if (FindFirstNamedDeclWithKind(ast, init_name, swift::DeclKind::Constructor, identifier_result)) + // { + // } + // } + // } + + if (identifier_result._types.size() == 1) + { + result._module = identifier_result._module; + result._decls.push_back(identifier_result._decls[0]); + result._types.push_back(FixCallingConv(identifier_result._decls[0], identifier_result._types[0].getPointer())); + } + else if (type_result.HasSingleType()) + { + const size_t num_identifier_results = identifier_result._types.size(); + bool found = false; + for (size_t i=0; igetKind(), type_result._types.front()->getKind())) + { + const swift::AnyFunctionType* identifier_func = identifier_type->getAs(); + const swift::AnyFunctionType* type_func = type_result._types.front()->getAs(); + if (CompareFunctionTypes(identifier_func, type_func)) + { + result._module = identifier_result._module; + result._decls.push_back(identifier_result._decls[i]); + result._types.push_back(FixCallingConv(identifier_result._decls[i], identifier_result._types[i].getPointer())); + found = true; + } + } + } + // Didn't find a match, just return the raw function type + if (!found) + result = type_result; + } +} + +static void +VisitNodeFunctionType (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult arg_type_result; + VisitNodeResult return_type_result; + swift::Demangle::Node::iterator end = cur_node->end(); + bool is_in_class = false; + bool throws = false; + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Class: + { + is_in_class = true; + VisitNodeResult class_type_result; + nodes.push_back(*pos); + VisitNode (ast, nodes, class_type_result, generic_context, log); + } + break; + case swift::Demangle::Node::Kind::Structure: + { + VisitNodeResult class_type_result; + nodes.push_back(*pos); + VisitNode (ast, nodes, class_type_result, generic_context, log); + } + break; + case swift::Demangle::Node::Kind::ArgumentTuple: + case swift::Demangle::Node::Kind::Metatype: + { + nodes.push_back(*pos); + VisitNode (ast, nodes, arg_type_result, generic_context, log); + } + break; + case swift::Demangle::Node::Kind::ThrowsAnnotation: + throws = true; + break; + case swift::Demangle::Node::Kind::ReturnType: + { + nodes.push_back(*pos); + VisitNode (ast, nodes, return_type_result, generic_context, log); + } + break; + default: + break; + } + } + swift::Type arg_clang_type; + swift::Type return_clang_type; + + switch (arg_type_result._types.size()) + { + case 0: + arg_clang_type = swift::TupleType::getEmpty(*ast); + break; + case 1: + arg_clang_type = arg_type_result._types.front().getPointer(); + break; + default: + result._error = "too many argument types for a function type"; + break; + } + + switch (return_type_result._types.size()) + { + case 0: + return_clang_type = swift::TupleType::getEmpty(*ast); + break; + case 1: + return_clang_type = return_type_result._types.front().getPointer(); + break; + default: + result._error = "too many return types for a function type"; + break; + } + + if (arg_clang_type && return_clang_type) + { + result._types.push_back(swift::FunctionType::get(arg_clang_type, + return_clang_type, + swift::FunctionType::ExtInfo(). + withThrows(throws))); + } +} + +static void +VisitNodeGenericType (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult new_generic_context; + std::copy(generic_context._types.begin(), generic_context._types.end(), back_inserter(new_generic_context._types)); + for (swift::Demangle::Node::iterator pos = cur_node->begin(), end = cur_node->end(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Generics: + nodes.push_back(*pos); + VisitNode (ast, nodes, new_generic_context, generic_context, log); + break; + case swift::Demangle::Node::Kind::Type: + nodes.push_back(*pos); + VisitNode (ast, nodes, result, new_generic_context, log); + break; + default: + result._error = stringWithFormat("%s encountered in generic type children", SwiftDemangleNodeKindToCString(child_node_kind)); + break; + } + } +} + +static void +VisitNodeSetterGetter (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + VisitNodeResult decl_ctx_result; + std::string identifier; + VisitNodeResult type_result; + swift::Demangle::Node::Kind node_kind = cur_node->getKind(); + + for (swift::Demangle::Node::iterator pos = cur_node->begin(), end = cur_node->end(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Module: + case swift::Demangle::Node::Kind::Structure: + nodes.push_back(*pos); + VisitNode (ast, nodes, decl_ctx_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::Identifier: + identifier.assign((*pos)->getText()); + break; + case swift::Demangle::Node::Kind::Type: + nodes.push_back(*pos); + VisitNode (ast, nodes, type_result, generic_context, log); + break; + default: + result._error = stringWithFormat("%s encountered in generic type children", SwiftDemangleNodeKindToCString(child_node_kind)); + break; + } + } + + if (identifier == "subscript") + { + // Subscript setters and getters are named with the reserved word "subscript". + // Since there can be many subscripts for the same nominal type, we need to + // find the one matching the specified type. + + FindNamedDecls (ast, identifier, decl_ctx_result); + size_t num_decls = decl_ctx_result._decls.size(); + + if (num_decls == 0) + { + result._error = "Could not find a subscript decl"; + return; + } + + swift::SubscriptDecl *subscript_decl; + const swift::AnyFunctionType* type_func = type_result._types.front()->getAs(); + + swift::CanType type_result_type(type_func->getResult()->getDesugaredType()->getCanonicalType()); + swift::CanType type_input_type(type_func->getInput()->getDesugaredType()->getCanonicalType()); + + + swift::FuncDecl *identifier_func = nullptr; + + for (size_t i = 0; i < num_decls; i++) + { + subscript_decl = llvm::dyn_cast_or_null(decl_ctx_result._decls[i]); + if (subscript_decl) + { + switch (node_kind) + { + case swift::Demangle::Node::Kind::Getter: + identifier_func = subscript_decl->getGetter(); + break; + case swift::Demangle::Node::Kind::Setter: + identifier_func = subscript_decl->getGetter(); + break; + case swift::Demangle::Node::Kind::DidSet: + identifier_func = subscript_decl->getDidSetFunc(); + break; + case swift::Demangle::Node::Kind::WillSet: + identifier_func = subscript_decl->getWillSetFunc(); + break; + default: + identifier_func = nullptr; + break; + } + + if (identifier_func && identifier_func->getType()) + { + const swift::AnyFunctionType *identifier_func_type = identifier_func->getType()->getAs(); + if (identifier_func_type) + { + // Swift function types are formally functions that take the class and return the method, + // we have to strip off the first level of function call to compare against the type + // from the demangled name. + const swift::AnyFunctionType *identifier_uncurried_result = identifier_func_type->getResult()->getAs(); + if (identifier_uncurried_result) + { + swift::CanType identifier_result_type(identifier_uncurried_result->getResult()->getDesugaredType()->getCanonicalType()); + swift::CanType identifier_input_type(identifier_uncurried_result->getInput()->getDesugaredType()->getCanonicalType()); + if (identifier_result_type == type_result_type && + identifier_input_type == type_input_type) + { + break; + } + } + } + } + } + identifier_func = nullptr; + } + + if (identifier_func) + { + result._decls.push_back(identifier_func); + result._types.push_back(FixCallingConv(identifier_func, identifier_func->getType().getPointer())); + } + else + { + result._error = "could not find a matching subscript signature"; + } + } + else + { + // Otherwise this is a getter/setter/etc for a variable. Currently you can't write a getter/setter that + // takes a different type from the type of the variable. So there is only one possible function. + swift::AbstractStorageDecl *var_decl = nullptr; + + FindFirstNamedDeclWithKind(ast, identifier, swift::DeclKind::Var, decl_ctx_result); + + if (decl_ctx_result._decls.size() == 1) + { + var_decl = llvm::dyn_cast_or_null(decl_ctx_result._decls[0]); + } + else if (decl_ctx_result._decls.size() > 0) + { + // TODO: can we use the type to pick the right one? can we really have multiple variables with the same name? + result._error = stringWithFormat("multiple variables with the same name %s",identifier.c_str()); + return; + } + else + { + result._error =stringWithFormat("no variables with the name %s",identifier.c_str()); + return; + } + + if (var_decl) + { + swift::FuncDecl *decl = nullptr; + + if (node_kind == swift::Demangle::Node::Kind::DidSet && var_decl->getDidSetFunc()) + { + decl = var_decl->getDidSetFunc(); + } + else if (node_kind == swift::Demangle::Node::Kind::Getter && var_decl->getGetter()) + { + decl = var_decl->getGetter(); + } + else if (node_kind == swift::Demangle::Node::Kind::Setter && var_decl->getSetter()) + { + decl = var_decl->getSetter(); + } + else if (node_kind == swift::Demangle::Node::Kind::WillSet && var_decl->getWillSetFunc()) + { + decl = var_decl->getWillSetFunc(); + } + + if (decl) + { + result._decls.push_back(decl); + result._types.push_back(FixCallingConv(decl, decl->getType().getPointer())); + } + else + { + result._error = stringWithFormat("could not retrieve %s for variable %s", + SwiftDemangleNodeKindToCString(node_kind), + identifier.c_str()); + return; + } + } + else + { + result._error = stringWithFormat("no decl object for %s", + identifier.c_str()); + return; + } + } +} + +static void +VisitNodeIdentifier (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + swift::Demangle::NodePointer parent_node = nodes[nodes.size() - 2]; + swift::DeclKind decl_kind = GetKindAsDeclKind (parent_node->getKind()); + + if (!FindFirstNamedDeclWithKind (ast, cur_node->getText(), decl_kind, result)) + { + if (result._error.empty()) + result._error = stringWithFormat("unable to find Node::Kind::Identifier '%s'", cur_node->getText().c_str()); + } +} + +static void +VisitNodeLocalDeclName (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + swift::Demangle::NodePointer parent_node = nodes[nodes.size() - 2]; + std::string remangledNode = swift::Demangle::mangleNode(parent_node); + swift::TypeDecl *decl = result._module.lookupLocalType(remangledNode); + if (!decl) + result._error = stringWithFormat("unable to lookup local type %s", + remangledNode.c_str()); + else + { + // if this were to come from a closure, there may be no decl - just a module + if (!result._decls.empty()) + result._decls.pop_back(); + if (!result._types.empty()) + result._types.pop_back(); + + result._decls.push_back(decl); + auto type = decl->getType(); + if (swift::MetatypeType *metatype = llvm::dyn_cast_or_null(type.getPointer())) + type = metatype->getInstanceType(); + result._types.push_back(type); + } +} + +static void +VisitNodePrivateDeclName (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + swift::Demangle::NodePointer parent_node = nodes[nodes.size() - 2]; + swift::DeclKind decl_kind = GetKindAsDeclKind (parent_node->getKind()); + + if (cur_node->getNumChildren() != 2) + { + if (result._error.empty()) + result._error = stringWithFormat("unable to retrieve content for Node::Kind::PrivateDeclName"); + return; + } + + swift::Demangle::NodePointer priv_decl_id_node (cur_node->getChild(0)); + swift::Demangle::NodePointer id_node (cur_node->getChild(1)); + + if (!priv_decl_id_node->hasText() || !id_node->hasText()) + { + if (result._error.empty()) + result._error = stringWithFormat("unable to retrieve content for Node::Kind::PrivateDeclName"); + return; + } + + if (!FindFirstNamedDeclWithKind (ast, id_node->getText(), decl_kind, result, priv_decl_id_node->getText())) + { + if (result._error.empty()) + result._error = stringWithFormat("unable to find Node::Kind::PrivateDeclName '%s' in '%s'", id_node->getText().c_str(), priv_decl_id_node->getText().c_str()); + } +} + +static void +VisitNodeInOut (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + nodes.push_back(cur_node->getFirstChild()); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result._types.size() == 1 && type_result._types[0]) + { + result._types.push_back(swift::Type(swift::LValueType::get(type_result._types[0]))); + } + else + { + result._error = "couldn't resolve referent type"; + } +} + +static void +VisitNodeMetatype (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + auto iter = cur_node->begin(); + auto end = cur_node->end(); + + llvm::Optional metatype_repr; + VisitNodeResult type_result; + + for (; iter != end; ++iter) + { + switch ((*iter)->getKind()) + { + case swift::Demangle::Node::Kind::Type: + nodes.push_back(*iter); + VisitNode(ast, nodes, type_result, generic_context, log); + break; + case swift::Demangle::Node::Kind::MetatypeRepresentation: + if ( (*iter)->getText() == "@thick" ) + metatype_repr = swift::MetatypeRepresentation::Thick; + else if ( (*iter)->getText() == "@thin" ) + metatype_repr = swift::MetatypeRepresentation::Thin; + else if ( (*iter)->getText() == "@objc" ) + metatype_repr = swift::MetatypeRepresentation::ObjC; + else + ; // leave it alone if we don't understand the representation + break; + default: + break; + } + + } + + if (type_result.HasSingleType()) + { + result._types.push_back(swift::MetatypeType::get(type_result._types[0], metatype_repr)); + } + else + { + result._error = stringWithFormat("instance type for metatype cannot be uniquely resolved"); + return; + } + +} + +static void +VisitNodeModule (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + std::string error; + const char *module_name = cur_node->getText().c_str(); + if (!module_name || *module_name == '\0') + { + result._error = stringWithFormat("error: empty module name."); + return; + } + + result._module = DeclsLookupSource::GetDeclsLookupSource(*ast, ConstString(module_name)); + if (!result._module) + { + result._error = stringWithFormat("unable to load module '%s' (%s)", + module_name, error.data()); + } +} + +static void +VisitNodeNonVariadicTuple (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() == cur_node->end()) + { + // No children of this tuple, make an empty tuple + + if (ast) + { + result._types.push_back(swift::TupleType::getEmpty(*ast)); + } + else + { + result._error = "invalid ASTContext"; + } + } + else + { + std::vector tuple_fields; + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + nodes.push_back(*pos); + VisitNodeResult tuple_element_result; + VisitNode (ast, nodes, tuple_element_result, generic_context, log); + if (tuple_element_result._error.empty() && tuple_element_result._tuple_type_element.getType()) + { + tuple_fields.push_back(tuple_element_result._tuple_type_element); + } + else + { + result._error = tuple_element_result._error; + } + } + if (result._error.empty()) + { + if (ast) + { + result._types.push_back(swift::TupleType::get(tuple_fields, *ast)); + } + else + { + result._error = "invalid ASTContext"; + } + } + } +} + +static void +VisitNodeProtocolList (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() != cur_node->end()) + { + VisitNodeResult protocol_types_result; + nodes.push_back(cur_node->getFirstChild()); + VisitNode (ast, nodes, protocol_types_result, generic_context, log); + if (protocol_types_result._error.empty() /* cannot check for empty type list as protocol<> is allowed */) + { + if (ast) + { + result._types.push_back(swift::ProtocolCompositionType::get(*ast, protocol_types_result._types)); + } + else + { + result._error = "invalid ASTContext"; + } + } + } +} + +static void +VisitNodeQualifiedArchetype (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() != cur_node->end()) + { + swift::Demangle::Node::iterator end = cur_node->end(); + VisitNodeResult type_result; + uint64_t index = 0xFFFFFFFFFFFFFFFF; + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + switch (pos->get()->getKind()) + { + case swift::Demangle::Node::Kind::Number: + index = pos->get()->getIndex(); + break; + case swift::Demangle::Node::Kind::DeclContext: + nodes.push_back(*pos); + VisitNode (ast, nodes, type_result, generic_context, log); + break; + default: + break; + } + } + if (index != 0xFFFFFFFFFFFFFFFF) + { + if (type_result._types.size() == 1 && type_result._decls.size() == 1) + { + // given a method defined as func ... (args) -> (ret) {...} + // the Swift type system represents it as + // (SomeTypeMoniker) -> (args) -> (ret), where SomeTypeMoniker is an appropriately crafted + // reference to the type that contains the method (e.g. for a struct, an @inout StructType) + // For a qualified archetype of a method, we do not care about the first-level function, but about + // the returned function, which is the thing whose archetypes we truly care to extract + // TODO: this might be a generally useful operation, but it requires a Decl as well as a type + // to be reliably performed, and as such we cannot just put it in CompilerType as of now + // (consider, func foo (@inout StructType) -> (Int) -> () vs struct StructType {func foo(Int) -> ()} to see why) + swift::TypeBase *type_ptr = type_result._types[0].getPointer(); + swift::Decl* decl_ptr = type_result._decls[0]; + // if this is a function... + if (type_ptr && type_ptr->is()) + { + // if this is defined in a type... + if (decl_ptr->getDeclContext()->isTypeContext()) + { + // if I can get the function type from it + if (auto func_type = llvm::dyn_cast_or_null(type_ptr)) + { + // and it has a return type which is itself a function + auto return_func_type = llvm::dyn_cast_or_null(func_type->getResult().getPointer()); + if (return_func_type) + type_ptr = return_func_type; // then use IT as our source of archetypes + } + } + } + swift::TypeBase *arg_type = GetTemplateArgument(type_ptr, index); + result._types.push_back(swift::Type(arg_type)); + } + else if (type_result._module.IsExtension()) + { + result._types.push_back(type_result._module.GetQualifiedArchetype(index, ast)); + } + } + } +} + +static void +VisitNodeSelfTypeRef (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + nodes.push_back(cur_node->getFirstChild()); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result.HasSingleType()) + { + swift::Type supposed_protocol_type(type_result.GetFirstType()); + swift::ProtocolType *protocol_type = supposed_protocol_type->getAs(); + swift::ProtocolDecl *protocol_decl = protocol_type ? protocol_type->getDecl() : nullptr; + if (protocol_decl) + { + swift::ArchetypeType::AssocTypeOrProtocolType assoc_protocol_type(protocol_decl); + if (ast) + { + swift::CanTypeWrapper self_type = swift::ArchetypeType::getNew(*ast, + nullptr, + assoc_protocol_type, + ast->getIdentifier("Self"), + {supposed_protocol_type}, + swift::Type(), + false); + if (self_type.getPointer()) + result._types.push_back(swift::Type(self_type)); + else + result._error = "referent type cannot be made into an archetype"; + } + else + { + result._error = "invalid ASTContext"; + } + } + else + { + result._error = "referent type does not resolve to a protocol"; + } + } + else + { + result._error = "couldn't resolve referent type"; + } +} + +static void +VisitNodeTupleElement (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + const char *tuple_name = NULL; + VisitNodeResult tuple_type_result; + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + const swift::Demangle::Node::Kind child_node_kind = (*pos)->getKind(); + switch (child_node_kind) + { + case swift::Demangle::Node::Kind::TupleElementName: + tuple_name = (*pos)->getText().c_str(); + break; + case swift::Demangle::Node::Kind::Type: + nodes.push_back((*pos)->getFirstChild()); + VisitNode (ast, nodes, tuple_type_result, generic_context, log); + break; + default: + break; + } + } + + if (tuple_type_result._error.empty() && tuple_type_result._types.size() == 1) + { + if (tuple_name) + result._tuple_type_element = swift::TupleTypeElt(tuple_type_result._types.front().getPointer(), + ast->getIdentifier(tuple_name)); + else + result._tuple_type_element = swift::TupleTypeElt(tuple_type_result._types.front().getPointer()); + } +} + +static void +VisitNodeTypeList (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() != cur_node->end()) + { + swift::Demangle::Node::iterator end = cur_node->end(); + for (swift::Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) + { + nodes.push_back(*pos); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result._error.empty() && type_result._types.size() == 1) + { + if (type_result._decls.empty()) + result._decls.push_back(NULL); + else + result._decls.push_back(type_result._decls.front()); + result._types.push_back(type_result._types.front()); + } + else + { + result._error = type_result._error; + } + } + } +} + +static void +VisitNodeUnowned (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + nodes.push_back(cur_node->getFirstChild()); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result._types.size() == 1 && type_result._types[0]) + { + if (ast) + { + result._types.push_back(swift::Type(swift::UnownedStorageType::get(type_result._types[0], + *ast))); + } + else + { + result._error = "invalid ASTContext"; + } + } + else + { + result._error = "couldn't resolve referent type"; + } +} + +static void +VisitNodeWeak (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + nodes.push_back(cur_node->getFirstChild()); + VisitNodeResult type_result; + VisitNode (ast, nodes, type_result, generic_context, log); + if (type_result._types.size() == 1 && type_result._types[0]) + { + if (ast) + { + result._types.push_back(swift::Type(swift::WeakStorageType::get(type_result._types[0], + *ast))); + } + else + { + result._error = "invalid ASTContext"; + } + } + else + { + result._error = "couldn't resolve referent type"; + } +} + +static void +VisitFirstChildNode (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (cur_node->begin() != cur_node->end()) + { + nodes.push_back(cur_node->getFirstChild()); + VisitNode (ast, nodes, result, generic_context, log); + } +} + +static void +VisitAllChildNodes (SwiftASTContext *ast, + std::vector &nodes, + swift::Demangle::NodePointer& cur_node, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + swift::Demangle::Node::iterator child_end = cur_node->end(); + for (swift::Demangle::Node::iterator child_pos = cur_node->begin(); child_pos != child_end; ++child_pos) + { + nodes.push_back(*child_pos); + VisitNode (ast, nodes, result, generic_context, log); + } +} + +static void +VisitNode (SwiftASTContext *ast, + std::vector &nodes, + VisitNodeResult &result, + const VisitNodeResult &generic_context, // set by GenericType case + Log *log) +{ + if (nodes.empty()) + result._error = "no node"; + else if (nodes.back() == nullptr) + result._error = "last node is NULL"; + else + result._error = ""; + + if (result._error.empty()) + { + swift::Demangle::NodePointer node = nodes.back(); + const swift::Demangle::Node::Kind node_kind = node->getKind(); + + switch (node_kind) + { + case swift::Demangle::Node::Kind::OwningAddressor: + case swift::Demangle::Node::Kind::OwningMutableAddressor: + case swift::Demangle::Node::Kind::UnsafeAddressor: + case swift::Demangle::Node::Kind::UnsafeMutableAddressor: + VisitNodeAddressor (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Generics: + VisitNodeGenerics (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::ArchetypeRef: + VisitNodeArchetypeRef (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Archetype: + VisitNodeArchetype (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::ArgumentTuple: + VisitFirstChildNode (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::AssociatedTypeRef: + VisitNodeAssociatedTypeRef (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::BoundGenericClass: + case swift::Demangle::Node::Kind::BoundGenericStructure: + case swift::Demangle::Node::Kind::BoundGenericEnum: + VisitNodeBoundGeneric (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::BuiltinTypeName: + VisitNodeBuiltinTypeName (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Structure: + case swift::Demangle::Node::Kind::Class: + case swift::Demangle::Node::Kind::Enum: + case swift::Demangle::Node::Kind::Global: + case swift::Demangle::Node::Kind::Static: + case swift::Demangle::Node::Kind::TypeAlias: + case swift::Demangle::Node::Kind::Type: + case swift::Demangle::Node::Kind::TypeMangling: + case swift::Demangle::Node::Kind::ReturnType: + case swift::Demangle::Node::Kind::Protocol: + VisitAllChildNodes (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Constructor: + VisitNodeConstructor (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Destructor: + VisitNodeDestructor (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::DeclContext: + VisitNodeDeclContext (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::ErrorType: + result._error = "error type encountered while demangling name"; + break; + + case swift::Demangle::Node::Kind::Extension: + VisitNodeExtension(ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::ExplicitClosure: + VisitNodeExplicitClosure (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Function: + case swift::Demangle::Node::Kind::Allocator: + case swift::Demangle::Node::Kind::Variable: // Out of order on purpose + VisitNodeFunction (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::FunctionType: + case swift::Demangle::Node::Kind::UncurriedFunctionType: // Out of order on purpose. + VisitNodeFunctionType (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::GenericType: + VisitNodeGenericType (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::DidSet: + case swift::Demangle::Node::Kind::Getter: + case swift::Demangle::Node::Kind::Setter: + case swift::Demangle::Node::Kind::WillSet: // out of order on purpose + VisitNodeSetterGetter (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::LocalDeclName: + VisitNodeLocalDeclName(ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Identifier: + VisitNodeIdentifier (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::InOut: + VisitNodeInOut (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Metatype: + VisitNodeMetatype (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Module: + VisitNodeModule (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::NonVariadicTuple: + VisitNodeNonVariadicTuple (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::PrivateDeclName: + VisitNodePrivateDeclName(ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::ProtocolList: + VisitNodeProtocolList (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::QualifiedArchetype: + VisitNodeQualifiedArchetype (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::SelfTypeRef: + VisitNodeSelfTypeRef (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::TupleElement: + VisitNodeTupleElement (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::TypeList: + VisitNodeTypeList (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Unowned: + VisitNodeUnowned (ast, nodes, node, result, generic_context, log); + break; + + case swift::Demangle::Node::Kind::Weak: + VisitNodeWeak (ast, nodes, node, result, generic_context, log); + break; + default: + break; + } + } + nodes.pop_back(); +} + +swift::Type swift::ide::getTypeFromMangledTypename(swift::ASTContext &Ctx, + const char *mangled_typename, + std::string &error) +{ + ConstString mangled_name (mangled_typename); + std::vector nodes; + nodes.push_back(swift::Demangle::demangleTypeAsNode(mangled_typename, + mangled_name.length())); + VisitNodeResult empty_generic_context; + VisitNodeResult result; + + VisitNode(&Ctx, nodes, result, empty_generic_context, nullptr); + error = result._error; + if (error.empty() && result._types.size() == 1) + { + return result._types.front().getPointer(); + } + else + { + error = stringWithFormat("type for typename '%s' was not found",mangled_typename); + return swift::Type(); + } + return swift::Type(); +} + +swift::Type swift::ide::getTypeFromMangledSymbolname(swift::ASTContext &Ctx, + const char *mangled_typename, + std::string &error) +{ + ConstString mangled_name (mangled_typename); + std::vector nodes; + nodes.push_back(swift::Demangle::demangleSymbolAsNode(mangled_typename, + mangled_name.length())); + VisitNodeResult empty_generic_context; + VisitNodeResult result; + + VisitNode(&Ctx, nodes, result, empty_generic_context, nullptr); + error = result._error; + if (error.empty() && result._types.size() == 1) + { + return result._types.front().getPointer(); + } + else + { + error = stringWithFormat("type for symbolname '%s' was not found",mangled_typename); + return swift::Type(); + } + return swift::Type(); +} diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index 0a1b20d37e6ba..a36068c8cd848 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -1,8 +1,8 @@ -//===- SourceEntityWalker.cpp - Routines for semantic source info ---------===// +//===--- SourceEntityWalker.cpp - Routines for semantic source info -------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,6 +12,7 @@ #include "swift/IDE/SourceEntityWalker.h" #include "swift/IDE/Utils.h" +#include "swift/Parse/Lexer.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" @@ -61,7 +62,7 @@ class SemaAnnotator : public ASTWalker { bool passModulePathElements(ArrayRef Path, const clang::Module *ClangMod); - bool passReference(ValueDecl *D, Type Ty, SourceLoc Loc); + bool passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc); bool passReference(ModuleEntity Mod, std::pair IdLoc); bool passSubscriptReference(ValueDecl *D, SourceLoc Loc, bool IsOpenBracket); @@ -198,16 +199,19 @@ std::pair SemaAnnotator::walkToExprPre(Expr *E) { if (DeclRefExpr *DRE = dyn_cast(E)) { if (auto *module = dyn_cast(DRE->getDecl())) { - if (!passReference(ModuleEntity(module), std::make_pair(module->getName(), E->getLoc()))) + if (!passReference(ModuleEntity(module), + std::make_pair(module->getName(), E->getLoc()))) return { false, nullptr }; - } else if (!passReference(DRE->getDecl(), DRE->getType(), E->getLoc())) { + } else if (!passReference(DRE->getDecl(), DRE->getType(), + DRE->getNameLoc())) { return { false, nullptr }; } } else if (MemberRefExpr *MRE = dyn_cast(E)) { // Visit in source order. if (!MRE->getBase()->walk(*this)) return { false, nullptr }; - if (!passReference(MRE->getMember().getDecl(), MRE->getType(), E->getLoc())) + if (!passReference(MRE->getMember().getDecl(), MRE->getType(), + MRE->getNameLoc())) return { false, nullptr }; // We already visited the children. @@ -281,7 +285,7 @@ bool SemaAnnotator::walkToTypeReprPre(TypeRepr *T) { return passReference(ModD, std::make_pair(IdT->getIdentifier(), IdT->getIdLoc())); - return passReference(VD, Type(), IdT->getIdLoc()); + return passReference(VD, Type(), DeclNameLoc(IdT->getIdLoc())); } } return true; @@ -332,7 +336,8 @@ bool SemaAnnotator::handleImports(ImportDecl *Import) { auto Decls = Import->getDecls(); if (Decls.size() == 1) { - if (!passReference(Decls.front(), Type(), Import->getEndLoc())) + // FIXME: ImportDecl should store a DeclNameLoc. + if (!passReference(Decls.front(), Type(), DeclNameLoc(Import->getEndLoc()))) return false; } @@ -364,22 +369,22 @@ bool SemaAnnotator::passSubscriptReference(ValueDecl *D, SourceLoc Loc, return Continue; } -bool SemaAnnotator::passReference(ValueDecl *D, Type Ty, SourceLoc Loc) { - unsigned NameLen = D->getName().getLength(); +bool SemaAnnotator::passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc) { TypeDecl *CtorTyRef = nullptr; if (TypeDecl *TD = dyn_cast(D)) { if (!CtorRefs.empty() && Loc.isValid()) { Expr *Fn = CtorRefs.back()->getFn(); - if (Fn->getLoc() == Loc) { + if (Fn->getLoc() == Loc.getBaseNameLoc()) { D = extractDecl(Fn); CtorTyRef = TD; } } } - CharSourceRange Range = (Loc.isValid()) ? CharSourceRange(Loc, NameLen) - : CharSourceRange(); + CharSourceRange Range = + Lexer::getCharSourceRangeFromSourceRange(D->getASTContext().SourceMgr, + Loc.getSourceRange()); bool Continue = SEWalker.visitDeclReference(D, Range, CtorTyRef, Ty); if (!Continue) Cancelled = true; @@ -460,7 +465,7 @@ bool SourceEntityWalker::visitSubscriptReference(ValueDecl *D, CharSourceRange Range, bool IsOpenBracket) { // Most of the clients treat subscript reference the same way as a - // regular reference when called on the open open bracket and + // regular reference when called on the open bracket and // ignore the closing one. return IsOpenBracket ? visitDeclReference(D, Range, nullptr, Type()) : true; } diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 21e123174a769..70ab7e7bff641 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -1,8 +1,8 @@ -//===- SyntaxModel.cpp - Routines for IDE syntax model --------------------===// +//===--- SyntaxModel.cpp - Routines for IDE syntax model ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -48,6 +48,7 @@ struct SyntaxModelContext::Implementation { SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) : Impl(*new Implementation(SrcFile)) { + const bool IsPlayground = Impl.LangOpts.Playground; const SourceManager &SM = Impl.SrcMgr; std::vector Tokens = swift::tokenize(Impl.LangOpts, SM, *Impl.SrcFile.getBufferID(), @@ -97,6 +98,7 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) #define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break; #include "swift/Parse/Tokens.def" #undef KEYWORD + case tok::pound_selector: Kind = SyntaxNodeKind::Keyword; break; case tok::pound_line: case tok::pound_available: Kind = SyntaxNodeKind::BuildConfigKeyword; break; @@ -111,9 +113,11 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) case tok::floating_literal: Kind = SyntaxNodeKind::Floating; break; case tok::string_literal: Kind = SyntaxNodeKind::String; break; case tok::comment: - if (Tok.getText().startswith("///")) + if (Tok.getText().startswith("///") || + (IsPlayground && Tok.getText().startswith("//:"))) Kind = SyntaxNodeKind::DocCommentLine; - else if (Tok.getText().startswith("/**")) + else if (Tok.getText().startswith("/**") || + (IsPlayground && Tok.getText().startswith("/*:"))) Kind = SyntaxNodeKind::DocCommentBlock; else if (Tok.getText().startswith("//")) Kind = SyntaxNodeKind::CommentLine; @@ -994,7 +998,7 @@ class IdRefWalker : public ASTWalker { if (DRE->getRefKind() != DeclRefKind::Ordinary) return { true, E }; if (!Fn(CharSourceRange(DRE->getSourceRange().Start, - DRE->getName().getLength()))) + DRE->getName().getBaseName().getLength()))) return { false, nullptr }; } return { true, E }; diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 8842ecc9f9e9c..b84b02e492ae7 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -119,7 +119,7 @@ ide::isSourceInputComplete(std::unique_ptr MemBuf) { const char *SourceStart = Buffer.data(); const char *SourceEnd = Buffer.data() + Buffer.size(); const char *LineStart = SourceStart; - const char *LineSourceStart = NULL; + const char *LineSourceStart = nullptr; uint32_t LineIndent = 0; struct IndentInfo { StringRef Prefix; @@ -134,7 +134,7 @@ ide::isSourceInputComplete(std::unique_ptr MemBuf) { case '\r': case '\n': LineIndent = 0; - LineSourceStart = NULL; + LineSourceStart = nullptr; LineStart = p + 1; break; @@ -146,7 +146,7 @@ ide::isSourceInputComplete(std::unique_ptr MemBuf) { case '(': case '[': ++LineIndent; - if (LineSourceStart == NULL) + if (LineSourceStart == nullptr) IndentInfos.push_back(IndentInfo(LineStart, p - LineStart, LineIndent)); @@ -166,7 +166,7 @@ ide::isSourceInputComplete(std::unique_ptr MemBuf) { break; default: - if (LineSourceStart == NULL && !isspace(*p)) + if (LineSourceStart == nullptr && !isspace(*p)) LineSourceStart = p; break; } @@ -189,7 +189,7 @@ SourceCompleteResult ide::isSourceInputComplete(StringRef Text) { } // Adjust the cc1 triple string we got from clang, to make sure it will be -// accepted when it goes throught the swift clang importer. +// accepted when it goes through the swift clang importer. static std::string adjustClangTriple(StringRef TripleStr) { std::string Result; llvm::raw_string_ostream OS(Result); @@ -202,6 +202,14 @@ static std::string adjustClangTriple(StringRef TripleStr) { OS << "armv7s"; break; case llvm::Triple::SubArchType::ARMSubArch_v7k: OS << "armv7k"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6: + OS << "armv6"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6m: + OS << "armv6m"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6k: + OS << "armv6k"; break; + case llvm::Triple::SubArchType::ARMSubArch_v6t2: + OS << "armv6t2"; break; default: // Adjust i386-macosx to x86_64 because there is no Swift stdlib for i386. if ((Triple.getOS() == llvm::Triple::MacOSX || diff --git a/lib/IRGen/Address.h b/lib/IRGen/Address.h index d7596ae2e063f..a8daaf98b4d01 100644 --- a/lib/IRGen/Address.h +++ b/lib/IRGen/Address.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -91,7 +91,7 @@ class ContainedAddress { /// The address of an object of type T. Address Addr; - /// The address of an object of [local_storage] T. + /// The container of the address. Address Container; public: diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index 2fb21697f1370..e907d44a42a2f 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -30,10 +30,10 @@ add_swift_library(swiftIRGen IRGenModule.cpp IRGenSIL.cpp Linking.cpp + LocalTypeData.cpp SwiftTargetInfo.cpp StructLayout.cpp TypeLayoutVerifier.cpp - UnimplementedTypeInfo.cpp LINK_LIBRARIES swiftAST swiftLLVMPasses diff --git a/lib/IRGen/CallEmission.h b/lib/IRGen/CallEmission.h index 19235618d9dc6..b5facbcb9fbe9 100644 --- a/lib/IRGen/CallEmission.h +++ b/lib/IRGen/CallEmission.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/Callee.h b/lib/IRGen/Callee.h index 80ed4fc85e8ba..c5264d9380c4c 100644 --- a/lib/IRGen/Callee.h +++ b/lib/IRGen/Callee.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/CallingConvention.h b/lib/IRGen/CallingConvention.h index c3a041ad7d442..1d67de03bd804 100644 --- a/lib/IRGen/CallingConvention.h +++ b/lib/IRGen/CallingConvention.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/ClassMetadataLayout.h b/lib/IRGen/ClassMetadataLayout.h index 7612218f4cd3b..492454cf6da63 100644 --- a/lib/IRGen/ClassMetadataLayout.h +++ b/lib/IRGen/ClassMetadataLayout.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -84,7 +84,13 @@ template class ClassMetadataLayout : public MetadataLayout { // consistent metadata layout between generic superclasses and concrete // subclasses. if (Type superclass = theClass->getSuperclass()) { - addClassMembers(superclass->getClassOrBoundGenericClass()); + ClassDecl *superclassDecl = superclass->getClassOrBoundGenericClass(); + // Skip superclass fields if superclass is resilient. + // FIXME: Needs runtime support to ensure the field offset vector is + // populated correctly. + if (!IGM.isResilient(superclassDecl, ResilienceExpansion::Maximal)) { + addClassMembers(superclass->getClassOrBoundGenericClass()); + } } // Add a reference to the parent class, if applicable. diff --git a/lib/IRGen/DebugTypeInfo.cpp b/lib/IRGen/DebugTypeInfo.cpp index 0bbbd95cb4c98..fc2cf5b81a192 100644 --- a/lib/IRGen/DebugTypeInfo.cpp +++ b/lib/IRGen/DebugTypeInfo.cpp @@ -1,8 +1,8 @@ -//===--- DebugTypeInfo.h - Type Info for Debugging --------------*- C++ -*-===// +//===--- DebugTypeInfo.cpp - Type Info for Debugging ----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -114,6 +114,21 @@ DebugTypeInfo::DebugTypeInfo(ValueDecl *Decl, swift::Type Ty, initFromTypeInfo(size, align, StorageType, Info); } +DebugTypeInfo::DebugTypeInfo(ValueDecl *Decl, swift::Type Ty, + llvm::Type *StorageTy, + Size size, Alignment align) + : DeclOrContext(Decl), + StorageType(StorageTy), + size(size), + align(align) { + // Prefer the original, potentially sugared version of the type if + // the type hasn't been mucked with by an optimization pass. + if (Decl->getType().getCanonicalTypeOrNull() == Ty.getCanonicalTypeOrNull()) + Type = Decl->getType().getPointer(); + else + Type = Ty.getPointer(); +} + static bool typesEqual(Type A, Type B) { if (A.getPointer() == B.getPointer()) return true; diff --git a/lib/IRGen/DebugTypeInfo.h b/lib/IRGen/DebugTypeInfo.h index b452058c00b60..fbb246572808d 100644 --- a/lib/IRGen/DebugTypeInfo.h +++ b/lib/IRGen/DebugTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,93 +18,108 @@ #ifndef SWIFT_IRGEN_DEBUGTYPEINFO_H #define SWIFT_IRGEN_DEBUGTYPEINFO_H -#include "swift/AST/Types.h" -#include "swift/AST/Decl.h" #include "IRGen.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Types.h" namespace llvm { - class Type; +class Type; } namespace swift { - class SILDebugScope; - - namespace irgen { - class TypeInfo; - - /// This data structure holds everything needed to emit debug info - /// for a type. - class DebugTypeInfo { - public: - /// The Decl holds the DeclContext, location, but also allows to - /// look up struct members. If there is no Decl, generic types - /// mandate there be at least a DeclContext. - PointerUnion DeclOrContext; - /// The type we need to emit may be different from the type - /// mentioned in the Decl, for example, stripped of qualifiers. - TypeBase *Type; - /// Needed to determine the size of basic types and to determine - /// the storage type for undefined variables. - llvm::Type *StorageType; - Size size; - Alignment align; - - DebugTypeInfo() - : Type(nullptr), StorageType(nullptr), size(0), align(1) {} - DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy, - uint64_t SizeInBytes, uint32_t AlignInBytes, - DeclContext *DC); - DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy, - Size size, Alignment align, DeclContext *DC); - DebugTypeInfo(swift::Type Ty, const TypeInfo &Info, DeclContext *DC); - DebugTypeInfo(ValueDecl *Decl, const TypeInfo &Info); - DebugTypeInfo(ValueDecl *Decl, llvm::Type *StorageType, - Size size, Alignment align); - DebugTypeInfo(ValueDecl *Decl, swift::Type Ty, const TypeInfo &Info); - TypeBase* getType() const { return Type; } - - ValueDecl* getDecl() const { - return DeclOrContext.dyn_cast(); - } - - DeclContext *getDeclContext() const { - if (ValueDecl *D = getDecl()) return D->getDeclContext(); - else return DeclOrContext.get(); - } - - void unwrapLValueOrInOutType() { - Type = Type->getLValueOrInOutObjectType().getPointer(); - } - - bool isNull() const { return Type == nullptr; } - bool operator==(DebugTypeInfo T) const; - bool operator!=(DebugTypeInfo T) const; - - void dump() const; - }; +class SILDebugScope; + +namespace irgen { +class TypeInfo; + +/// This data structure holds everything needed to emit debug info +/// for a type. +class DebugTypeInfo { +public: + /// The Decl holds the DeclContext, location, but also allows to + /// look up struct members. If there is no Decl, generic types + /// mandate there be at least a DeclContext. + PointerUnion DeclOrContext; + /// The type we need to emit may be different from the type + /// mentioned in the Decl, for example, stripped of qualifiers. + TypeBase *Type; + /// Needed to determine the size of basic types and to determine + /// the storage type for undefined variables. + llvm::Type *StorageType; + Size size; + Alignment align; + + // FIXME: feels like there might be too many constructors here + + DebugTypeInfo() : Type(nullptr), StorageType(nullptr), size(0), align(1) {} + DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy, uint64_t SizeInBytes, + uint32_t AlignInBytes, DeclContext *DC); + DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy, Size size, + Alignment align, DeclContext *DC); + DebugTypeInfo(swift::Type Ty, const TypeInfo &Info, DeclContext *DC); + DebugTypeInfo(ValueDecl *Decl, const TypeInfo &Info); + DebugTypeInfo(ValueDecl *Decl, llvm::Type *StorageType, Size size, + Alignment align); + DebugTypeInfo(ValueDecl *Decl, swift::Type Ty, const TypeInfo &Info); + DebugTypeInfo(ValueDecl *Decl, swift::Type Ty, + llvm::Type *StorageType, Size size, + Alignment align); + TypeBase *getType() const { return Type; } + + ValueDecl *getDecl() const { return DeclOrContext.dyn_cast(); } + + DeclContext *getDeclContext() const { + if (ValueDecl *D = getDecl()) + return D->getDeclContext(); + else + return DeclOrContext.get(); + } + + void unwrapLValueOrInOutType() { + Type = Type->getLValueOrInOutObjectType().getPointer(); + } + + // Determine whether this type is an Archetype itself. + bool isArchetype() const { + return Type->getLValueOrInOutObjectType()->getKind() == TypeKind::Archetype; + } + + /// LValues, inout args, and Archetypes are implicitly indirect by + /// virtue of their DWARF type. + bool isImplicitlyIndirect() const { + return Type->isLValueType() || isArchetype() || + (Type->getKind() == TypeKind::InOut); } + + bool isNull() const { return Type == nullptr; } + bool operator==(DebugTypeInfo T) const; + bool operator!=(DebugTypeInfo T) const; + + void dump() const; +}; +} } namespace llvm { - // Dense map specialization. - template<> struct DenseMapInfo { - static swift::irgen::DebugTypeInfo getEmptyKey() { - return swift::irgen::DebugTypeInfo(); - } - static swift::irgen::DebugTypeInfo getTombstoneKey() { - return swift::irgen::DebugTypeInfo(llvm::DenseMapInfo - ::getTombstoneKey(), nullptr, 0, 0, 0); - } - static unsigned getHashValue(swift::irgen::DebugTypeInfo Val) { - return DenseMapInfo::getHashValue(Val.getType()); - } - static bool isEqual(swift::irgen::DebugTypeInfo LHS, - swift::irgen::DebugTypeInfo RHS) { - return LHS == RHS; - } - }; - +// Dense map specialization. +template <> struct DenseMapInfo { + static swift::irgen::DebugTypeInfo getEmptyKey() { + return swift::irgen::DebugTypeInfo(); + } + static swift::irgen::DebugTypeInfo getTombstoneKey() { + return swift::irgen::DebugTypeInfo( + llvm::DenseMapInfo::getTombstoneKey(), nullptr, 0, 0, + 0); + } + static unsigned getHashValue(swift::irgen::DebugTypeInfo Val) { + return DenseMapInfo::getHashValue(Val.getType()); + } + static bool isEqual(swift::irgen::DebugTypeInfo LHS, + swift::irgen::DebugTypeInfo RHS) { + return LHS == RHS; + } +}; } #endif diff --git a/lib/IRGen/DominancePoint.h b/lib/IRGen/DominancePoint.h new file mode 100644 index 0000000000000..d2df06f8429ed --- /dev/null +++ b/lib/IRGen/DominancePoint.h @@ -0,0 +1,77 @@ +//===--- DominancePoint.h - Dominance points --------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines types relating to local dominance calculations +// during the emission of a function. +// +// During the emission of a function, the LLVM IR is not well-formed enough +// to do accurate dominance computations. For example, a basic block may +// appear to have a single predecessor, but that may be because a different +// predecessor has not yet been added. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_DOMINANCEPOINT_H +#define SWIFT_IRGEN_DOMINANCEPOINT_H + +#include +#include + +namespace swift { +namespace irgen { + class IRGenFunction; + +/// An opaque class for storing keys for the dominance callback. The +/// key is assumed to be something like a (uniqued) pointer, and a +/// null pointer is assumed to mean a non-dominating point. +class DominancePoint { + uintptr_t Value; + enum : uintptr_t { + Universal = 0, + }; + explicit DominancePoint(uintptr_t value) : Value(value) {} +public: + explicit DominancePoint(void *value) + : Value(reinterpret_cast(value)) { + assert(isOrdinary()); + } + + /// Something about the definition is known to dominate all possible + /// places that will use it. + static DominancePoint universal() { return DominancePoint(Universal); } + + bool isOrdinary() const { + return Value != Universal; + } + bool isUniversal() const { + return Value == Universal; + } + + template T* as() const { + assert(isOrdinary()); + return reinterpret_cast(Value); + } + bool operator==(DominancePoint other) const { return Value == other.Value; } +}; + +/// A dominance resolver is a function that answers the question of +/// whether one dominance point dominates another. +/// +/// It will only be asked this question with ordinary dominance points. +using DominanceResolverFunction = bool(*)(IRGenFunction &IGF, + DominancePoint curPoint, + DominancePoint definingPoint); + +} +} + +#endif diff --git a/lib/IRGen/DominanceScope.h b/lib/IRGen/DominanceScope.h new file mode 100644 index 0000000000000..97ebeebd5b5c1 --- /dev/null +++ b/lib/IRGen/DominanceScope.h @@ -0,0 +1,82 @@ +//===--- DominanceScope.h - Dominance scoping -------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines types relating to local dominance calculations +// during the emission of a function. +// +// During the emission of a function, the LLVM IR is not well-formed enough +// to do accurate dominance computations. For example, a basic block may +// appear to have a single predecessor, but that may be because a different +// predecessor has not yet been added. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_DOMINANCEPOINT_H +#define SWIFT_IRGEN_DOMINANCEPOINT_H + +#include + +namespace swift { +namespace irgen { + class IRGenFunction; + +/// An opaque class for storing keys for the dominance callback. The +/// key is assumed to be something like a (uniqued) pointer, and a +/// null pointer is assumed to mean a non-dominating point. +class DominancePoint { + uintptr_t Value; + enum : uintptr_t { + Universal = 0, + Unknown = 1, + }; + explicit DominancePoint(uintptr_t value) : Value(value) {} +public: + explicit DominancePoint(void *value) + : Value(reinterpret_cast(value)) { + assert(isOrdinary()); + } + + /// Something about the definition is known to dominate all possible + /// places that will use it. + static DominancePoint universal() { return DominanceKey(Universal); } + + /// This definition point has non-obvious dominance rules; don't put + /// anything here and assume it'll dominate other things. This should be + /// used when IRGen adds its own control flow that might interact awkwardly + /// with dominance. + static DominancePoint unknown() { return DominanceKey(Unknown); } + + bool isOrdinary() { + return Value > Uncacheable; + } + bool isUniversal() { + return Value == Universal; + } + bool isUnknown() { + return Value == Unknown; + } + + template T* as() const { + assert(isOrdinary()); + return reinterpret_cast(Value); + } + bool operator==(DominancePoint other) const { return Value == other.Value; } +}; + +using DominanceResolverFunction = bool(*)(IRGenFunction &IGF, + DominancePoint curPoint, + DominancePoint definingPoint); + +} +} + +#endif diff --git a/lib/IRGen/EnumMetadataLayout.h b/lib/IRGen/EnumMetadataLayout.h index 2dbd65307f9b3..adb228a178983 100644 --- a/lib/IRGen/EnumMetadataLayout.h +++ b/lib/IRGen/EnumMetadataLayout.h @@ -1,8 +1,8 @@ -//===--- EnumMetadataLayout.h - CRTP for enum metadata ------*- C++ -*-===// +//===--- EnumMetadataLayout.h - CRTP for enum metadata ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/EnumPayload.cpp b/lib/IRGen/EnumPayload.cpp index c4c22110389fd..90d8ba60fa6db 100644 --- a/lib/IRGen/EnumPayload.cpp +++ b/lib/IRGen/EnumPayload.cpp @@ -1,8 +1,8 @@ -//===--- EnumPayload.cpp - Payload management for 'enum' Types -----------===// +//===--- EnumPayload.cpp - Payload management for 'enum' Types ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -77,11 +77,10 @@ EnumPayload EnumPayload::fromBitPattern(IRGenModule &IGM, return result; } -template +// Fn: void(LazyValue &payloadValue, unsigned payloadBitWidth, +// unsigned payloadValueOffset, unsigned valueBitWidth, +// unsigned valueOffset) +template static void withValueInPayload(IRGenFunction &IGF, const EnumPayload &payload, llvm::Type *valueType, diff --git a/lib/IRGen/EnumPayload.h b/lib/IRGen/EnumPayload.h index 21288e45ff002..3b675f4b65e4c 100644 --- a/lib/IRGen/EnumPayload.h +++ b/lib/IRGen/EnumPayload.h @@ -1,8 +1,8 @@ -//===--- EnumPayload.h - Payload management for 'enum' Types ------* C++ *-===// +//===--- EnumPayload.h - Payload management for 'enum' Types ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/Explosion.h b/lib/IRGen/Explosion.h index c7ff0befd2808..2f6646bb61b14 100644 --- a/lib/IRGen/Explosion.h +++ b/lib/IRGen/Explosion.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/ExtraInhabitants.cpp b/lib/IRGen/ExtraInhabitants.cpp index 5e9ef76443103..5ee01e145af42 100644 --- a/lib/IRGen/ExtraInhabitants.cpp +++ b/lib/IRGen/ExtraInhabitants.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/ExtraInhabitants.h b/lib/IRGen/ExtraInhabitants.h index 5794776a82bed..436e89f802e56 100644 --- a/lib/IRGen/ExtraInhabitants.h +++ b/lib/IRGen/ExtraInhabitants.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h index 4d51071540798..222d8178ff347 100644 --- a/lib/IRGen/FixedTypeInfo.h +++ b/lib/IRGen/FixedTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -72,11 +72,14 @@ class FixedTypeInfo : public TypeInfo { static bool isFixed() { return true; } /// Whether this type is known to be empty. - bool isKnownEmpty() const { return StorageSize.isZero(); } + bool isKnownEmpty(ResilienceExpansion expansion) const { + return (isFixedSize(expansion) && StorageSize.isZero()); + } ContainedAddress allocateStack(IRGenFunction &IGF, SILType T, const llvm::Twine &name) const override; void deallocateStack(IRGenFunction &IGF, Address addr, SILType T) const override; + void destroyStack(IRGenFunction &IGF, Address addr, SILType T) const override; // We can give these reasonable default implementations. diff --git a/lib/IRGen/Fulfillment.cpp b/lib/IRGen/Fulfillment.cpp index 90992b119417d..c4355155323a9 100644 --- a/lib/IRGen/Fulfillment.cpp +++ b/lib/IRGen/Fulfillment.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "Fulfillment.h" +#include "IRGen.h" #include "swift/AST/Decl.h" #include "swift/SIL/TypeLowering.h" @@ -23,6 +24,79 @@ using namespace swift; using namespace irgen; +/// Is metadata for the given type kind a "leaf", or does it possibly +/// store any other type metadata that we can statically extract? +/// +/// It's okay to conservatively answer "no". It's more important for this +/// to be quick than for it to be accurate; don't recurse. +static bool isLeafTypeMetadata(CanType type) { + switch (type->getKind()) { +#define SUGARED_TYPE(ID, SUPER) \ + case TypeKind::ID: +#define UNCHECKED_TYPE(ID, SUPER) \ + case TypeKind::ID: +#define TYPE(ID, SUPER) +#include "swift/AST/TypeNodes.def" + llvm_unreachable("kind is invalid for a canonical type"); + +#define ARTIFICIAL_TYPE(ID, SUPER) \ + case TypeKind::ID: +#define TYPE(ID, SUPER) +#include "swift/AST/TypeNodes.def" + case TypeKind::LValue: + case TypeKind::InOut: + case TypeKind::DynamicSelf: + llvm_unreachable("these types do not have metadata"); + + // All the builtin types are leaves. +#define BUILTIN_TYPE(ID, SUPER) \ + case TypeKind::ID: +#define TYPE(ID, SUPER) +#include "swift/AST/TypeNodes.def" + case TypeKind::Module: + return true; + + // Type parameters are statically opaque. + case TypeKind::Archetype: + case TypeKind::GenericTypeParam: + case TypeKind::DependentMember: + return true; + + // Only the empty tuple is a leaf. + case TypeKind::Tuple: + return cast(type)->getNumElements() == 0; + + // Nominal types might have parents. + case TypeKind::Class: + case TypeKind::Enum: + case TypeKind::Protocol: + case TypeKind::Struct: + return !cast(type)->getParent(); + + // Bound generic types have type arguments. + case TypeKind::BoundGenericClass: + case TypeKind::BoundGenericEnum: + case TypeKind::BoundGenericStruct: + return false; + + // Functions have component types. + case TypeKind::Function: + case TypeKind::PolymorphicFunction: + case TypeKind::GenericFunction: // included for future-proofing + return false; + + // Protocol compositions have component types. + case TypeKind::ProtocolComposition: + return false; + + // Metatypes have instance types. + case TypeKind::Metatype: + case TypeKind::ExistentialMetatype: + return false; + } + llvm_unreachable("bad type kind"); +} + /// Given that we have a source for metadata of the given type, check /// to see if it fulfills anything. /// @@ -31,11 +105,21 @@ using namespace irgen; bool FulfillmentMap::searchTypeMetadata(ModuleDecl &M, CanType type, IsExact_t isExact, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *keys) { + const InterestingKeysCallback &keys) { + + // If this is an exact source, and it's an interesting type, add this + // as a fulfillment. + if (isExact && keys.isInterestingType(type)) { + // If the type isn't a leaf type, also check it as an inexact match. + bool hadFulfillment = false; + if (!isLeafTypeMetadata(type)) { + hadFulfillment |= searchTypeMetadata(M, type, IsInexact, source, + MetadataPath(path), keys); + } - // Type parameters. Inexact metadata are useless here. - if (isExact && type->isTypeParameter()) { - return addFulfillment({type, nullptr}, source, std::move(path)); + // Add the fulfillment. + hadFulfillment |= addFulfillment({type, nullptr}, source, std::move(path)); + return hadFulfillment; } // Inexact metadata will be a problem if we ever try to use this @@ -55,10 +139,73 @@ bool FulfillmentMap::searchTypeMetadata(ModuleDecl &M, CanType type, return false; } +/// Given that we have a source for a witness table that the given type +/// conforms to the given protocol, check to see if it fulfills anything. +bool FulfillmentMap::searchWitnessTable(ModuleDecl &M, + CanType type, ProtocolDecl *protocol, + unsigned source, MetadataPath &&path, + const InterestingKeysCallback &keys) { + llvm::SmallPtrSet interestingConformancesBuffer; + llvm::SmallPtrSetImpl *interestingConformances = nullptr; + + // If the interesting-keys set is limiting the set of interesting + // conformances, collect that filter. + if (keys.isInterestingType(type) && + keys.hasLimitedInterestingConformances(type)) { + // Bail out immediately if the set is empty. + // This only makes sense because we're not trying to fulfill + // associated types this way. + auto requiredConformances = keys.getInterestingConformances(type); + if (requiredConformances.empty()) return false; + + interestingConformancesBuffer.insert(requiredConformances.begin(), + requiredConformances.end()); + interestingConformances = &interestingConformancesBuffer; + } + + return searchWitnessTable(M, type, protocol, source, std::move(path), keys, + interestingConformances); +} + +bool FulfillmentMap::searchWitnessTable(ModuleDecl &M, + CanType type, ProtocolDecl *protocol, + unsigned source, MetadataPath &&path, + const InterestingKeysCallback &keys, + const llvm::SmallPtrSetImpl * + interestingConformances) { + assert(Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)); + + bool hadFulfillment = false; + + auto nextInheritedIndex = 0; + for (auto inherited : protocol->getInheritedProtocols(nullptr)) { + auto index = nextInheritedIndex++; + + // Ignore protocols that don't have witness tables. + if (!Lowering::TypeConverter::protocolRequiresWitnessTable(inherited)) + continue; + + MetadataPath inheritedPath = path; + inheritedPath.addInheritedProtocolComponent(index); + hadFulfillment |= searchWitnessTable(M, type, inherited, + source, std::move(inheritedPath), + keys, interestingConformances); + } + + // If we're not limited the set of interesting conformances, or if + // this is an interesting conformance, record it. + if (!interestingConformances || interestingConformances->count(protocol)) { + hadFulfillment |= addFulfillment({type, protocol}, source, std::move(path)); + } + + return hadFulfillment; +} + + bool FulfillmentMap::searchParentTypeMetadata(ModuleDecl &M, CanType parent, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *keys) { + const InterestingKeysCallback &keys) { // We might not have a parent type. if (!parent) return false; @@ -71,7 +218,7 @@ bool FulfillmentMap::searchNominalTypeMetadata(ModuleDecl &M, CanNominalType type, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *keys) { + const InterestingKeysCallback &keys) { // Nominal types add no generic arguments themselves, but they // may have the arguments of their parents. return searchParentTypeMetadata(M, type.getParent(), @@ -82,7 +229,7 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M, CanBoundGenericType type, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *keys) { + const InterestingKeysCallback &keys) { auto params = type->getDecl()->getGenericParams()->getAllArchetypes(); auto substitutions = type->getSubstitutions(&M, nullptr); assert(params.size() >= substitutions.size() && @@ -94,11 +241,12 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M, auto sub = substitutions[i]; CanType arg = sub.getReplacement()->getCanonicalType(); - if (keys && !keys->isInterestingType(arg)) + // Skip uninteresting type arguments. + if (!keys.hasInterestingType(arg)) continue; // If the argument is a type parameter, fulfill conformances for it. - if (arg->isTypeParameter()) { + if (keys.isInterestingType(arg)) { hadFulfillment |= searchTypeArgConformances(M, arg, params[i], source, path, i, keys); } @@ -122,52 +270,39 @@ bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg, unsigned source, const MetadataPath &path, unsigned argIndex, - const InterestingKeysCallback *keys) { + const InterestingKeysCallback &keys) { // Our sources are the protocol conformances that are recorded in // the generic metadata. auto storedConformances = param->getConformsTo(); if (storedConformances.empty()) return false; - bool hadFulfillment = false; + llvm::SmallPtrSet interestingConformancesBuffer; + llvm::SmallPtrSetImpl *interestingConformances = nullptr; - // If we don't have an interesting-keys callback, add fulfillments - // for all of the stored conformances. - if (!keys) { - // Check each of the stored conformances. - for (size_t confIndex : indices(storedConformances)) { - MetadataPath confPath = path; - confPath.addNominalTypeArgumentConformanceComponent(argIndex, - confIndex); - hadFulfillment |= - addFulfillment({arg, storedConformances[confIndex]}, - source, std::move(confPath)); - } + // If the interesting-keys set is limiting the set of interesting + // conformances, collect that filter. + if (keys.hasLimitedInterestingConformances(arg)) { + // Bail out immediately if the set is empty. + auto requiredConformances = keys.getInterestingConformances(arg); + if (requiredConformances.empty()) return false; - return hadFulfillment; + interestingConformancesBuffer.insert(requiredConformances.begin(), + requiredConformances.end()); + interestingConformances = &interestingConformancesBuffer; } - // Otherwise, our targets are the interesting conformances for the type - // argument. - auto requiredConformances = keys->getInterestingConformances(arg); - if (requiredConformances.empty()) return false; + bool hadFulfillment = false; - for (auto target : requiredConformances) { - // Ignore trivial protocols. - if (!Lowering::TypeConverter::protocolRequiresWitnessTable(target)) + for (size_t confIndex : indices(storedConformances)) { + auto storedProtocol = storedConformances[confIndex]; + if (!Lowering::TypeConverter::protocolRequiresWitnessTable(storedProtocol)) continue; - // Check each of the stored conformances. - for (size_t confIndex : indices(storedConformances)) { - // TODO: maybe this should consider indirect conformance. - // But that should be part of the metadata path. - if (target == storedConformances[confIndex]) { - MetadataPath confPath = path; - confPath.addNominalTypeArgumentConformanceComponent(argIndex, - confIndex); - hadFulfillment |= - addFulfillment({arg, target}, source, std::move(confPath)); - } - } + MetadataPath confPath = path; + confPath.addNominalTypeArgumentConformanceComponent(argIndex, confIndex); + hadFulfillment |= + searchWitnessTable(M, arg, storedProtocol, source, std::move(confPath), + keys, interestingConformances); } return hadFulfillment; @@ -193,3 +328,18 @@ bool FulfillmentMap::addFulfillment(FulfillmentKey key, return true; } } + +bool FulfillmentMap::Everything::isInterestingType(CanType type) const { + return true; +} +bool FulfillmentMap::Everything::hasInterestingType(CanType type) const { + return true; +} +bool FulfillmentMap::Everything + ::hasLimitedInterestingConformances(CanType type) const { + return false; +} +GenericSignature::ConformsToArray +FulfillmentMap::Everything::getInterestingConformances(CanType type) const{ + return {}; +} diff --git a/lib/IRGen/Fulfillment.h b/lib/IRGen/Fulfillment.h index 6d6681d03883c..3351894d0d73a 100644 --- a/lib/IRGen/Fulfillment.h +++ b/lib/IRGen/Fulfillment.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,7 @@ namespace swift { namespace irgen { + enum IsExact_t : bool; /// The metadata value can be fulfilled by following the given metadata /// path from the given source. @@ -46,19 +47,43 @@ class FulfillmentMap { llvm::DenseMap Fulfillments; public: - /// Given that we have metadata for a type, is it exactly of the - /// specified type, or might it be a subtype? - enum IsExact_t : bool { IsInexact = false, IsExact = true }; - struct InterestingKeysCallback { + /// Is the given type something that we should add fulfillments for? virtual bool isInterestingType(CanType type) const = 0; + + /// Is the given type expressed in terms of types that we should add + /// fulfillments for? + /// + /// It's okay to conservatively return true here. + virtual bool hasInterestingType(CanType type) const = 0; + + /// Are we only interested in a subset of the conformances for a + /// given type? + virtual bool hasLimitedInterestingConformances(CanType type) const = 0; + + /// Return the limited interesting conformances for an interesting type. virtual GenericSignature::ConformsToArray getInterestingConformances(CanType type) const = 0; + virtual ~InterestingKeysCallback() = default; }; + /// An implementation of InterestingKeysCallback that returns everything + /// fulfillable. + struct Everything : InterestingKeysCallback { + bool isInterestingType(CanType type) const override; + bool hasInterestingType(CanType type) const override; + bool hasLimitedInterestingConformances(CanType type) const override; + GenericSignature::ConformsToArray + getInterestingConformances(CanType type) const override; + }; + FulfillmentMap() = default; + using iterator = decltype(Fulfillments)::iterator; + iterator begin() { return Fulfillments.begin(); } + iterator end() { return Fulfillments.end(); } + /// Is it even theoretically possible that we might find a fulfillment /// in the given type? static bool isInterestingTypeForFulfillments(CanType type) { @@ -72,7 +97,14 @@ class FulfillmentMap { /// \return true if any fulfillments were added by this search. bool searchTypeMetadata(ModuleDecl &M, CanType type, IsExact_t isExact, unsigned sourceIndex, MetadataPath &&path, - const InterestingKeysCallback *interestingKeys = nullptr); + const InterestingKeysCallback &interestingKeys); + + /// Search the given witness table for useful fulfillments. + /// + /// \return true if any fulfillments were added by this search. + bool searchWitnessTable(ModuleDecl &M, CanType type, ProtocolDecl *protocol, + unsigned sourceIndex, MetadataPath &&path, + const InterestingKeysCallback &interestingKeys); /// Register a fulfillment for the given key. /// @@ -101,21 +133,31 @@ class FulfillmentMap { private: bool searchParentTypeMetadata(ModuleDecl &M, CanType parent, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *interestingKeys); + const InterestingKeysCallback &keys); bool searchNominalTypeMetadata(ModuleDecl &M, CanNominalType type, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *interestingKeys); + const InterestingKeysCallback &keys); bool searchBoundGenericTypeMetadata(ModuleDecl &M, CanBoundGenericType type, unsigned source, MetadataPath &&path, - const InterestingKeysCallback *interestingKeys); + const InterestingKeysCallback &keys); bool searchTypeArgConformances(ModuleDecl &M, CanType arg, ArchetypeType *param, unsigned source, const MetadataPath &path, unsigned argIndex, - const InterestingKeysCallback *interestingKeys); + const InterestingKeysCallback &keys); + + /// Search the given witness table for useful fulfillments. + /// + /// \return true if any fulfillments were added by this search. + bool searchWitnessTable(ModuleDecl &M, CanType type, ProtocolDecl *protocol, + unsigned sourceIndex, MetadataPath &&path, + const InterestingKeysCallback &interestingKeys, + const llvm::SmallPtrSetImpl * + interestingConformances); + }; } diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index 07d697689e8bc..2a956c5cd4857 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,7 +19,6 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Types.h" #include "swift/AST/Decl.h" -#include "swift/AST/IRGenOptions.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/SmallString.h" @@ -51,6 +50,11 @@ using namespace swift; using namespace irgen; +static llvm::Value *emitArchetypeTypeMetadataRef(IRGenFunction &IGF, + CanArchetypeType archetype) { + return IGF.getLocalTypeData(archetype, LocalTypeDataKind::forTypeMetadata()); +} + namespace { /// Common type implementation details for all archetypes. @@ -83,8 +87,9 @@ class ArchetypeTypeInfoBase { CanArchetypeType archetype, unsigned which) const { assert(which < getNumStoredProtocols()); + auto protocol = archetype->getConformsTo()[which]; return IGF.getLocalTypeData(archetype, - LocalTypeData::forArchetypeProtocolWitness(which)); + LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol)); } }; @@ -163,9 +168,9 @@ getArchetypeInfo(IRGenFunction &IGF, CanArchetypeType t, const TypeInfo &ti) { } /// Emit a single protocol witness table reference. -llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, - CanArchetypeType archetype, - ProtocolDecl *proto) { +llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF, + CanArchetypeType archetype, + ProtocolDecl *proto) { assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto) && "looking up witness table for protocol that doesn't have one"); @@ -179,6 +184,38 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, return wtable; } +llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, + CanArchetypeType origin, + AssociatedTypeDecl *associate) { + // Find the conformance of the origin to the associated type's protocol. + llvm::Value *wtable = emitArchetypeWitnessTableRef(IGF, origin, + associate->getProtocol()); + + // Find the origin's type metadata. + llvm::Value *originMetadata = emitArchetypeTypeMetadataRef(IGF, origin); + + return emitAssociatedTypeMetadataRef(IGF, originMetadata, wtable, associate); +} + +llvm::Value * +irgen::emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF, + CanArchetypeType origin, + AssociatedTypeDecl *associate, + llvm::Value *associateMetadata, + ProtocolDecl *associateProtocol) { + // Find the conformance of the origin to the associated type's protocol. + llvm::Value *wtable = emitArchetypeWitnessTableRef(IGF, origin, + associate->getProtocol()); + + // Find the origin's type metadata. + llvm::Value *originMetadata = emitArchetypeTypeMetadataRef(IGF, origin); + + // FIXME: will this ever be an indirect requirement? + return emitAssociatedTypeWitnessTableRef(IGF, originMetadata, wtable, + associate, associateMetadata, + associateProtocol); +} + const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) { assert(isExemplarArchetype(archetype) && "lowering non-exemplary archetype"); @@ -237,22 +274,8 @@ static void setMetadataRef(IRGenFunction &IGF, llvm::Value *metadata) { assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); IGF.setUnscopedLocalTypeData(CanType(archetype), - LocalTypeData::forMetatype(), + LocalTypeDataKind::forTypeMetadata(), metadata); - - // Create a shadow copy of the metadata in an alloca for the debug info. - StringRef Name = metadata->getName(); - if (!IGF.IGM.Opts.Optimize) { - auto Alloca = IGF.createAlloca(metadata->getType(), - IGF.IGM.getPointerAlignment(), Name); - IGF.Builder.CreateAlignedStore(metadata, Alloca.getAddress(), - IGF.IGM.getPointerAlignment().getValue()); - metadata = Alloca.getAddress(); - } - - // Emit debug info for the metadata. - if (IGF.IGM.DebugInfo) - IGF.IGM.DebugInfo->emitTypeMetadata(IGF, metadata, Name); } static void setWitnessTable(IRGenFunction &IGF, @@ -261,8 +284,10 @@ static void setWitnessTable(IRGenFunction &IGF, llvm::Value *wtable) { assert(wtable->getType() == IGF.IGM.WitnessTablePtrTy); assert(protocolIndex < archetype->getConformsTo().size()); + auto protocol = archetype->getConformsTo()[protocolIndex]; IGF.setUnscopedLocalTypeData(CanType(archetype), - LocalTypeData::forArchetypeProtocolWitness(protocolIndex), wtable); + LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol), + wtable); } /// Inform IRGenFunction that the given archetype has the given value @@ -271,9 +296,7 @@ void IRGenFunction::bindArchetype(ArchetypeType *archetype, llvm::Value *metadata, ArrayRef wtables) { // Set the metadata pointer. - bool setNames = !archetype->getOpenedExistentialType(); - if (setNames) - metadata->setName(archetype->getFullName()); + setTypeMetadataName(IGM, metadata, CanType(archetype)); setMetadataRef(*this, archetype, metadata); // Set the protocol witness tables. @@ -284,10 +307,7 @@ void IRGenFunction::bindArchetype(ArchetypeType *archetype, if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto)) continue; auto wtable = wtables[wtableI++]; - if (setNames) { - wtable->setName(Twine(archetype->getFullName()) + "." + - proto->getName().str()); - } + setProtocolWitnessTableName(IGM, wtable, CanType(archetype), proto); setWitnessTable(*this, archetype, i, wtable); } assert(wtableI == wtables.size()); @@ -299,8 +319,7 @@ llvm::Value *irgen::emitDynamicTypeOfOpaqueArchetype(IRGenFunction &IGF, auto archetype = type.castTo(); // Acquire the archetype's static metadata. - llvm::Value *metadata = IGF.getLocalTypeData(archetype, - LocalTypeData::forMetatype()); + llvm::Value *metadata = emitArchetypeTypeMetadataRef(IGF, archetype); return IGF.Builder.CreateCall(IGF.IGM.getGetDynamicTypeFn(), {addr.getAddress(), metadata}); } diff --git a/lib/IRGen/GenArchetype.h b/lib/IRGen/GenArchetype.h index 76936393d1811..44e1cda19ce1f 100644 --- a/lib/IRGen/GenArchetype.h +++ b/lib/IRGen/GenArchetype.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -32,9 +32,22 @@ namespace irgen { class IRGenFunction; /// Emit a witness table reference. - llvm::Value *emitWitnessTableRef(IRGenFunction &IGF, - CanArchetypeType archetype, - ProtocolDecl *protocol); + llvm::Value *emitArchetypeWitnessTableRef(IRGenFunction &IGF, + CanArchetypeType archetype, + ProtocolDecl *protocol); + + /// Emit a metadata reference for an associated type of an archetype. + llvm::Value *emitAssociatedTypeMetadataRef(IRGenFunction &IGF, + CanArchetypeType origin, + AssociatedTypeDecl *associate); + + /// Emit a witness table reference for a specific conformance of an + /// associated type of an archetype. + llvm::Value *emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF, + CanArchetypeType origin, + AssociatedTypeDecl *associate, + llvm::Value *associateMetadata, + ProtocolDecl *associateProtocol); /// Emit a dynamic metatype lookup for the given archetype. llvm::Value *emitDynamicTypeOfOpaqueArchetype(IRGenFunction &IGF, diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index 955540cde5c69..4c9b4eea3b416 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -103,7 +103,7 @@ FailableCastResult irgen::emitClassIdenticalCast(IRGenFunction &IGF, // TODO: use ObjC class references llvm::Value *targetMetadata; if (allowConservative && - (targetMetadata = tryEmitConstantHeapMetadataRef(IGF.IGM, + (targetMetadata = tryEmitConstantTypeMetadataRef(IGF.IGM, toType.getSwiftRValueType()))) { // ok } else { @@ -196,7 +196,7 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from, // FIXME: Eventually, we may want to throw. call->setDoesNotThrow(); - llvm::Type *subTy = IGF.getTypeInfo(toType).StorageType; + llvm::Type *subTy = IGF.getTypeInfo(toType).getStorageType(); return IGF.Builder.CreateBitCast(call, subTy); } @@ -320,7 +320,7 @@ static llvm::Function *emitExistentialScalarCastFn(IRGenModule &IGM, llvm::Twine(name), IGM.getModule()); fn->setAttributes(IGM.constructInitialAttributes()); - auto IGF = IRGenFunction(IGM, fn); + IRGenFunction IGF(IGM, fn); Explosion args = IGF.collectParameters(); auto value = args.claimNext(); @@ -593,6 +593,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF, // If we're doing a conditional cast, and the ObjC protocol checks failed, // then the cast is done. + Optional condition; llvm::BasicBlock *origBB = nullptr, *successBB = nullptr, *contBB = nullptr; if (!objcProtos.empty()) { switch (mode) { @@ -607,6 +608,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF, cast(objcCast->getType()))); IGF.Builder.CreateCondBr(isNull, contBB, successBB); IGF.Builder.emitBlock(successBB); + condition.emplace(IGF); } } } @@ -658,6 +660,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF, // If we had conditional ObjC checks, join the failure paths. if (contBB) { + condition.reset(); IGF.Builder.CreateBr(contBB); IGF.Builder.emitBlock(contBB); diff --git a/lib/IRGen/GenCast.h b/lib/IRGen/GenCast.h index 85912592c7e0f..d97bf8af0f497 100644 --- a/lib/IRGen/GenCast.h +++ b/lib/IRGen/GenCast.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenClangDecl.cpp b/lib/IRGen/GenClangDecl.cpp index ecb6eaf0e16a5..789c23118d558 100644 --- a/lib/IRGen/GenClangDecl.cpp +++ b/lib/IRGen/GenClangDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 9d4277a144d3e..607e46231c581 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -205,7 +205,9 @@ clang::CanQualType GenClangType::visitStructType(CanStructType type) { CHECK_NAMED_TYPE("COpaquePointer", ctx.VoidPtrTy); CHECK_NAMED_TYPE("CVaListPointer", getClangDecayedVaListType(ctx)); CHECK_NAMED_TYPE("DarwinBoolean", ctx.UnsignedCharTy); - CHECK_NAMED_TYPE("NSZone", ctx.VoidPtrTy); + CHECK_NAMED_TYPE(swiftDecl->getASTContext().getSwiftName( + KnownFoundationEntity::NSZone), + ctx.VoidPtrTy); CHECK_NAMED_TYPE("ObjCBool", ctx.ObjCBuiltinBoolTy); CHECK_NAMED_TYPE("Selector", getClangSelectorType(ctx)); #undef CHECK_NAMED_TYPE diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 610364e9ce176..d9fade82b97d1 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1,8 +1,8 @@ -//===--- GenClass.cpp - Swift IR Generation For 'class' Types -----------===// +//===--- GenClass.cpp - Swift IR Generation For 'class' Types -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -91,50 +91,12 @@ IsaEncoding irgen::getIsaEncodingForType(IRGenModule &IGM, return IsaEncoding::Pointer; } -/// Different policies for accessing a physical field. -enum class FieldAccess : uint8_t { - /// Instance variable offsets are constant. - ConstantDirect, - - /// Instance variable offsets must be loaded from "direct offset" - /// global variables. - NonConstantDirect, - - /// Instance variable offsets are kept in fields in metadata, but - /// the offsets of those fields within the metadata are constant. - ConstantIndirect, - - /// Instance variable offsets are kept in fields in metadata, and - /// the offsets of those fields within the metadata must be loaded - /// from "indirect offset" global variables. - NonConstantIndirect -}; - namespace { - class FieldEntry { - llvm::PointerIntPair VarAndAccess; - public: - FieldEntry(VarDecl *var, FieldAccess access) - : VarAndAccess(var, access) {} - - VarDecl *getVar() const { - return VarAndAccess.getPointer(); - } - FieldAccess getAccess() const { - return VarAndAccess.getInt(); - } - }; - /// Layout information for class types. class ClassTypeInfo : public HeapTypeInfo { ClassDecl *TheClass; mutable StructLayout *Layout; - /// Lazily-initialized array of all fragile stored properties in the class - /// (including superclass stored properties). - mutable ArrayRef AllStoredProperties; - /// Lazily-initialized array of all fragile stored properties inherited from - /// superclasses. - mutable ArrayRef InheritedStoredProperties; + mutable ClassLayout FieldLayout; /// Can we use swift reference-counting, or do we have to use /// objc_retain/release? @@ -160,8 +122,7 @@ namespace { ClassDecl *getClass() const { return TheClass; } const StructLayout &getLayout(IRGenModule &IGM) const; - ArrayRef getAllStoredProperties(IRGenModule &IGM) const; - ArrayRef getInheritedStoredProperties(IRGenModule &IGM) const; + const struct ClassLayout &getClassLayout(IRGenModule &IGM) const; Alignment getHeapAlignment(IRGenModule &IGM) const { return getLayout(IGM).getAlignment(); @@ -170,128 +131,6 @@ namespace { return getLayout(IGM).getElements(); } }; - - /// A class for computing properties of the instance-variable layout - /// of a class. TODO: cache the results! - class LayoutClass { - IRGenModule &IGM; - - ClassDecl *Root; - SmallVector Fields; - - bool IsMetadataResilient = false; - bool IsObjectResilient = false; - bool IsObjectGenericallyArranged = false; - - ResilienceScope Resilience; - - public: - LayoutClass(IRGenModule &IGM, ResilienceScope resilience, - ClassDecl *theClass, SILType type) - : IGM(IGM), Resilience(resilience) { - layout(theClass, type); - } - - /// The root class for purposes of metaclass objects. - ClassDecl *getRootClassForMetaclass() const { - // If the formal root class is imported from Objective-C, then - // we should use that. For a class that's really implemented in - // Objective-C, this is obviously right. For a class that's - // really implemented in Swift, but that we're importing via an - // Objective-C interface, this would be wrong --- except such a - // class can never be a formal root class, because a Swift class - // without a formal superclass will actually be parented by - // SwiftObject (or maybe eventually something else like it), - // which will be visible in the Objective-C type system. - if (Root->hasClangNode()) return Root; - - // FIXME: If the root class specifies its own runtime ObjC base class, - // assume that that base class ultimately inherits NSObject. - if (Root->getAttrs().hasAttribute()) - return IGM.getObjCRuntimeBaseClass(IGM.Context.Id_NSObject); - - return IGM.getObjCRuntimeBaseClass(IGM.Context.Id_SwiftObject); - } - - const FieldEntry &getFieldEntry(VarDecl *field) const { - for (auto &entry : Fields) - if (entry.getVar() == field) - return entry; - llvm_unreachable("no entry for field!"); - } - - private: - void layout(ClassDecl *theClass, SILType type) { - // First, collect information about the superclass. - if (theClass->hasSuperclass()) { - SILType superclassType = type.getSuperclass(nullptr); - auto superclass = superclassType.getClassOrBoundGenericClass(); - assert(superclass); - layout(superclass, superclassType); - } else { - Root = theClass; - } - - // If the class is resilient (which includes classes imported - // from Objective-C), then it may have fields we can't see, - // and all subsequent fields are *at least* resilient. - bool isClassResilient = IGM.isResilient(theClass, Resilience); - if (isClassResilient) { - IsMetadataResilient = true; - IsObjectResilient = true; - } - - // Okay, make entries for all the physical fields we know about. - for (auto member : theClass->getMembers()) { - auto var = dyn_cast(member); - if (!var) continue; - - // Skip properties that we have to access logically. - if (!var->hasStorage()) - continue; - - // Adjust based on the type of this field. - // FIXME: this algorithm is assuming that fields are laid out - // in declaration order. - adjustAccessAfterField(var, type); - - Fields.push_back(FieldEntry(var, getCurFieldAccess())); - } - } - - FieldAccess getCurFieldAccess() const { - if (IsObjectGenericallyArranged) { - if (IsMetadataResilient) { - return FieldAccess::NonConstantIndirect; - } else { - return FieldAccess::ConstantIndirect; - } - } else { - if (IsObjectResilient) { - return FieldAccess::NonConstantDirect; - } else { - return FieldAccess::ConstantDirect; - } - } - } - - void adjustAccessAfterField(VarDecl *var, SILType classType) { - if (!var->hasStorage()) return; - - SILType fieldType = classType.getFieldType(var, *IGM.SILMod); - auto &fieldTI = IGM.getTypeInfo(fieldType); - if (fieldTI.isFixedSize()) - return; - - // If the field type is not fixed-size, the size either depends - // on generic parameters, or resilient types. In the former case, - // we store field offsets in type metadata. - if (fieldType.hasArchetype()) - IsObjectGenericallyArranged = true; - - IsObjectResilient = true; - } - }; } // end anonymous namespace. /// Return the lowered type for the class's 'self' type within its context. @@ -305,23 +144,52 @@ static const ClassTypeInfo &getSelfTypeInfo(IRGenModule &IGM, ClassDecl *base) { return IGM.getTypeInfo(getSelfType(base)).as(); } -/// Return the index of the given field within the class. -static unsigned getFieldIndex(IRGenModule &IGM, - ClassDecl *base, VarDecl *target) { - // FIXME: This is algorithmically terrible. - auto &ti = getSelfTypeInfo(IGM, base); - - auto props = ti.getAllStoredProperties(IGM); - auto found = std::find(props.begin(), props.end(), target); - assert(found != props.end() && "didn't find field in type?!"); - return found - props.begin(); -} - namespace { class ClassLayoutBuilder : public StructLayoutBuilder { SmallVector Elements; SmallVector AllStoredProperties; + SmallVector AllFieldAccesses; + + // The manner in which this class embeds the field offset vector of + // the superclass. + // + // - ConstantDirect - size and content of superclass metadata is known + // at compile time. + // - NonConstantDirect - size of superclass metadata is known, however + // some field offsets depend on the sizes of resilient types, or the + // size of an imported Objective-C base class. + // - ConstantIndirect - size of superclass metadata is known, however + // some field offsets depend on generic parameters, sizes of + // resilient types, or the size of an imported Objective-C base class. + // - NonConstantIndirect - size of superclass metadata is unknown, + // so all class metadata entries for members of this class must be + // accessed indirectly. + FieldAccess MetadataAccess = FieldAccess::ConstantDirect; + unsigned NumInherited = 0; + + // Does the class require a metadata template? This will be true if + // the class or any of its ancestors have generic parameters, or if + // any of the below conditions are false. + bool ClassHasMetadataPattern = false; + + // Does the superclass have a fixed number of stored properties? + // If not, and the class has generally-dependent layout, we have to + // access stored properties through an indirect offset into the field + // offset vector. + bool ClassHasFixedFieldCount = true; + + // Does the class have a fixed size up until the current point? + // If not, we have to access stored properties either ivar offset globals, + // or through the field offset vector, based on whether the layout has + // dependent layout. + bool ClassHasFixedSize = true; + + // Does the class have identical layout under all generic substitutions? + // If not, we can have to access stored properties through the field + // offset vector in the instantiated type metadata. + bool ClassHasConcreteLayout = true; + public: ClassLayoutBuilder(IRGenModule &IGM, ClassDecl *theClass) : StructLayoutBuilder(IGM) @@ -340,31 +208,68 @@ namespace { ArrayRef getElements() const { return Elements; } - - /// Return the full list of stored properties. - ArrayRef getAllStoredProperties() const { - return AllStoredProperties; - } - /// Return the inherited stored property count. - unsigned getNumInherited() const { - return NumInherited; + ClassLayout getClassLayout() const { + ClassLayout fieldLayout; + auto allStoredProps = IGM.Context.AllocateCopy(AllStoredProperties); + auto inheritedStoredProps = allStoredProps.slice(0, NumInherited); + fieldLayout.AllStoredProperties = allStoredProps; + fieldLayout.InheritedStoredProperties = inheritedStoredProps; + fieldLayout.AllFieldAccesses = IGM.Context.AllocateCopy(AllFieldAccesses); + fieldLayout.MetadataAccess = MetadataAccess; + fieldLayout.HasMetadataPattern = ClassHasMetadataPattern; + return fieldLayout; } + private: void addFieldsForClass(ClassDecl *theClass, SILType classType) { + if (theClass->isGenericContext()) + ClassHasMetadataPattern = true; + if (theClass->hasSuperclass()) { // TODO: apply substitutions when computing base-class layouts! SILType superclassType = classType.getSuperclass(nullptr); auto superclass = superclassType.getClassOrBoundGenericClass(); assert(superclass); - // Recur. - addFieldsForClass(superclass, superclassType); - // Count the fields we got from the superclass. - NumInherited = Elements.size(); + if (superclass->hasClangNode()) { + // As a special case, assume NSObject has a fixed layout. + if (superclass->getName() != + IGM.Context.getSwiftId(KnownFoundationEntity::NSObject)) { + // If the superclass was imported from Objective-C, its size is + // not known at compile time. However, since the field offset + // vector only stores offsets of stored properties defined in + // Swift, we don't have to worry about indirect indexing of + // the field offset vector. + ClassHasFixedSize = false; + } + } else if (IGM.isResilient(superclass, ResilienceExpansion::Maximal)) { + // If the superclass is resilient, the number of stored properties + // is not known at compile time. + ClassHasMetadataPattern = true; + + ClassHasFixedFieldCount = false; + ClassHasFixedSize = false; + + // If the superclass is in a generic context, conservatively + // assume the layout depends on generic parameters, since we + // can't look at stored properties. + if (superclassType.hasArchetype()) + ClassHasConcreteLayout = false; + } else { + // Otherwise, we have total knowledge of the class and its + // fields, so walk them to compute the layout. + addFieldsForClass(superclass, superclassType); + // Count the fields we got from the superclass. + NumInherited = Elements.size(); + } } + // The final value is field access for the superclass of the class we're + // building. + MetadataAccess = getCurFieldAccess(); + // Collect fields from this class and add them to the layout as a chunk. addDirectFieldsFromClass(theClass, classType); } @@ -374,15 +279,55 @@ namespace { for (VarDecl *var : theClass->getStoredProperties()) { SILType type = classType.getFieldType(var, *IGM.SILMod); auto &eltType = IGM.getTypeInfo(type); + + if (!eltType.isFixedSize()) { + ClassHasMetadataPattern = true; + ClassHasFixedSize = false; + + if (type.hasArchetype()) + ClassHasConcreteLayout = false; + } + Elements.push_back(ElementLayout::getIncomplete(eltType)); AllStoredProperties.push_back(var); + AllFieldAccesses.push_back(getCurFieldAccess()); + } + } + + FieldAccess getCurFieldAccess() const { + if (ClassHasConcreteLayout) { + if (ClassHasFixedSize) { + // No generic parameter dependencies, fixed size. The field offset + // is known at compile time. + return FieldAccess::ConstantDirect; + } else { + // No generic parameter dependencies, but some stored properties + // have unknown size. The field offset is stored in a global constant + // and set up by the Objective-C or Swift runtime, depending on the + // class's heritage. + return FieldAccess::NonConstantDirect; + } + } else { + if (ClassHasFixedFieldCount) { + // Layout depends on generic parameters, but the number of fields + // is known. The field offset is loaded from a fixed offset in the + // field offset vector in type metadata. + return FieldAccess::ConstantIndirect; + } else { + // Layout depends on generic parameters, and the number of fields + // is not known at compile time either. The field index is loaded + // from a global variable set up by the runtime, and then this + // index is used to load the offset from the field offset vector. + return FieldAccess::NonConstantIndirect; + } } } }; } void ClassTypeInfo::generateLayout(IRGenModule &IGM) const { - assert(!Layout && AllStoredProperties.empty() && "already generated layout"); + assert(!Layout && FieldLayout.AllStoredProperties.empty() && + "already generated layout"); // Add the heap header. ClassLayoutBuilder builder(IGM, getClass()); @@ -396,10 +341,7 @@ void ClassTypeInfo::generateLayout(IRGenModule &IGM) const { Layout = new StructLayout(builder, TheClass->getDeclaredTypeInContext()->getCanonicalType(), classTy, builder.getElements()); - AllStoredProperties - = IGM.Context.AllocateCopy(builder.getAllStoredProperties()); - InheritedStoredProperties - = AllStoredProperties.slice(0, builder.getNumInherited()); + FieldLayout = builder.getClassLayout(); } const StructLayout &ClassTypeInfo::getLayout(IRGenModule &IGM) const { @@ -410,24 +352,13 @@ const StructLayout &ClassTypeInfo::getLayout(IRGenModule &IGM) const { return *Layout; } -ArrayRef -ClassTypeInfo::getAllStoredProperties(IRGenModule &IGM) const { +const ClassLayout &ClassTypeInfo::getClassLayout(IRGenModule &IGM) const { // Return the cached layout if available. if (Layout) - return AllStoredProperties; + return FieldLayout; generateLayout(IGM); - return AllStoredProperties; -} - -ArrayRef -ClassTypeInfo::getInheritedStoredProperties(IRGenModule &IGM) const { - // Return the cached layout if available. - if (Layout) - return InheritedStoredProperties; - - generateLayout(IGM); - return InheritedStoredProperties; + return FieldLayout; } /// Cast the base to i8*, apply the given inbounds offset (in bytes, @@ -465,20 +396,6 @@ static OwnedAddress emitAddressAtOffset(IRGenFunction &IGF, return OwnedAddress(addr, base); } -llvm::Constant *irgen::tryEmitClassConstantFragileFieldOffset(IRGenModule &IGM, - ClassDecl *theClass, - VarDecl *field) { - assert(field->hasStorage()); - // FIXME: This field index computation is an ugly hack. - auto &ti = getSelfTypeInfo(IGM, theClass); - - unsigned fieldIndex = getFieldIndex(IGM, theClass, field); - auto &element = ti.getElements(IGM)[fieldIndex]; - if (element.getKind() == ElementLayout::Kind::Fixed) - return IGM.getSize(element.getByteOffset()); - return nullptr; -} - OwnedAddress irgen::projectPhysicalClassMemberAddress(IRGenFunction &IGF, llvm::Value *base, SILType baseType, @@ -486,25 +403,22 @@ OwnedAddress irgen::projectPhysicalClassMemberAddress(IRGenFunction &IGF, VarDecl *field) { // If the field is empty, its address doesn't matter. auto &fieldTI = IGF.getTypeInfo(fieldType); - if (fieldTI.isKnownEmpty()) { + if (fieldTI.isKnownEmpty(ResilienceExpansion::Maximal)) { return OwnedAddress(fieldTI.getUndefAddress(), base); } auto &baseClassTI = IGF.getTypeInfo(baseType).as(); ClassDecl *baseClass = baseType.getClassOrBoundGenericClass(); - + // TODO: Lay out the class based on the substituted baseType rather than // the generic type. Doing this requires that we also handle // specialized layout in ClassTypeInfo. - LayoutClass layout(IGF.IGM, ResilienceScope::Component, baseClass, - getSelfType(baseClass) /* TODO: should be baseType */); - - auto &entry = layout.getFieldEntry(field); - switch (entry.getAccess()) { - case FieldAccess::ConstantDirect: { - // FIXME: This field index computation is an ugly hack. - unsigned fieldIndex = getFieldIndex(IGF.IGM, baseClass, field); + auto &classLayout = baseClassTI.getClassLayout(IGF.IGM); + unsigned fieldIndex = classLayout.getFieldIndex(field); + + switch (classLayout.AllFieldAccesses[fieldIndex]) { + case FieldAccess::ConstantDirect: { Address baseAddr(base, baseClassTI.getHeapAlignment(IGF.IGM)); auto &element = baseClassTI.getElements(IGF.IGM)[fieldIndex]; Address memberAddr = element.project(IGF, baseAddr, None); @@ -777,10 +691,11 @@ void IRGenModule::emitClassDecl(ClassDecl *D) { PrettyStackTraceDecl prettyStackTrace("emitting class metadata for", D); auto &classTI = Types.getTypeInfo(D).as(); - auto &layout = classTI.getLayout(*this); // Emit the class metadata. - emitClassMetadata(*this, D, layout); + emitClassMetadata(*this, D, + classTI.getLayout(*this), + classTI.getClassLayout(*this)); emitNestedTypeDecls(D->getMembers()); } @@ -804,8 +719,8 @@ namespace { IRGenModule &IGM; PointerUnion TheEntity; ExtensionDecl *TheExtension; - const LayoutClass *Layout; - const StructLayout *FieldLayout; + const StructLayout *Layout; + const ClassLayout *FieldLayout; ClassDecl *getClass() const { return TheEntity.get(); @@ -824,7 +739,6 @@ namespace { return TheEntity.is(); } - bool Generic = false; bool HasNonTrivialDestructor = false; bool HasNonTrivialConstructor = false; llvm::SmallString<16> CategoryName; @@ -846,15 +760,15 @@ namespace { unsigned NextFieldIndex; public: ClassDataBuilder(IRGenModule &IGM, ClassDecl *theClass, - const LayoutClass &layout, - const StructLayout &fieldLayout, - unsigned firstField) + const StructLayout &layout, + const ClassLayout &fieldLayout) : IGM(IGM), TheEntity(theClass), TheExtension(nullptr), - Layout(&layout), FieldLayout(&fieldLayout), - Generic(theClass->isGenericContext()), - FirstFieldIndex(firstField), - NextFieldIndex(firstField) + Layout(&layout), + FieldLayout(&fieldLayout) { + FirstFieldIndex = fieldLayout.InheritedStoredProperties.size(); + NextFieldIndex = FirstFieldIndex; + visitConformances(theClass); visitMembers(theClass); @@ -867,9 +781,11 @@ namespace { ClassDataBuilder(IRGenModule &IGM, ClassDecl *theClass, ExtensionDecl *theExtension) : IGM(IGM), TheEntity(theClass), TheExtension(theExtension), - Layout(nullptr), FieldLayout(nullptr), - Generic(theClass->isGenericContext()) + Layout(nullptr), FieldLayout(nullptr) { + FirstFieldIndex = -1; + NextFieldIndex = -1; + buildCategoryName(CategoryName); visitConformances(theExtension); @@ -920,7 +836,7 @@ namespace { void buildMetaclassStub() { assert(Layout && "can't build a metaclass from a category"); // The isa is the metaclass pointer for the root class. - auto rootClass = Layout->getRootClassForMetaclass(); + auto rootClass = getRootClassForMetaclass(IGM, TheEntity.get()); auto rootPtr = IGM.getAddrOfMetaclassObject(rootClass, NotForDefinition); // The superclass of the metaclass is the metaclass of the @@ -932,11 +848,7 @@ namespace { llvm::Constant *superPtr; if (getClass()->hasSuperclass()) { auto base = getClass()->getSuperclass()->getClassOrBoundGenericClass(); - // If the base is generic, we'll need to instantiate it at runtime. - if (base->isGenericContext()) - superPtr = llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy); - else - superPtr = IGM.getAddrOfMetaclassObject(base, NotForDefinition); + superPtr = IGM.getAddrOfMetaclassObject(base, NotForDefinition); } else { superPtr = IGM.getAddrOfMetaclassObject( IGM.getObjCRuntimeBaseForSwiftRootClass(getClass()), @@ -986,7 +898,7 @@ namespace { fields.push_back(IGM.getAddrOfObjCClass(getClass(), NotForDefinition)); else { auto type = getSelfType(getClass()).getSwiftRValueType(); - llvm::Constant *metadata = tryEmitConstantHeapMetadataRef(IGM, type); + llvm::Constant *metadata = tryEmitConstantTypeMetadataRef(IGM, type); assert(metadata && "extended objc class doesn't have constant metadata?"); fields.push_back(metadata); @@ -1050,7 +962,7 @@ namespace { } llvm::Constant *emitRODataFields(ForMetaClass_t forMeta) { - assert(Layout && FieldLayout && "can't emit rodata for a category"); + assert(Layout && "can't emit rodata for a category"); SmallVector fields; // struct _class_ro_t { // uint32_t flags; @@ -1071,14 +983,14 @@ namespace { // historical nonsense instanceStart = instanceSize; } else { - instanceSize = FieldLayout->getSize(); - if (FieldLayout->getElements().empty() - || FieldLayout->getElements().size() == FirstFieldIndex) { + instanceSize = Layout->getSize(); + if (Layout->getElements().empty() + || Layout->getElements().size() == FirstFieldIndex) { instanceStart = instanceSize; - } else if (FieldLayout->getElement(FirstFieldIndex).getKind() + } else if (Layout->getElement(FirstFieldIndex).getKind() == ElementLayout::Kind::Fixed) { // FIXME: assumes layout is always sequential! - instanceStart = FieldLayout->getElement(FirstFieldIndex).getByteOffset(); + instanceStart = Layout->getElement(FirstFieldIndex).getByteOffset(); } else { instanceStart = Size(0); } @@ -1396,7 +1308,7 @@ namespace { /// affect flags. void visitStoredVar(VarDecl *var) { // FIXME: how to handle ivar extensions in categories? - if (!Layout && !FieldLayout) + if (!Layout) return; // For now, we never try to emit specialized versions of the @@ -1419,38 +1331,31 @@ namespace { /// uint32_t size; /// }; llvm::Constant *buildIvar(VarDecl *ivar, SILType loweredType) { - assert(Layout && FieldLayout && "can't build ivar for category"); + assert(Layout && "can't build ivar for category"); // FIXME: this is not always the right thing to do! - auto &elt = FieldLayout->getElement(NextFieldIndex++); + //auto &elt = Layout->getElement(NextFieldIndex++); auto &ivarTI = IGM.getTypeInfo(loweredType); - + llvm::Constant *offsetPtr; - if (elt.getKind() == ElementLayout::Kind::Fixed) { - // Emit a field offset variable for the fixed field statically. + switch (FieldLayout->AllFieldAccesses[NextFieldIndex++]) { + case FieldAccess::ConstantDirect: + case FieldAccess::NonConstantDirect: { + // If the field offset is fixed relative to the start of the superclass, + // reference the global from the ivar metadata so that the Objective-C + // runtime will slide it down. auto offsetAddr = IGM.getAddrOfFieldOffset(ivar, /*indirect*/ false, - ForDefinition); - auto offsetVar = cast(offsetAddr.getAddress()); - offsetVar->setConstant(false); - auto offsetVal = - llvm::ConstantInt::get(IGM.IntPtrTy, elt.getByteOffset().getValue()); - offsetVar->setInitializer(offsetVal); - - offsetPtr = offsetVar; - } else { - // Emit an indirect field offset variable with the field index. - auto offsetAddr = IGM.getAddrOfFieldOffset(ivar, /*indirect*/ true, - ForDefinition); - auto offsetVar = cast(offsetAddr.getAddress()); - offsetVar->setConstant(false); - auto offset = - getClassFieldOffset(IGM, getClass(), ivar).getValue(); - auto offsetVal = - llvm::ConstantInt::get(IGM.IntPtrTy, offset); - offsetVar->setInitializer(offsetVal); - - // We need to set this up when the metadata is instantiated. + NotForDefinition); + offsetPtr = cast(offsetAddr.getAddress()); + break; + } + case FieldAccess::ConstantIndirect: + case FieldAccess::NonConstantIndirect: + // Otherwise, swift_initClassMetadata_UniversalStrategy() will point + // the Objective-C runtime into the field offset vector of the + // instantiated metadata. offsetPtr = llvm::ConstantPointerNull::get(IGM.IntPtrTy->getPointerTo()); + break; } // TODO: clang puts this in __TEXT,__objc_methname,cstring_literals @@ -1777,10 +1682,9 @@ llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM, assert(IGM.ObjCInterop && "emitting RO-data outside of interop mode"); SILType selfType = getSelfType(cls); auto &classTI = IGM.getTypeInfo(selfType).as(); - auto &fieldLayout = classTI.getLayout(IGM); - LayoutClass layout(IGM, ResilienceScope::Universal, cls, selfType); - ClassDataBuilder builder(IGM, cls, layout, fieldLayout, - classTI.getInheritedStoredProperties(IGM).size()); + auto &layout = classTI.getLayout(IGM); + auto &fieldLayout = classTI.getClassLayout(IGM); + ClassDataBuilder builder(IGM, cls, layout, fieldLayout); // First, build the metaclass object. builder.buildMetaclassStub(); @@ -1796,10 +1700,9 @@ irgen::emitClassPrivateDataFields(IRGenModule &IGM, ClassDecl *cls) { assert(IGM.ObjCInterop && "emitting RO-data outside of interop mode"); SILType selfType = getSelfType(cls); auto &classTI = IGM.getTypeInfo(selfType).as(); - auto &fieldLayout = classTI.getLayout(IGM); - LayoutClass layout(IGM, ResilienceScope::Universal, cls, selfType); - ClassDataBuilder builder(IGM, cls, layout, fieldLayout, - classTI.getInheritedStoredProperties(IGM).size()); + auto &layout = classTI.getLayout(IGM); + auto &fieldLayout = classTI.getClassLayout(IGM); + ClassDataBuilder builder(IGM, cls, layout, fieldLayout); auto classFields = builder.emitRODataFields(ForClass); auto metaclassFields = builder.emitRODataFields(ForMetaClass); @@ -1850,7 +1753,8 @@ const TypeInfo *TypeConverter::convertClassType(ClassDecl *D) { } /// Lazily declare a fake-looking class to represent an ObjC runtime base class. -ClassDecl *IRGenModule::getObjCRuntimeBaseClass(Identifier name) { +ClassDecl *IRGenModule::getObjCRuntimeBaseClass(Identifier name, + Identifier objcName) { auto found = SwiftRootClasses.find(name); if (found != SwiftRootClasses.end()) return found->second; @@ -1862,7 +1766,7 @@ ClassDecl *IRGenModule::getObjCRuntimeBaseClass(Identifier name) { Context.TheBuiltinModule); SwiftRootClass->computeType(); SwiftRootClass->setIsObjC(true); - SwiftRootClass->getAttrs().add(ObjCAttr::createNullary(Context, name, + SwiftRootClass->getAttrs().add(ObjCAttr::createNullary(Context, objcName, /*implicit=*/true)); SwiftRootClass->setImplicit(); SwiftRootClass->setAccessibility(Accessibility::Public); @@ -1885,11 +1789,39 @@ IRGenModule::getObjCRuntimeBaseForSwiftRootClass(ClassDecl *theClass) { // Otherwise, use the standard SwiftObject class. name = Context.Id_SwiftObject; } - return getObjCRuntimeBaseClass(name); + return getObjCRuntimeBaseClass(name, name); } ClassDecl *irgen::getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *C) { - LayoutClass layout(IGM, ResilienceScope::Component, C, getSelfType(C)); + while (auto superclass = C->getSuperclass()) + C = superclass->getClassOrBoundGenericClass(); + + // If the formal root class is imported from Objective-C, then + // we should use that. For a class that's really implemented in + // Objective-C, this is obviously right. For a class that's + // really implemented in Swift, but that we're importing via an + // Objective-C interface, this would be wrong --- except such a + // class can never be a formal root class, because a Swift class + // without a formal superclass will actually be parented by + // SwiftObject (or maybe eventually something else like it), + // which will be visible in the Objective-C type system. + if (C->hasClangNode()) return C; + + // FIXME: If the root class specifies its own runtime ObjC base class, + // assume that that base class ultimately inherits NSObject. + if (C->getAttrs().hasAttribute()) + return IGM.getObjCRuntimeBaseClass( + IGM.Context.getSwiftId(KnownFoundationEntity::NSObject), + IGM.Context.getIdentifier("NSObject")); + + return IGM.getObjCRuntimeBaseClass(IGM.Context.Id_SwiftObject, + IGM.Context.Id_SwiftObject); +} - return layout.getRootClassForMetaclass(); +bool irgen::getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass) { + // Classes imported from Objective-C never have a metadata pattern. + if (theClass->hasClangNode()) + return false; + + return getSelfTypeInfo(IGM, theClass).getClassLayout(IGM).HasMetadataPattern; } diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h index 68b7a3dd8364c..83645ee57618b 100644 --- a/lib/IRGen/GenClass.h +++ b/lib/IRGen/GenClass.h @@ -1,8 +1,8 @@ -//===--- GenStruct.h - Swift IR generation for classes ------------*- C++ -*-===// +//===--- GenClass.h - Swift IR generation for classes -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -58,7 +58,7 @@ namespace irgen { llvm::Constant *emitClassPrivateData(IRGenModule &IGM, ClassDecl *theClass); void emitGenericClassPrivateDataTemplate(IRGenModule &IGM, - ClassDecl *cls, + ClassDecl *theClass, llvm::SmallVectorImpl &fields, Size &metaclassOffset, Size &classRODataOffset, @@ -96,19 +96,12 @@ namespace irgen { /// does not have fixed layout. For resilient classes this does not /// correspond to the runtime alignment of instances of the class. llvm::Constant *tryEmitClassConstantFragileInstanceSize(IRGenModule &IGM, - ClassDecl *Class); + ClassDecl *theClass); /// Emit the constant fragile instance alignment mask of the class, or null if /// the class does not have fixed layout. For resilient classes this does not /// correspond to the runtime alignment of instances of the class. llvm::Constant *tryEmitClassConstantFragileInstanceAlignMask(IRGenModule &IGM, - ClassDecl *Class); - - /// Emit the constant fragile byte offset for the field in the class, or null - /// if the field does not have fixed layout. For resilient classes this does - /// not correspond to the runtime offset of the field. - llvm::Constant *tryEmitClassConstantFragileFieldOffset(IRGenModule &IGM, - ClassDecl *theClass, - VarDecl *field); + ClassDecl *theClass); /// What reference counting mechanism does a class use? ReferenceCounting getReferenceCountingForClass(IRGenModule &IGM, @@ -117,7 +110,9 @@ namespace irgen { /// What isa-encoding mechanism does a type use? IsaEncoding getIsaEncodingForType(IRGenModule &IGM, CanType type); - ClassDecl *getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *C); + ClassDecl *getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *theClass); + + bool getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenControl.cpp b/lib/IRGen/GenControl.cpp index 8a88603cf4ce9..e35716a62bae8 100644 --- a/lib/IRGen/GenControl.cpp +++ b/lib/IRGen/GenControl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenCoverage.cpp b/lib/IRGen/GenCoverage.cpp index 29b172a5ea4cd..acfb5ca0a440f 100644 --- a/lib/IRGen/GenCoverage.cpp +++ b/lib/IRGen/GenCoverage.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -82,7 +82,7 @@ void IRGenModule::emitCoverageMapping() { W.write(OS); auto *NameVal = - llvm::ConstantDataArray::getString(LLVMContext, M.getName(), true); + llvm::ConstantDataArray::getString(LLVMContext, M.getName(), false); auto *NameVar = new llvm::GlobalVariable(*getModule(), NameVal->getType(), true, llvm::GlobalValue::LinkOnceAnyLinkage, NameVal, @@ -94,7 +94,7 @@ void IRGenModule::emitCoverageMapping() { llvm::ConstantExpr::getBitCast(NameVar, Int8PtrTy), // TODO: We're including the null to match the profile, but we should // really skip the null in the profile instead. - llvm::ConstantInt::get(Int32Ty, M.getName().size() + 1), + llvm::ConstantInt::get(Int32Ty, M.getName().size()), llvm::ConstantInt::get(Int32Ty, CurrentSize - PrevSize), llvm::ConstantInt::get(Int64Ty, M.getHash())}; FunctionRecords.push_back(llvm::ConstantStruct::get( diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 6500ca64798d7..befedac9c6378 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -106,7 +106,7 @@ class CategoryInitializerVisitor class_addProtocol = IGM.getClassAddProtocolFn(); CanType origTy = ext->getDeclaredTypeOfContext()->getCanonicalType(); - classMetadata = tryEmitConstantHeapMetadataRef(IGM, origTy); + classMetadata = tryEmitConstantTypeMetadataRef(IGM, origTy); assert(classMetadata && "extended objc class doesn't have constant metadata?!"); classMetadata = llvm::ConstantExpr::getBitCast(classMetadata, @@ -456,15 +456,39 @@ void IRGenModule::emitSourceFile(SourceFile &SF, unsigned StartElem) { this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library)); } +/// Collect elements of an already-existing global list with the given +/// \c name into \c list. +/// +/// We use this when Clang code generation might populate the list. +static void collectGlobalList(IRGenModule &IGM, + SmallVectorImpl &list, + StringRef name) { + if (auto *existing = IGM.Module.getGlobalVariable(name)) { + auto *globals = cast(existing->getInitializer()); + for (auto &use : globals->operands()) { + auto *global = use.get(); + list.push_back(global); + } + existing->eraseFromParent(); + } + + std::for_each(list.begin(), list.end(), + [](const llvm::WeakVH &global) { + assert(!isa(global) || + !cast(global)->isDeclaration() && + "all globals in the 'used' list must be definitions"); + }); +} + /// Emit a global list, i.e. a global constant array holding all of a /// list of values. Generally these lists are for various LLVM /// metadata or runtime purposes. static llvm::GlobalVariable * emitGlobalList(IRGenModule &IGM, ArrayRef handles, - StringRef name, StringRef section, - llvm::GlobalValue::LinkageTypes linkage, - llvm::Type *eltTy, - bool isConstant) { + StringRef name, StringRef section, + llvm::GlobalValue::LinkageTypes linkage, + llvm::Type *eltTy, + bool isConstant) { // Do nothing if the list is empty. if (handles.empty()) return nullptr; @@ -500,6 +524,7 @@ emitGlobalList(IRGenModule &IGM, ArrayRef handles, void IRGenModule::emitRuntimeRegistration() { // Duck out early if we have nothing to register. if (ProtocolConformances.empty() + && RuntimeResolvableTypes.empty() && (!ObjCInterop || (ObjCProtocols.empty() && ObjCClasses.empty() && ObjCCategoryDecls.empty()))) @@ -620,6 +645,26 @@ void IRGenModule::emitRuntimeRegistration() { RegIGF.Builder.CreateCall(getRegisterProtocolConformancesFn(), {begin, end}); } + + if (!RuntimeResolvableTypes.empty()) { + llvm::Constant *records = emitTypeMetadataRecords(); + + llvm::Constant *beginIndices[] = { + llvm::ConstantInt::get(Int32Ty, 0), + llvm::ConstantInt::get(Int32Ty, 0), + }; + auto begin = llvm::ConstantExpr::getGetElementPtr( + /*Ty=*/nullptr, records, beginIndices); + llvm::Constant *endIndices[] = { + llvm::ConstantInt::get(Int32Ty, 0), + llvm::ConstantInt::get(Int32Ty, RuntimeResolvableTypes.size()), + }; + auto end = llvm::ConstantExpr::getGetElementPtr( + /*Ty=*/nullptr, records, endIndices); + + RegIGF.Builder.CreateCall(getRegisterTypeMetadataRecordsFn(), {begin, end}); + } + RegIGF.Builder.CreateRetVoid(); } @@ -630,6 +675,13 @@ void IRGenModule::addUsedGlobal(llvm::GlobalValue *global) { LLVMUsed.push_back(global); } +/// Add the given global value to @llvm.compiler.used. +/// +/// This value must have a definition by the time the module is finalized. +void IRGenModule::addCompilerUsedGlobal(llvm::GlobalValue *global) { + LLVMCompilerUsed.push_back(global); +} + /// Add the given global value to the Objective-C class list. void IRGenModule::addObjCClass(llvm::Constant *classPtr, bool nonlazy) { ObjCClasses.push_back(classPtr); @@ -644,6 +696,42 @@ void IRGenModule::addProtocolConformanceRecord( ProtocolConformances.push_back(conformance); } +static bool +hasExplicitProtocolConformance(NominalTypeDecl *decl) { + auto conformances = decl->getAllConformances(); + for (auto conformance : conformances) { + // inherited protocols do not emit explicit conformance records + // TODO any special handling required for Specialized conformances? + if (conformance->getKind() == ProtocolConformanceKind::Inherited) + continue; + + auto P = conformance->getProtocol(); + + // @objc protocols do not have conformance records + if (P->isObjC()) + continue; + + // neither does AnyObject + if (P->getKnownProtocolKind().hasValue() && + *P->getKnownProtocolKind() == KnownProtocolKind::AnyObject) + continue; + + return true; + } + + return false; +} + +void IRGenModule::addRuntimeResolvableType(CanType type) { + // Don't emit type metadata records for types that can be found in the protocol + // conformance table as the runtime will search both tables when resolving a + // type by name. + if (auto nom = type->getAnyNominal()) { + if (!hasExplicitProtocolConformance(nom)) + RuntimeResolvableTypes.push_back(type); + } +} + void IRGenModule::emitGlobalLists() { if (ObjCInterop) { assert(TargetInfo.OutputObjectFormat == llvm::Triple::MachO); @@ -674,26 +762,19 @@ void IRGenModule::emitGlobalLists() { // @llvm.used // Collect llvm.used globals already in the module (coming from ClangCodeGen). - auto *ExistingLLVMUsed = Module.getGlobalVariable("llvm.used"); - if (ExistingLLVMUsed) { - auto *Globals = - cast(ExistingLLVMUsed->getInitializer()); - for (auto &Use : Globals->operands()) { - auto *Global = Use.get(); - LLVMUsed.push_back(Global); - } - ExistingLLVMUsed->eraseFromParent(); - } - - assert(std::all_of(LLVMUsed.begin(), LLVMUsed.end(), - [](const llvm::WeakVH &global) { - return !isa(global) || - !cast(global)->isDeclaration(); - }) && "all globals in the 'used' list must be definitions"); + collectGlobalList(*this, LLVMUsed, "llvm.used"); emitGlobalList(*this, LLVMUsed, "llvm.used", "llvm.metadata", llvm::GlobalValue::AppendingLinkage, Int8PtrTy, false); + + // Collect llvm.compiler.used globals already in the module (coming + // from ClangCodeGen). + collectGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used"); + emitGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used", "llvm.metadata", + llvm::GlobalValue::AppendingLinkage, + Int8PtrTy, + false); } void IRGenModuleDispatcher::emitGlobalTopLevel() { @@ -788,6 +869,12 @@ void IRGenModuleDispatcher::emitProtocolConformances() { } } +void IRGenModuleDispatcher::emitTypeMetadataRecords() { + for (auto &m : *this) { + m.second->emitTypeMetadataRecords(); + } +} + /// Emit any lazy definitions (of globals or functions or whatever /// else) that we require. void IRGenModuleDispatcher::emitLazyDefinitions() { @@ -832,16 +919,15 @@ void IRGenModule::emitVTableStubs() { continue; if (!stub) { - // Create a single stub function which calls swift_reportMissingMethod(). + // Create a single stub function which calls swift_deletedMethodError(). stub = llvm::Function::Create(llvm::FunctionType::get(VoidTy, false), - llvm::GlobalValue::LinkOnceODRLinkage, + llvm::GlobalValue::InternalLinkage, "_swift_dead_method_stub"); stub->setAttributes(constructInitialAttributes()); Module.getFunctionList().push_back(stub); - stub->setVisibility(llvm::GlobalValue::HiddenVisibility); stub->setCallingConv(RuntimeCC); auto *entry = llvm::BasicBlock::Create(getLLVMContext(), "entry", stub); - auto *errorFunc = getDeadMethodErrorFn(); + auto *errorFunc = getDeletedMethodErrorFn(); llvm::CallInst::Create(errorFunc, ArrayRef(), "", entry); new llvm::UnreachableInst(getLLVMContext(), entry); } @@ -988,8 +1074,7 @@ SILLinkage LinkEntity::getLinkage(IRGenModule &IGM, case Kind::TypeMetadataAccessFunction: case Kind::TypeMetadataLazyCacheVariable: - switch (getTypeMetadataAccessStrategy(IGM, getType(), - /*preferDirectAccess=*/false)) { + switch (getTypeMetadataAccessStrategy(IGM, getType())) { case MetadataAccessStrategy::PublicUniqueAccessor: return getSILLinkage(FormalLinkage::PublicUnique, forDefinition); case MetadataAccessStrategy::HiddenUniqueAccessor: @@ -998,8 +1083,6 @@ SILLinkage LinkEntity::getLinkage(IRGenModule &IGM, return getSILLinkage(FormalLinkage::Private, forDefinition); case MetadataAccessStrategy::NonUniqueAccessor: return SILLinkage::Shared; - case MetadataAccessStrategy::Direct: - llvm_unreachable("metadata accessor for type with direct access?"); } llvm_unreachable("bad metadata access kind"); @@ -1016,7 +1099,6 @@ SILLinkage LinkEntity::getLinkage(IRGenModule &IGM, case Kind::DirectProtocolWitnessTable: case Kind::ProtocolWitnessTableAccessFunction: - case Kind::DependentProtocolWitnessTableGenerator: return getConformanceLinkage(IGM, getProtocolConformance()); case Kind::ProtocolWitnessTableLazyAccessFunction: @@ -1029,7 +1111,10 @@ SILLinkage LinkEntity::getLinkage(IRGenModule &IGM, return SILLinkage::Shared; } - case Kind::DependentProtocolWitnessTableTemplate: + case Kind::AssociatedTypeMetadataAccessFunction: + case Kind::AssociatedTypeWitnessTableAccessFunction: + case Kind::GenericProtocolWitnessTableCache: + case Kind::GenericProtocolWitnessTableInstantiationFunction: return SILLinkage::Private; case Kind::SILFunction: @@ -1049,8 +1134,7 @@ bool LinkEntity::isFragile(IRGenModule &IGM) const { case Kind::SILGlobalVariable: return getSILGlobalVariable()->isFragile(); - case Kind::DirectProtocolWitnessTable: - case Kind::DependentProtocolWitnessTableGenerator: { + case Kind::DirectProtocolWitnessTable: { auto wt = IGM.SILMod->lookUpWitnessTable(getProtocolConformance()); if (wt.first) { return wt.first->isFragile(); @@ -1375,6 +1459,7 @@ void IRGenModule::emitExternalDefinition(Decl *D) { case DeclKind::PostfixOperator: case DeclKind::IfConfig: case DeclKind::Param: + case DeclKind::Module: llvm_unreachable("Not a valid external definition for IRgen"); case DeclKind::Var: @@ -1396,19 +1481,33 @@ void IRGenModule::emitExternalDefinition(Decl *D) { case DeclKind::Class: case DeclKind::Protocol: break; - - case DeclKind::Module: - break; } } Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, + const TypeInfo &ti, ForDefinition_t forDefinition) { LinkEntity entity = LinkEntity::forSILGlobalVariable(var); - auto &unknownTI = getTypeInfo(var->getLoweredType()); - assert(isa(unknownTI) && - "unsupported global variable of resilient type!"); - auto &ti = cast(unknownTI); + ResilienceExpansion expansion = getResilienceExpansionForLayout(var); + + llvm::Type *storageType; + Size fixedSize; + Alignment fixedAlignment; + + // If the type has a fixed size, allocate static storage. Otherwise, allocate + // a fixed-size buffer and possibly heap-allocate a payload at runtime if the + // runtime size of the type does not fit in the buffer. + if (ti.isFixedSize(expansion)) { + auto &fixedTI = cast(ti); + + storageType = fixedTI.getStorageType(); + fixedSize = fixedTI.getFixedSize(); + fixedAlignment = fixedTI.getFixedAlignment(); + } else { + storageType = getFixedBufferTy(); + fixedSize = Size(DataLayout.getTypeAllocSize(storageType)); + fixedAlignment = Alignment(DataLayout.getABITypeAlignment(storageType)); + } // Check whether we've created the global variable already. // FIXME: We should integrate this into the LinkEntity cache more cleanly. @@ -1418,8 +1517,8 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, updateLinkageForDefinition(*this, gvar, entity); llvm::Constant *addr = gvar; - if (ti.getStorageType() != gvar->getType()->getElementType()) { - auto *expectedTy = ti.StorageType->getPointerTo(); + if (storageType != gvar->getType()->getElementType()) { + auto *expectedTy = storageType->getPointerTo(); addr = llvm::ConstantExpr::getBitCast(addr, expectedTy); } return Address(addr, Alignment(gvar->getAlignment())); @@ -1429,27 +1528,27 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, if (var->getDecl()) { // If we have the VarDecl, use it for more accurate debugging information. DebugTypeInfo DbgTy(var->getDecl(), - var->getLoweredType().getSwiftType(), ti); - gvar = link.createVariable(*this, ti.StorageType, - ti.getFixedAlignment(), + var->getLoweredType().getSwiftType(), + storageType, fixedSize, fixedAlignment); + gvar = link.createVariable(*this, storageType, fixedAlignment, DbgTy, SILLocation(var->getDecl()), var->getDecl()->getName().str()); } else { // There is no VarDecl for a SILGlobalVariable, and thus also no context. DeclContext *DeclCtx = nullptr; - DebugTypeInfo DbgTy(var->getLoweredType().getSwiftRValueType(), ti, - DeclCtx); + DebugTypeInfo DbgTy(var->getLoweredType().getSwiftRValueType(), + storageType, fixedSize, fixedAlignment, DeclCtx); Optional loc; if (var->hasLocation()) loc = var->getLocation(); - gvar = link.createVariable(*this, ti.StorageType, ti.getFixedAlignment(), + gvar = link.createVariable(*this, storageType, fixedAlignment, DbgTy, loc, var->getName()); } // Set the alignment from the TypeInfo. - Address gvarAddr = ti.getAddressForPointer(gvar); - gvar->setAlignment(gvarAddr.getAlignment().getValue()); + Address gvarAddr = Address(gvar, fixedAlignment); + gvar->setAlignment(fixedAlignment.getValue()); return gvarAddr; } @@ -1563,7 +1662,7 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment, defaultType, debugType); } -/// Get or create a llvm::GlobalVariable. +/// Get or create an llvm::GlobalVariable. /// /// If a definition type is given, the result will always be an /// llvm::GlobalVariable of that type. Otherwise, the result will @@ -1716,40 +1815,61 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, return {gotEquivalent, DirectOrGOT::GOT}; } +/// If true, we lazily initialize metadata at runtime because the layout +/// is only partially known. Otherwise, we can emit a direct reference a +/// constant metadata symbol. +bool +IRGenModule::hasMetadataPattern(NominalTypeDecl *theDecl) { + assert(theDecl != nullptr); + // Protocols must be special-cased in a few places. + assert(!isa(theDecl)); + + // For classes, we already computed this when we did the layout. + // FIXME: Try not to call this for classes of other modules, by referencing + // the metadata accessor instead. + if (auto *theClass = dyn_cast(theDecl)) + return irgen::getClassHasMetadataPattern(*this, theClass); + + // Ok, we have a value type. If it is generic, it is always initialized + // at runtime. + if (theDecl->isGenericContext()) + return true; + + // If the type is not fixed-size, its size depends on resilient types, + // and the metadata is initialized at runtime. + if (!getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize()) + return true; + + return false; +} + namespace { struct TypeEntityInfo { - unsigned flags; + ProtocolConformanceFlags flags; LinkEntity entity; llvm::Type *defaultTy, *defaultPtrTy; }; } // end anonymous namespace static TypeEntityInfo -getTypeEntityForProtocolConformanceRecord(IRGenModule &IGM, - NormalProtocolConformance *conformance) { - ProtocolConformanceTypeKind typeKind; +getTypeEntityInfo(IRGenModule &IGM, CanType conformingType) { + TypeMetadataRecordKind typeKind; Optional entity; llvm::Type *defaultTy, *defaultPtrTy; - // TODO: Should use accessor kind for lazy conformances - ProtocolConformanceReferenceKind conformanceKind - = ProtocolConformanceReferenceKind::WitnessTable; - - auto conformingType = conformance->getType()->getCanonicalType(); - if (auto bgt = dyn_cast(conformingType)) { - // Conformances for generics are represented by referencing the metadata - // pattern for the generic type. - typeKind = ProtocolConformanceTypeKind::UniqueGenericPattern; - entity = LinkEntity::forTypeMetadata( - bgt->getDecl()->getDeclaredType()->getCanonicalType(), - TypeMetadataAddress::AddressPoint, - /*isPattern*/ true); - defaultTy = IGM.TypeMetadataPatternStructTy; - defaultPtrTy = IGM.TypeMetadataPatternPtrTy; + auto nom = conformingType->getAnyNominal(); + if (IGM.hasMetadataPattern(nom)) { + // Conformances for generics, concrete subclasses of generics, and + // resiliently-sized types are represented by referencing the + // nominal type descriptor. + typeKind = TypeMetadataRecordKind::UniqueNominalTypeDescriptor; + entity = LinkEntity::forNominalTypeDescriptor(nom); + defaultTy = IGM.NominalTypeDescriptorTy; + defaultPtrTy = IGM.NominalTypeDescriptorPtrTy; } else if (auto ct = dyn_cast(conformingType)) { auto clas = ct->getDecl(); if (clas->isForeign()) { - typeKind = ProtocolConformanceTypeKind::NonuniqueDirectType; + typeKind = TypeMetadataRecordKind::NonuniqueDirectType; entity = LinkEntity::forForeignTypeMetadataCandidate(conformingType); defaultTy = IGM.TypeMetadataStructTy; defaultPtrTy = IGM.TypeMetadataPtrTy; @@ -1757,7 +1877,7 @@ getTypeEntityForProtocolConformanceRecord(IRGenModule &IGM, // TODO: We should indirectly reference classes. For now directly // reference the class object, which is totally wrong for ObjC interop. - typeKind = ProtocolConformanceTypeKind::UniqueDirectClass; + typeKind = TypeMetadataRecordKind::UniqueDirectClass; if (hasKnownSwiftMetadata(IGM, clas)) entity = LinkEntity::forTypeMetadata( conformingType, @@ -1768,17 +1888,17 @@ getTypeEntityForProtocolConformanceRecord(IRGenModule &IGM, defaultTy = IGM.TypeMetadataStructTy; defaultPtrTy = IGM.TypeMetadataPtrTy; } - } else if (auto nom = conformingType->getNominalOrBoundGenericNominal()) { + } else { // Metadata for Clang types should be uniqued like foreign classes. if (nom->hasClangNode()) { - typeKind = ProtocolConformanceTypeKind::NonuniqueDirectType; + typeKind = TypeMetadataRecordKind::NonuniqueDirectType; entity = LinkEntity::forForeignTypeMetadataCandidate(conformingType); defaultTy = IGM.TypeMetadataStructTy; defaultPtrTy = IGM.TypeMetadataPtrTy; } else { // We can reference the canonical metadata for native value types // directly. - typeKind = ProtocolConformanceTypeKind::UniqueDirectType; + typeKind = TypeMetadataRecordKind::UniqueDirectType; entity = LinkEntity::forTypeMetadata( conformingType, TypeMetadataAddress::AddressPoint, @@ -1786,16 +1906,11 @@ getTypeEntityForProtocolConformanceRecord(IRGenModule &IGM, defaultTy = IGM.TypeMetadataStructTy; defaultPtrTy = IGM.TypeMetadataPtrTy; } - } else { - // TODO: Universal and/or structural conformances - llvm_unreachable("unhandled protocol conformance"); } - auto flags = ProtocolConformanceFlags() - .withTypeKind(typeKind) - .withConformanceKind(conformanceKind); + auto flags = ProtocolConformanceFlags().withTypeKind(typeKind); - return {flags.getValue(), *entity, defaultTy, defaultPtrTy}; + return {flags, *entity, defaultTy, defaultPtrTy}; } /// Form an LLVM constant for the relative distance between a reference @@ -1807,33 +1922,51 @@ static llvm::Constant *emitRelativeReference(IRGenModule &IGM, llvm::Constant *base, unsigned arrayIndex, unsigned structIndex) { - auto targetAddr = llvm::ConstantExpr::getPtrToInt(target.first, IGM.SizeTy); + llvm::Constant *relativeAddr = + IGM.emitDirectRelativeReference(target.first, base, + { arrayIndex, structIndex }); + + // If the reference is to a GOT entry, flag it by setting the low bit. + // (All of the base, direct target, and GOT entry need to be pointer-aligned + // for this to be OK.) + if (target.second == IRGenModule::DirectOrGOT::GOT) { + relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, + llvm::ConstantInt::get(IGM.RelativeAddressTy, 1)); + } - llvm::Constant *indexes[] = { - llvm::ConstantInt::get(IGM.Int32Ty, 0), - llvm::ConstantInt::get(IGM.Int32Ty, arrayIndex), - llvm::ConstantInt::get(IGM.Int32Ty, structIndex), + return relativeAddr; +} + +/// Form an LLVM constant for the relative distance between a reference +/// (appearing at gep (0, indices...) of `base`) and `target`. For now, +/// for this to succeed portably, both need to be globals defined in the +/// current translation unit. +llvm::Constant * +IRGenModule::emitDirectRelativeReference(llvm::Constant *target, + llvm::Constant *base, + ArrayRef baseIndices) { + // Convert the target to an integer. + auto targetAddr = llvm::ConstantExpr::getPtrToInt(target, SizeTy); + + SmallVector indices; + indices.push_back(llvm::ConstantInt::get(Int32Ty, 0)); + for (unsigned baseIndex : baseIndices) { + indices.push_back(llvm::ConstantInt::get(Int32Ty, baseIndex)); }; + // Drill down to the appropriate address in the base, then convert + // that to an integer. auto baseElt = llvm::ConstantExpr::getInBoundsGetElementPtr( - base->getType()->getPointerElementType(), base, indexes); - - auto baseAddr = llvm::ConstantExpr::getPtrToInt(baseElt, IGM.SizeTy); + base->getType()->getPointerElementType(), base, indices); + auto baseAddr = llvm::ConstantExpr::getPtrToInt(baseElt, SizeTy); + // The relative address is the difference between those. auto relativeAddr = llvm::ConstantExpr::getSub(targetAddr, baseAddr); // Relative addresses can be 32-bit even on 64-bit platforms. - if (IGM.SizeTy != IGM.RelativeAddressTy) + if (SizeTy != RelativeAddressTy) relativeAddr = llvm::ConstantExpr::getTrunc(relativeAddr, - IGM.RelativeAddressTy); - - // If the reference is to a GOT entry, flag it by setting the low bit. - // (All of the base, direct target, and GOT entry need to be pointer-aligned - // for this to be OK.) - if (target.second == IRGenModule::DirectOrGOT::GOT) { - relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, - llvm::ConstantInt::get(IGM.Int32Ty, 1)); - } + RelativeAddressTy); return relativeAddr; } @@ -1876,13 +2009,15 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { auto descriptorRef = getAddrOfLLVMVariableOrGOTEquivalent( LinkEntity::forProtocolDescriptor(conformance->getProtocol()), getPointerAlignment(), ProtocolDescriptorStructTy); - - auto typeEntity - = getTypeEntityForProtocolConformanceRecord(*this, conformance); + auto typeEntity = getTypeEntityInfo(*this, + conformance->getType()->getCanonicalType()); + auto flags = typeEntity.flags + .withConformanceKind(ProtocolConformanceReferenceKind::WitnessTable); // If the conformance is in this object's table, then the witness table // should also be in this object file, so we can always directly reference // it. + // TODO: Should use accessor kind for lazy conformances // TODO: Produce a relative reference to a private generator function // if the witness table requires lazy initialization, instantiation, or // conditional conformance checking. @@ -1898,7 +2033,7 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { emitRelativeReference(*this, descriptorRef, var, elts.size(), 0), emitRelativeReference(*this, typeRef, var, elts.size(), 1), emitRelativeReference(*this, witnessTableRef, var, elts.size(), 2), - llvm::ConstantInt::get(Int32Ty, typeEntity.flags), + llvm::ConstantInt::get(Int32Ty, flags.getValue()), }; auto record = llvm::ConstantStruct::get(ProtocolConformanceRecordTy, @@ -1915,6 +2050,64 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { return var; } +/// Emit type metadata for types that might not have explicit protocol conformances. +llvm::Constant *IRGenModule::emitTypeMetadataRecords() { + std::string sectionName; + switch (TargetInfo.OutputObjectFormat) { + case llvm::Triple::MachO: + sectionName = "__TEXT, __swift2_types, regular, no_dead_strip"; + break; + case llvm::Triple::ELF: + sectionName = ".swift2_type_metadata"; + break; + default: + llvm_unreachable("Don't know how to emit type metadata table for " + "the selected object format."); + } + + // Do nothing if the list is empty. + if (RuntimeResolvableTypes.empty()) + return nullptr; + + // Define the global variable for the conformance list. + // We have to do this before defining the initializer since the entries will + // contain offsets relative to themselves. + auto arrayTy = llvm::ArrayType::get(TypeMetadataRecordTy, + RuntimeResolvableTypes.size()); + + // FIXME: This needs to be a linker-local symbol in order for Darwin ld to + // resolve relocations relative to it. + auto var = new llvm::GlobalVariable(Module, arrayTy, + /*isConstant*/ true, + llvm::GlobalValue::PrivateLinkage, + /*initializer*/ nullptr, + "\x01l_type_metadata_table"); + + SmallVector elts; + for (auto type : RuntimeResolvableTypes) { + auto typeEntity = getTypeEntityInfo(*this, type); + auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent( + typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy); + + llvm::Constant *recordFields[] = { + emitRelativeReference(*this, typeRef, var, elts.size(), 0), + llvm::ConstantInt::get(Int32Ty, typeEntity.flags.getValue()), + }; + + auto record = llvm::ConstantStruct::get(TypeMetadataRecordTy, + recordFields); + elts.push_back(record); + } + + auto initializer = llvm::ConstantArray::get(arrayTy, elts); + + var->setInitializer(initializer); + var->setSection(sectionName); + var->setAlignment(getPointerAlignment().getValue()); + addUsedGlobal(var); + return var; +} + /// Fetch a global reference to the given Objective-C class. The /// result is of type ObjCClassPtrTy. llvm::Constant *IRGenModule::getAddrOfObjCClass(ClassDecl *theClass, @@ -1987,12 +2180,37 @@ IRGenModule::getAddrOfTypeMetadataAccessFunction(CanType type, return entry; } +/// Fetch the type metadata access function for the given generic type. +llvm::Function * +IRGenModule::getAddrOfGenericTypeMetadataAccessFunction( + NominalTypeDecl *nominal, + ArrayRef genericArgs, + ForDefinition_t forDefinition) { + assert(!genericArgs.empty()); + assert(nominal->isGenericContext()); + + auto type = nominal->getDeclaredType()->getCanonicalType(); + assert(isa(type)); + LinkEntity entity = LinkEntity::forTypeMetadataAccessFunction(type); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + auto fnType = llvm::FunctionType::get(TypeMetadataPtrTy, genericArgs, false); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = link.createFunction(*this, fnType, RuntimeCC, llvm::AttributeSet()); + return entry; +} + /// Get or create a type metadata cache variable. These are an /// implementation detail of type metadata access functions. llvm::Constant * IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type, ForDefinition_t forDefinition) { assert(!type->hasArchetype() && !type->hasTypeParameter()); + assert(!type->hasUnboundGenericType()); LinkEntity entity = LinkEntity::forTypeMetadataLazyCacheVariable(type); return getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition, TypeMetadataPtrTy, DebugTypeInfo()); @@ -2052,6 +2270,10 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, if (!section.empty()) var->setSection(section); + // Keep type metadata around for all types, although the runtime can currently + // only perform name lookup of non-generic types. + addRuntimeResolvableType(concreteType); + // For metadata patterns, we're done. if (isPattern) return var; @@ -2369,7 +2591,6 @@ Address IRGenModule::getAddrOfWitnessTableOffset(SILDeclRef code, ForDefinition_t forDefinition) { LinkEntity entity = LinkEntity::forWitnessTableOffset(code.getDecl(), - code.getResilienceExpansion(), code.uncurryLevel); return getAddrOfSimpleVariable(*this, GlobalVars, entity, SizeTy, getPointerAlignment(), @@ -2382,7 +2603,7 @@ Address IRGenModule::getAddrOfWitnessTableOffset(SILDeclRef code, Address IRGenModule::getAddrOfWitnessTableOffset(VarDecl *field, ForDefinition_t forDefinition) { LinkEntity entity = - LinkEntity::forWitnessTableOffset(field, ResilienceExpansion::Minimal, 0); + LinkEntity::forWitnessTableOffset(field, 0); return ::getAddrOfSimpleVariable(*this, GlobalVars, entity, SizeTy, getPointerAlignment(), forDefinition); @@ -2518,17 +2739,34 @@ Address IRGenFunction::createFixedSizeBufferAlloca(const llvm::Twine &name) { /// /// \returns an i8* with a null terminator; note that embedded nulls /// are okay -llvm::Constant *IRGenModule::getAddrOfGlobalString(StringRef data) { +/// +/// FIXME: willBeRelativelyAddressed is only needed to work around an ld64 bug +/// resolving relative references to coalesceable symbols. +/// It should be removed when fixed. rdar://problem/22674524 +llvm::Constant *IRGenModule::getAddrOfGlobalString(StringRef data, + bool willBeRelativelyAddressed) { // Check whether this string already exists. auto &entry = GlobalStrings[data]; - if (entry) return entry; + if (entry.second) { + // FIXME: Clear unnamed_addr if the global will be relative referenced + // to work around an ld64 bug. rdar://problem/22674524 + if (willBeRelativelyAddressed) + entry.first->setUnnamedAddr(false); + return entry.second; + } // If not, create it. This implicitly adds a trailing null. auto init = llvm::ConstantDataArray::getString(LLVMContext, data); auto global = new llvm::GlobalVariable(Module, init->getType(), true, llvm::GlobalValue::PrivateLinkage, init); - global->setUnnamedAddr(true); + // FIXME: ld64 crashes resolving relative references to coalesceable symbols. + // rdar://problem/22674524 + // If we intend to relatively address this string, don't mark it with + // unnamed_addr to prevent it from going into the cstrings section and getting + // coalesced. + if (!willBeRelativelyAddressed) + global->setUnnamedAddr(true); // Drill down to make an i8*. auto zero = llvm::ConstantInt::get(SizeTy, 0); @@ -2537,7 +2775,27 @@ llvm::Constant *IRGenModule::getAddrOfGlobalString(StringRef data) { global->getValueType(), global, indices); // Cache and return. - entry = address; + entry = {global, address}; + return address; +} + +llvm::Constant *IRGenModule::getAddrOfFieldName(StringRef Name) { + auto &entry = FieldNames[Name]; + if (entry.second) + return entry.second; + + auto init = llvm::ConstantDataArray::getString(LLVMContext, Name); + auto global = new llvm::GlobalVariable(Module, init->getType(), true, + llvm::GlobalValue::LinkOnceODRLinkage, + init); + global->setSection(getFieldNamesSectionName()); + + auto zero = llvm::ConstantInt::get(SizeTy, 0); + llvm::Constant *indices[] = { zero, zero }; + auto address = llvm::ConstantExpr::getInBoundsGetElementPtr( + global->getValueType(), global, indices); + + entry = { global, address }; return address; } @@ -2588,20 +2846,87 @@ StringRef IRGenModule::mangleType(CanType type, SmallVectorImpl &buffer) { return StringRef(buffer.data(), buffer.size()); } -/// Is the given declaration resilient? -bool IRGenModule::isResilient(Decl *D, ResilienceScope scope) { - auto NTD = dyn_cast(D); - if (!NTD) - return false; +/// Do we have to use resilient access patterns when working with this +/// declaration? +/// +/// IRGen is primarily concerned with resilient handling of the following: +/// - For structs, a struct's size might change +/// - For enums, new cases can be added +/// - For classes, the superclass might change the size or number +/// of stored properties +bool IRGenModule::isResilient(NominalTypeDecl *D, ResilienceExpansion expansion) { + return !D->hasFixedLayout(SILMod->getSwiftModule(), expansion); +} + +// The most general resilience expansion where the given declaration is visible. +ResilienceExpansion +IRGenModule::getResilienceExpansionForAccess(NominalTypeDecl *decl) { + if (decl->getModuleContext() == SILMod->getSwiftModule() && + decl->getFormalAccess() != Accessibility::Public) + return ResilienceExpansion::Maximal; + return ResilienceExpansion::Minimal; +} + +// The most general resilience expansion which has knowledge of the declaration's +// layout. Calling isResilient() with this scope will always return false. +ResilienceExpansion +IRGenModule::getResilienceExpansionForLayout(NominalTypeDecl *decl) { + if (isResilient(decl, ResilienceExpansion::Minimal)) + return ResilienceExpansion::Maximal; + + return getResilienceExpansionForAccess(decl); +} + +// The most general resilience expansion which has knowledge of the global +// variable's layout. +ResilienceExpansion +IRGenModule::getResilienceExpansionForLayout(SILGlobalVariable *global) { + if (hasPublicVisibility(global->getLinkage())) + return ResilienceExpansion::Minimal; + return ResilienceExpansion::Maximal; +} + +llvm::Constant *IRGenModule:: +getAddrOfGenericWitnessTableCache(const NormalProtocolConformance *conf, + ForDefinition_t forDefinition) { + auto entity = LinkEntity::forGenericProtocolWitnessTableCache(conf); + auto expectedTy = getGenericWitnessTableCacheTy(); + auto storageTy = (forDefinition ? expectedTy : nullptr); + return getAddrOfLLVMVariable(entity, getPointerAlignment(), storageTy, + expectedTy, DebugTypeInfo()); +} + +llvm::Function * +IRGenModule::getAddrOfGenericWitnessTableInstantiationFunction( + const NormalProtocolConformance *conf) { + auto forDefinition = ForDefinition; - switch (scope) { - case ResilienceScope::Component: - return !NTD->hasFixedLayout(SILMod->getSwiftModule()); - case ResilienceScope::Universal: - return !NTD->hasFixedLayout(); + LinkEntity entity = + LinkEntity::forGenericProtocolWitnessTableInstantiationFunction(conf); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) updateLinkageForDefinition(*this, entry, entity); + return entry; } - llvm_unreachable("Bad resilience scope"); + auto fnType = llvm::FunctionType::get(VoidTy, + { WitnessTablePtrTy, + TypeMetadataPtrTy, + Int8PtrPtrTy }, + /*varargs*/ false); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = link.createFunction(*this, fnType, RuntimeCC, llvm::AttributeSet()); + return entry; +} + +llvm::StructType *IRGenModule::getGenericWitnessTableCacheTy() { + if (auto ty = GenericWitnessTableCacheTy) return ty; + + GenericWitnessTableCacheTy = llvm::StructType::create(getLLVMContext(), + { Int16Ty, Int16Ty, RelativeAddressTy, RelativeAddressTy, + llvm::ArrayType::get(Int8PtrTy, swift::NumGenericMetadataPrivateDataWords) + }, "swift.generic_witness_table_cache"); + return GenericWitnessTableCacheTy; } /// Fetch the witness table access function for a protocol conformance. @@ -2680,6 +3005,50 @@ IRGenModule::getAddrOfWitnessTable(const NormalProtocolConformance *conf, WitnessTableTy, DebugTypeInfo()); } +llvm::Function * +IRGenModule::getAddrOfAssociatedTypeMetadataAccessFunction( + const NormalProtocolConformance *conformance, + AssociatedTypeDecl *associate) { + auto forDefinition = ForDefinition; + + LinkEntity entity = + LinkEntity::forAssociatedTypeMetadataAccessFunction(conformance, associate); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + auto fnType = getAssociatedTypeMetadataAccessFunctionTy(); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = link.createFunction(*this, fnType, RuntimeCC, llvm::AttributeSet()); + return entry; +} + +llvm::Function * +IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction( + const NormalProtocolConformance *conformance, + AssociatedTypeDecl *associate, + ProtocolDecl *associateProtocol) { + auto forDefinition = ForDefinition; + + assert(conformance->getProtocol() == associate->getProtocol()); + LinkEntity entity = + LinkEntity::forAssociatedTypeWitnessTableAccessFunction(conformance, + associate, + associateProtocol); + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + auto fnType = getAssociatedTypeWitnessTableAccessFunctionTy(); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + entry = link.createFunction(*this, fnType, RuntimeCC, llvm::AttributeSet()); + return entry; +} + /// Should we be defining the given helper function? static llvm::Function *shouldDefineHelper(IRGenModule &IGM, llvm::Constant *fn) { diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 472fac3f3ef76..f9fa31fd4800d 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -1,8 +1,8 @@ -//===--- GenEnum.cpp - Swift IR Generation For 'enum' Types -------------===// +//===--- GenEnum.cpp - Swift IR Generation For 'enum' Types ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -158,7 +158,12 @@ llvm::Constant *EnumImplStrategy::emitCaseNames() const { fieldNames.push_back('\0'); } // The final null terminator is provided by getAddrOfGlobalString. - return IGM.getAddrOfGlobalString(fieldNames); + return IGM.getAddrOfGlobalString(fieldNames, + /*willBeRelativelyAddressed*/ true); +} + +unsigned EnumImplStrategy::getPayloadSizeForMetadata() const { + llvm_unreachable("don't need payload size for this enum kind"); } llvm::Value *irgen::EnumImplStrategy:: @@ -227,6 +232,11 @@ irgen::EnumImplStrategy::getTagIndex(EnumElementDecl *Case) const { llvm_unreachable("couldn't find case"); } +int +irgen::EnumImplStrategy::getResilientTagIndex(EnumElementDecl *Case) const { + return getTagIndex(Case) - ElementsWithPayload.size(); +} + namespace { /// Implementation strategy for singleton enums, with zero or one cases. class SingletonEnumImplStrategy final : public EnumImplStrategy { @@ -280,7 +290,11 @@ namespace { llvm::Value * emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr) const override { - return llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0); + // Convert fragile tag index into resilient tag index. + // - -1 -- if we have a payload + // - 0 -- if there's no payload + return llvm::ConstantInt::get(IGF.IGM.Int32Ty, + ElementsWithPayload.size() > 0 ? -1 : 0); } llvm::Value * @@ -466,7 +480,7 @@ namespace { } void destroy(IRGenFunction &IGF, Address addr, SILType T) const override { - if (getSingleton() && !getSingleton()->isPOD(ResilienceScope::Component)) + if (getSingleton() && !getSingleton()->isPOD(ResilienceExpansion::Maximal)) getSingleton()->destroy(IGF, getSingletonAddress(IGF, addr), getSingletonType(IGF.IGM, T)); } @@ -557,6 +571,7 @@ namespace { IGF.Builder.CreateCondBr(xiBool, xiBB, noXIBB); IGF.Builder.emitBlock(xiBB); + ConditionalDominanceScope condition(IGF); copyWitnessFromElt(ValueWitness::ExtraInhabitantFlags); IGF.Builder.CreateBr(noXIBB); @@ -687,7 +702,11 @@ namespace { const override { Explosion value; loadAsTake(IGF, enumAddr, value); - return value.claimNext(); + + // Converting fragile tag index into resilient tag index is + // not necessary; there are no payload tags. + return IGF.Builder.CreateZExtOrTrunc(value.claimNext(), + IGF.IGM.Int32Ty); } llvm::Value *emitValueCaseTest(IRGenFunction &IGF, @@ -882,15 +901,9 @@ namespace { llvm::StructType *enumTy) override; // TODO: Support this function also for other enum implementation strategies. - int64_t getDiscriminatorIndex(EnumElementDecl *target) const override { + int64_t getDiscriminatorIndex(EnumElementDecl *elt) const override { // The elements are assigned discriminators in declaration order. - // FIXME: using a linear search here is fairly ridiculous. - unsigned index = 0; - for (auto elt : target->getParentEnum()->getAllElements()) { - if (elt == target) break; - index++; - } - return index; + return getTagIndex(elt); } // TODO: Support this function also for other enum implementation strategies. @@ -1043,7 +1056,7 @@ namespace { // C enums have arbitrary values and we don't preserve the mapping // between the case and raw value at runtime, so don't emit any // case names at all so that reflection can give up in this case. - return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); + return nullptr; } }; @@ -1188,10 +1201,10 @@ namespace { void assign(IRGenFunction &IGF, Explosion &e, Address addr) const override { assert(TIK >= Loadable); Explosion old; - if (!isPOD(ResilienceScope::Component)) + if (!isPOD(ResilienceExpansion::Maximal)) loadAsTake(IGF, addr, old); initialize(IGF, e, addr); - if (!isPOD(ResilienceScope::Component)) + if (!isPOD(ResilienceExpansion::Maximal)) consume(IGF, old); } @@ -1371,13 +1384,13 @@ namespace { // If the payload is POD, then we can use POD value semantics. auto &payloadTI = *ElementsWithPayload[0].ti; - if (payloadTI.isPOD(ResilienceScope::Component)) { + if (payloadTI.isPOD(ResilienceExpansion::Maximal)) { CopyDestroyKind = POD; // If the payload is a single refcounted pointer and we have a single // empty case, then the layout will be a nullable pointer, and we can // pass enum values directly into swift_retain/swift_release as-is. } else if (tik >= TypeInfoKind::Loadable - && payloadTI.isSingleRetainablePointer(ResilienceScope::Component, + && payloadTI.isSingleRetainablePointer(ResilienceExpansion::Maximal, &Refcounting) && ElementsWithNoPayload.size() == 1 // FIXME: All single-retainable-pointer types should eventually have @@ -1395,11 +1408,12 @@ namespace { return NumExtraInhabitantTagValues; } - /// Emit a call into the runtime to get the current enum payload tag; this - /// is an internal form that returns -1 in the payload case, or an index of - /// an empty case. + /// Emit a call into the runtime to get the current enum payload tag. + /// This returns a tag index in the range + /// [-ElementsWithPayload..ElementsWithNoPayload-1]. llvm::Value * - loadPayloadTag(IRGenFunction &IGF, Address enumAddr, SILType T) const { + emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr) + const override { auto payloadMetadata = emitPayloadMetadataForLayout(IGF, T); auto numEmptyCases = llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size()); @@ -1412,17 +1426,6 @@ namespace { {opaqueAddr, payloadMetadata, numEmptyCases}); } - /// Emit a call into the runtime to get the current enum case; this form - /// is used for reflection where we want the payload cases to start at - /// zero. - llvm::Value * - emitGetEnumTag(IRGenFunction &IGF, SILType T, Address enumAddr) - const override { - auto value = loadPayloadTag(IGF, enumAddr, T); - return IGF.Builder.CreateAdd(value, - llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1)); - } - /// The payload for a single-payload enum is always placed in front and /// will never have interleaved tag bits, so we can just bitcast the enum /// address to the payload type for either injection or projection of the @@ -1539,13 +1542,20 @@ namespace { std::tie(payloadTag, extraTag) = getNoPayloadCaseValue(Case); auto &ti = getFixedPayloadTypeInfo(); - bool hasExtraInhabitants = ti.getFixedExtraInhabitantCount(IGF.IGM) > 0; - + llvm::Value *payloadResult = nullptr; - if (hasExtraInhabitants) - payloadResult = payload.emitCompare(IGF, + // We can omit the payload check if this is the only case represented with + // the particular extra tag bit pattern set. + // + // TODO: This logic covers the most common case, when there's exactly one + // more no-payload case than extra inhabitants in the payload. This could + // be slightly generalized to cases where there's multiple tag bits and + // exactly one no-payload case in the highest used tag value. + if (!tagBits || + ElementsWithNoPayload.size() != getFixedExtraInhabitantCount(IGF.IGM)+1) + payloadResult = payload.emitCompare(IGF, ti.getFixedExtraInhabitantMask(IGF.IGM), - payloadTag); + payloadTag); // If any tag bits are present, they must match. llvm::Value *tagResult = nullptr; @@ -1600,19 +1610,15 @@ namespace { llvm::BasicBlock *payloadDest = blockForCase(getPayloadElement()); unsigned extraInhabitantCount = getNumExtraInhabitantTagValues(); - auto elements = getPayloadElement()->getParentEnum()->getAllElements(); + auto elements = ElementsWithNoPayload; auto elti = elements.begin(), eltEnd = elements.end(); - if (*elti == getPayloadElement()) - ++elti; - // Advance the enum element iterator, skipping the payload case. + // Advance the enum element iterator. auto nextCase = [&]() -> EnumElementDecl* { assert(elti != eltEnd); - auto result = *elti; - ++elti; - if (elti != eltEnd && *elti == getPayloadElement()) - ++elti; - return result; + Element elt = *elti; + elti++; + return elt.decl; }; // If there are extra tag bits, switch over them first. @@ -1747,7 +1753,7 @@ namespace { llvm::BasicBlock *defaultDest) const { // Create a map of the destination blocks for quicker lookup. llvm::DenseMap destMap(dests.begin(), - dests.end()); + dests.end()); // If there was no default branch in SIL, use an unreachable branch as // the default. @@ -1758,26 +1764,25 @@ namespace { } // Ask the runtime to find the case index. - auto caseIndex = loadPayloadTag(IGF, addr, T); + auto caseIndex = emitGetEnumTag(IGF, T, addr); // Switch on the index. auto *swi = IGF.Builder.CreateSwitch(caseIndex, defaultDest); - // Add the payload case. - auto payloadCase = destMap.find(getPayloadElement()); - if (payloadCase != destMap.end()) - swi->addCase(llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1), - payloadCase->second); - - // Add the empty cases. - unsigned emptyCaseIndex = 0; - for (auto &empty : ElementsWithNoPayload) { - auto emptyCase = destMap.find(empty.decl); - if (emptyCase != destMap.end()) - swi->addCase(llvm::ConstantInt::get(IGF.IGM.Int32Ty, emptyCaseIndex), - emptyCase->second); - ++emptyCaseIndex; - } + auto emitCase = [&](Element elt) { + auto tagVal = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, + getResilientTagIndex(elt.decl)); + auto found = destMap.find(elt.decl); + if (found != destMap.end()) + swi->addCase(tagVal, found->second); + }; + + for (auto &elt : ElementsWithPayload) + emitCase(elt); + + for (auto &elt : ElementsWithNoPayload) + emitCase(elt); // Emit the unreachable block, if any. if (unreachableBB) { @@ -1822,20 +1827,6 @@ namespace { } private: - // Get the index of an enum element among the non-payload cases. - unsigned getSimpleElementTagIndex(EnumElementDecl *elt) const { - assert(elt != getPayloadElement() && "is payload element"); - unsigned i = 0; - // FIXME: linear search - for (auto *enumElt : elt->getParentEnum()->getAllElements()) { - if (elt == enumElt) - return i; - if (enumElt != getPayloadElement()) - ++i; - } - llvm_unreachable("element was not a member of enum"); - } - // Get the payload and extra tag (if any) parts of the discriminator for // a no-data case. std::pair @@ -1847,7 +1838,7 @@ namespace { // Non-payload cases use extra inhabitants, if any, or are discriminated // by setting the tag bits. - unsigned tagIndex = getSimpleElementTagIndex(elt); + unsigned tagIndex = getResilientTagIndex(elt); unsigned numExtraInhabitants = getNumExtraInhabitantTagValues(); APInt payload; unsigned extraTagValue; @@ -1996,7 +1987,7 @@ namespace { auto *noPayloadBB = llvm::BasicBlock::Create(C); // Ask the runtime what case we have. - llvm::Value *which = loadPayloadTag(IGF, addr, T); + llvm::Value *which = emitGetEnumTag(IGF, T, addr); // If it's -1 then we have the payload. llvm::Value *hasPayload = IGF.Builder.CreateICmpEQ(which, @@ -2072,6 +2063,7 @@ namespace { llvm::BasicBlock *endBB = testFixedEnumContainsPayload(IGF, payload, extraTag); if (PayloadBitCount > 0) { + ConditionalDominanceScope condition(IGF); Explosion payloadValue; Explosion payloadCopy; auto &loadableTI = getLoadablePayloadTypeInfo(); @@ -2120,6 +2112,7 @@ namespace { // If we did, consume it. if (PayloadBitCount > 0) { + ConditionalDominanceScope condition(IGF); Explosion payloadValue; auto &loadableTI = getLoadablePayloadTypeInfo(); loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); @@ -2162,6 +2155,7 @@ namespace { // If we did, consume it. if (PayloadBitCount > 0) { + ConditionalDominanceScope condition(IGF); Explosion payloadValue; auto &loadableTI = getLoadablePayloadTypeInfo(); loadableTI.unpackFromEnumPayload(IGF, payload, payloadValue, 0); @@ -2194,6 +2188,8 @@ namespace { // Check that there is a payload at the address. llvm::BasicBlock *endBB = testEnumContainsPayload(IGF, addr, T); + ConditionalDominanceScope condition(IGF); + // If there is, project and destroy it. Address payloadAddr = projectPayloadData(IGF, addr); getPayloadTypeInfo().destroy(IGF, payloadAddr, @@ -2255,7 +2251,7 @@ namespace { ElementsWithNoPayload.size())}); } - /// Emit an reassignment sequence from an enum at one address to another. + /// Emit a reassignment sequence from an enum at one address to another. void emitIndirectAssign(IRGenFunction &IGF, Address dest, Address src, SILType T, IsTake_t isTake) @@ -2277,46 +2273,64 @@ namespace { llvm::BasicBlock *noDestPayloadBB = testEnumContainsPayload(IGF, dest, T); - // Here, the destination has a payload. Now see if the source also has - // one. - llvm::BasicBlock *destNoSrcPayloadBB - = testEnumContainsPayload(IGF, src, T); + { + ConditionalDominanceScope destCondition(IGF); - // Here, both source and destination have payloads. Do the reassignment - // of the payload in-place. - if (isTake) - getPayloadTypeInfo().assignWithTake(IGF, destData, srcData, PayloadT); - else - getPayloadTypeInfo().assignWithCopy(IGF, destData, srcData, PayloadT); - IGF.Builder.CreateBr(endBB); + // Here, the destination has a payload. Now see if the source also + // has one. + llvm::BasicBlock *destNoSrcPayloadBB + = testEnumContainsPayload(IGF, src, T); - // If the destination has a payload but the source doesn't, we can destroy - // the payload and primitive-store the new no-payload value. - IGF.Builder.emitBlock(destNoSrcPayloadBB); - getPayloadTypeInfo().destroy(IGF, destData, PayloadT); - emitPrimitiveCopy(IGF, dest, src, T); - IGF.Builder.CreateBr(endBB); + { + ConditionalDominanceScope destSrcCondition(IGF); + + // Here, both source and destination have payloads. Do the + // reassignment of the payload in-place. + getPayloadTypeInfo().assign(IGF, destData, srcData, + isTake, PayloadT); + IGF.Builder.CreateBr(endBB); + } + + // If the destination has a payload but the source doesn't, we can + // destroy the payload and primitive-store the new no-payload value. + IGF.Builder.emitBlock(destNoSrcPayloadBB); + { + ConditionalDominanceScope destNoSrcCondition(IGF); + getPayloadTypeInfo().destroy(IGF, destData, PayloadT); + emitPrimitiveCopy(IGF, dest, src, T); + IGF.Builder.CreateBr(endBB); + } + } // Now, if the destination has no payload, check if the source has one. IGF.Builder.emitBlock(noDestPayloadBB); - llvm::BasicBlock *noDestNoSrcPayloadBB - = testEnumContainsPayload(IGF, src, T); - - // Here, the source has a payload but the destination doesn't. We can - // copy-initialize the source over the destination, then primitive-store - // the zero extra tag (if any). - if (isTake) - getPayloadTypeInfo().initializeWithTake(IGF, destData, srcData, PayloadT); - else - getPayloadTypeInfo().initializeWithCopy(IGF, destData, srcData, PayloadT); - emitInitializeExtraTagBitsForPayload(IGF, dest, T); - IGF.Builder.CreateBr(endBB); + { + ConditionalDominanceScope noDestCondition(IGF); + llvm::BasicBlock *noDestNoSrcPayloadBB + = testEnumContainsPayload(IGF, src, T); + + { + ConditionalDominanceScope noDestSrcCondition(IGF); + + // Here, the source has a payload but the destination doesn't. + // We can copy-initialize the source over the destination, then + // primitive-store the zero extra tag (if any). + + getPayloadTypeInfo().initialize(IGF, destData, srcData, isTake, + PayloadT); + emitInitializeExtraTagBitsForPayload(IGF, dest, T); + IGF.Builder.CreateBr(endBB); + } - // If neither destination nor source have payloads, we can just primitive- - // store the new empty-case value. - IGF.Builder.emitBlock(noDestNoSrcPayloadBB); - emitPrimitiveCopy(IGF, dest, src, T); - IGF.Builder.CreateBr(endBB); + // If neither destination nor source have payloads, we can just + // primitive-store the new empty-case value. + IGF.Builder.emitBlock(noDestNoSrcPayloadBB); + { + ConditionalDominanceScope noDestNoSrcCondition(IGF); + emitPrimitiveCopy(IGF, dest, src, T); + IGF.Builder.CreateBr(endBB); + } + } IGF.Builder.emitBlock(endBB); return; @@ -2366,22 +2380,25 @@ namespace { llvm::BasicBlock *noSrcPayloadBB = testEnumContainsPayload(IGF, src, T); - // Here, the source value has a payload. Initialize the destination with - // it, and set the extra tag if any to zero. - if (isTake) - getPayloadTypeInfo().initializeWithTake(IGF, destData, srcData, - getPayloadType(IGF.IGM, T)); - else - getPayloadTypeInfo().initializeWithCopy(IGF, destData, srcData, - getPayloadType(IGF.IGM, T)); - emitInitializeExtraTagBitsForPayload(IGF, dest, T); - IGF.Builder.CreateBr(endBB); + { + ConditionalDominanceScope condition(IGF); + + // Here, the source value has a payload. Initialize the destination + // with it, and set the extra tag if any to zero. + getPayloadTypeInfo().initialize(IGF, destData, srcData, isTake, + getPayloadType(IGF.IGM, T)); + emitInitializeExtraTagBitsForPayload(IGF, dest, T); + IGF.Builder.CreateBr(endBB); + } // If the source value has no payload, we can primitive-store the // empty-case value. IGF.Builder.emitBlock(noSrcPayloadBB); - emitPrimitiveCopy(IGF, dest, src, T); - IGF.Builder.CreateBr(endBB); + { + ConditionalDominanceScope condition(IGF); + emitPrimitiveCopy(IGF, dest, src, T); + IGF.Builder.CreateBr(endBB); + } IGF.Builder.emitBlock(endBB); return; @@ -2484,13 +2501,13 @@ namespace { projectExtraTagBits(IGF, enumAddr)); } + /// Constructs an enum value using a tag index in the range + /// [-ElementsWithPayload..ElementsWithNoPayload-1]. void emitStoreTag(IRGenFunction &IGF, SILType T, Address enumAddr, llvm::Value *tag) const override { llvm::Value *payload = emitPayloadMetadataForLayout(IGF, T); - llvm::Value *caseIndex = IGF.Builder.CreateSub(tag, - llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, 1)); llvm::Value *numEmptyCases = llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithNoPayload.size()); @@ -2499,7 +2516,7 @@ namespace { IGF.IGM.OpaquePtrTy); IGF.Builder.CreateCall(IGF.IGM.getStoreEnumTagSinglePayloadFn(), - {opaqueAddr, payload, caseIndex, numEmptyCases}); + {opaqueAddr, payload, tag, numEmptyCases}); } void initializeMetadata(IRGenFunction &IGF, @@ -2587,7 +2604,7 @@ namespace { auto &payloadTI = getFixedPayloadTypeInfo(); unsigned totalSize = cast(TI)->getFixedSize().getValueInBits(); - if (payloadTI.isKnownEmpty()) + if (payloadTI.isKnownEmpty(ResilienceExpansion::Maximal)) return APInt::getAllOnesValue(totalSize); auto baseMask = getFixedPayloadTypeInfo().getFixedExtraInhabitantMask(IGM); @@ -2628,7 +2645,7 @@ namespace { auto &payloadTI = getFixedPayloadTypeInfo(); ClusteredBitVector extraInhabitantsMask; - if (!payloadTI.isKnownEmpty()) + if (!payloadTI.isKnownEmpty(ResilienceExpansion::Maximal)) extraInhabitantsMask = getBitVectorFromAPInt(payloadTI.getFixedExtraInhabitantMask(IGM)); // Extend to include the extra tag bits, which are always significant. @@ -2672,6 +2689,10 @@ namespace { // The number of tag values used for no-payload cases. unsigned NumEmptyElementTags = ~0u; + // The payload size in bytes. This might need to be written to metadata + // if it depends on resilient types. + unsigned PayloadSize; + /// More efficient value semantics implementations for certain enum layouts. enum CopyDestroyStrategy { /// No special behavior. @@ -2692,6 +2713,7 @@ namespace { CopyDestroyStrategy CopyDestroyKind; ReferenceCounting Refcounting; + bool AllowFixedLayoutOptimizations; static EnumPayloadSchema getPayloadSchema(ArrayRef payloads) { // TODO: We might be able to form a nicer schema if the payload elements @@ -2711,6 +2733,7 @@ namespace { MultiPayloadEnumImplStrategy(IRGenModule &IGM, TypeInfoKind tik, IsFixedSize_t alwaysFixedSize, + bool allowFixedLayoutOptimizations, unsigned NumElements, std::vector &&WithPayload, std::vector &&WithNoPayload) @@ -2719,7 +2742,8 @@ namespace { std::move(WithPayload), std::move(WithNoPayload), getPayloadSchema(WithPayload)), - CopyDestroyKind(Normal) + CopyDestroyKind(Normal), + AllowFixedLayoutOptimizations(allowFixedLayoutOptimizations) { assert(ElementsWithPayload.size() > 1); @@ -2730,14 +2754,14 @@ namespace { bool allSingleRefcount = true; bool haveRefcounting = false; for (auto &elt : ElementsWithPayload) { - if (!elt.ti->isPOD(ResilienceScope::Component)) + if (!elt.ti->isPOD(ResilienceExpansion::Maximal)) allPOD = false; - if (!elt.ti->isBitwiseTakable(ResilienceScope::Component)) + if (!elt.ti->isBitwiseTakable(ResilienceExpansion::Maximal)) allBitwiseTakable = false; // refcounting is only set in the else branches ReferenceCounting refcounting; - if (!elt.ti->isSingleRetainablePointer(ResilienceScope::Component, + if (!elt.ti->isSingleRetainablePointer(ResilienceExpansion::Maximal, &refcounting)) { allSingleRefcount = false; } else if (haveRefcounting) { @@ -2774,7 +2798,17 @@ namespace { // the payload area size from all of the cases, so cache it in the // metadata. For fixed-layout cases this isn't necessary (except for // reflection, but it's OK if reflection is a little slow). - return TIK < Fixed; + // + // Note that even if from within our module the enum has a fixed layout, + // we might need the payload size if from another module the enum has + // a dynamic size, which can happen if the enum contains a resilient + // payload. + return !AllowFixedLayoutOptimizations; + } + + unsigned getPayloadSizeForMetadata() const override { + assert(TIK >= Fixed); + return PayloadSize; } TypeInfo *completeEnumTypeLayout(TypeConverter &TC, @@ -2943,7 +2977,8 @@ namespace { return {destructured.payload, destructured.extraTagBits, tag}; } - + + /// Returns a tag index in the range [0..NumElements-1]. llvm::Value * loadDynamicTag(IRGenFunction &IGF, Address addr, SILType T) const { addr = IGF.Builder.CreateBitCast(addr, IGF.IGM.OpaquePtrTy); @@ -2956,7 +2991,10 @@ namespace { return call; } - + + /// Returns a tag index in the range [0..ElementsWithPayload-1] + /// if the current case is a payload case, otherwise returns + /// an undefined value. llvm::Value * loadPayloadTag(IRGenFunction &IGF, Address addr, SILType T) const { if (TIK >= Fixed) { @@ -2973,18 +3011,27 @@ namespace { public: + /// Returns a tag index in the range + /// [-ElementsWithPayload..ElementsWithNoPayload+1]. llvm::Value * emitGetEnumTag(IRGenFunction &IGF, SILType T, Address addr) const override { + unsigned numPayloadCases = ElementsWithPayload.size(); + llvm::Constant *payloadCases = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, numPayloadCases); + if (TIK < Fixed) { // Ask the runtime to extract the dynamically-placed tag. - return loadDynamicTag(IGF, addr, T); + llvm::Value *tagValue = loadDynamicTag(IGF, addr, T); + + // Convert fragile tag index into resilient tag index. + return IGF.Builder.CreateSub(tagValue, payloadCases); } // For fixed-size enums, the currently inhabited case is a function of // both the payload tag and the payload value. // - // Low-numbered payload tags correspond to payload cases. No payload + // Low-numbered payload tags correspond to payload cases. No-payload // cases are represented with the remaining payload tags. // Load the fixed-size representation and derive the tags. @@ -2994,56 +3041,61 @@ namespace { // Load the payload tag. llvm::Value *tagValue = extractPayloadTag(IGF, payload, extraTagBits); + tagValue = IGF.Builder.CreateZExtOrTrunc(tagValue, IGF.IGM.Int32Ty); + + // Subtract number of payload cases from the payload tag. + // + // If we have a payload case, this yields a negative value, which is the + // final resilient tag index. + // + // If we have a no-payload case, this yields a non-negative value, which + // is the most significant bits of the current case index. + tagValue = IGF.Builder.CreateSub(tagValue, payloadCases); // If we don't have any no-payload cases, we are done -- the payload tag // alone is enough to distinguish between all cases. if (ElementsWithNoPayload.empty()) return tagValue; - tagValue = IGF.Builder.CreateZExtOrTrunc(tagValue, IGF.IGM.Int32Ty); - // To distinguish between non-payload cases, load the payload value and // strip off the spare bits. auto OccupiedBits = CommonSpareBits; OccupiedBits.flipAll(); + // Load the payload value, to distinguish no-payload cases. llvm::Value *payloadValue = payload.emitGatherSpareBits( IGF, OccupiedBits, 0, 32); - llvm::Constant *payloadCases = - llvm::ConstantInt::get(IGF.IGM.Int32Ty, ElementsWithPayload.size()); - llvm::Value *currentCase; unsigned numCaseBits = getNumCaseBits(); if (numCaseBits >= 32 || getNumCasesPerTag() >= ElementsWithNoPayload.size()) { // All no-payload cases have the same payload tag, so we can just use - // the payload value to distinguish between no-payload cases. + // the payload value to distinguish between them. + // + // The payload value is a tag index in the range + // [0..ElementsWithNoPayload], so we are done. currentCase = payloadValue; } else { // The no-payload cases are distributed between multiple payload tags; // combine the payload tag with the payload value. - // First, subtract number of payload cases from the payload tag to get - // the most significant bits of the current case. - currentCase = IGF.Builder.CreateSub(tagValue, payloadCases); - - // Now, shift these bits into place. + // Shift the most significant bits of the tag value into place. llvm::Constant *numCaseBitsVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, numCaseBits); - currentCase = IGF.Builder.CreateShl(currentCase, numCaseBitsVal); + currentCase = IGF.Builder.CreateShl(tagValue, numCaseBitsVal); // Add the payload value to the shifted payload tag. + // + // The result is a tag index in the range [0..ElementsWithNoPayload], + // so we are done. currentCase = IGF.Builder.CreateOr(currentCase, payloadValue); } - // Now, we have the index of a no-payload case. Add the number of payload - // cases back, to get an index of a case. - currentCase = IGF.Builder.CreateAdd(currentCase, payloadCases); - // Test if this is a payload or no-payload case. - llvm::Value *match = IGF.Builder.CreateICmpUGE(tagValue, payloadCases); + llvm::Value *match = IGF.Builder.CreateICmpSGE(tagValue, + llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0)); // Return one of the two values we computed based on the above. return IGF.Builder.CreateSelect(match, currentCase, tagValue); @@ -3246,34 +3298,25 @@ namespace { if (!defaultDest) defaultDest = unreachableBB; - auto blockForCase = [&](EnumElementDecl *theCase) -> llvm::BasicBlock* { - auto found = destMap.find(theCase); - if (found == destMap.end()) - return defaultDest; - else - return found->second; - }; - auto *tagSwitch = IGF.Builder.CreateSwitch(tag, unreachableBB, NumElements); - unsigned tagIndex = 0; - - // Payload tags come first. - for (auto &elt : ElementsWithPayload) { - auto tagVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tagIndex); - tagSwitch->addCase(tagVal, blockForCase(elt.decl)); - ++tagIndex; - } - - // Next come empty tags. - for (auto &elt : ElementsWithNoPayload) { - auto tagVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tagIndex); - tagSwitch->addCase(tagVal, blockForCase(elt.decl)); - ++tagIndex; - } + auto emitCase = [&](Element elt) { + auto tagVal = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, + getTagIndex(elt.decl)); + auto found = destMap.find(elt.decl); + tagSwitch->addCase(tagVal, + (found == destMap.end() + ? defaultDest + : found->second)); + }; - assert(tagIndex == NumElements); + for (auto &elt : ElementsWithPayload) + emitCase(elt); + + for (auto &elt : ElementsWithNoPayload) + emitCase(elt); // Delete the unreachable default block if we didn't use it, or emit it // if we did. @@ -3524,7 +3567,7 @@ namespace { auto &payloadTI = *payloadCasePair.ti; // Trivial payloads don't need any work. - if (payloadTI.isPOD(ResilienceScope::Component)) { + if (payloadTI.isPOD(ResilienceExpansion::Maximal)) { ++tagIndex; continue; } @@ -3533,6 +3576,8 @@ namespace { auto *caseBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext()); swi->addCase(llvm::ConstantInt::get(tagTy, tagIndex), caseBB); + ConditionalDominanceScope condition(IGF); + IGF.Builder.emitBlock(caseBB); f(tagIndex, payloadCasePair); IGF.Builder.CreateBr(endBB); @@ -3737,6 +3782,7 @@ namespace { auto *noAliasBB = llvm::BasicBlock::Create(C); IGF.Builder.CreateCondBr(alias, endBB, noAliasBB); IGF.Builder.emitBlock(noAliasBB); + ConditionalDominanceScope condition(IGF); // Destroy the old value. destroy(IGF, dest, T); @@ -3803,8 +3849,8 @@ namespace { auto &payloadTI = *payloadCasePair.ti; // Trivial and, in the case of a take, bitwise-takable payloads, // can all share the default path. - if (payloadTI.isPOD(ResilienceScope::Component) - || (isTake && payloadTI.isBitwiseTakable(ResilienceScope::Component))) { + if (payloadTI.isPOD(ResilienceExpansion::Maximal) + || (isTake && payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal))) { ++tagIndex; continue; } @@ -3815,6 +3861,8 @@ namespace { swi->addCase(llvm::ConstantInt::get(tagTy, tagIndex), caseBB); IGF.Builder.emitBlock(caseBB); + ConditionalDominanceScope condition(IGF); + // Do the take/copy of the payload. Address srcData = IGF.Builder.CreateBitCast(src, payloadTI.getStorageType()->getPointerTo()); @@ -3841,6 +3889,7 @@ namespace { // For trivial payloads (including no-payload cases), we can just // primitive-copy to the destination. IGF.Builder.emitBlock(trivialBB); + ConditionalDominanceScope condition(IGF); emitPrimitiveCopy(IGF, dest, src, T); IGF.Builder.CreateBr(endBB); @@ -4062,14 +4111,23 @@ namespace { SILType T, Address enumAddr, llvm::Value *tag) const override { + llvm::Value *numPayloadCases = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, + ElementsWithPayload.size()); + // Use the runtime to initialize dynamic cases. if (TIK < Fixed) { - // No-payload case indexes start after the payload cases. + // Convert resilient tag index into fragile tag index. + tag = IGF.Builder.CreateAdd(tag, numPayloadCases); + return storeDynamicTag(IGF, enumAddr, tag, T); } // If there are no empty cases, don't need a conditional. if (ElementsWithNoPayload.empty()) { + // Convert resilient tag index into fragile tag index. + tag = IGF.Builder.CreateAdd(tag, numPayloadCases); + storePayloadTag(IGF, enumAddr, tag, T); return; } @@ -4079,21 +4137,28 @@ namespace { auto payloadBB = llvm::BasicBlock::Create(C); auto endBB = llvm::BasicBlock::Create(C); - llvm::Value *numPayloadCases = - llvm::ConstantInt::get(IGF.IGM.Int32Ty, - ElementsWithPayload.size()); - llvm::Value *cond = IGF.Builder.CreateICmpUGE(tag, numPayloadCases); + llvm::Value *cond = IGF.Builder.CreateICmpSGE(tag, + llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0)); IGF.Builder.CreateCondBr(cond, noPayloadBB, payloadBB); IGF.Builder.emitBlock(noPayloadBB); - llvm::Value *noPayloadTag = IGF.Builder.CreateSub(tag, numPayloadCases); - storeNoPayloadTag(IGF, enumAddr, noPayloadTag, T); - IGF.Builder.CreateBr(endBB); - + { + ConditionalDominanceScope condition(IGF); + storeNoPayloadTag(IGF, enumAddr, tag, T); + IGF.Builder.CreateBr(endBB); + } + IGF.Builder.emitBlock(payloadBB); - storePayloadTag(IGF, enumAddr, tag, T); - IGF.Builder.CreateBr(endBB); - + { + ConditionalDominanceScope condition(IGF); + + // Convert resilient tag index into fragile tag index. + tag = IGF.Builder.CreateAdd(tag, numPayloadCases); + + storePayloadTag(IGF, enumAddr, tag, T); + IGF.Builder.CreateBr(endBB); + } + IGF.Builder.emitBlock(endBB); } @@ -4275,7 +4340,7 @@ namespace { void destructiveProjectDataForLoad(IRGenFunction &IGF, SILType T, Address enumAddr) const override { - emitDestructiveProjectEnumDataCall(IGF, T, enumAddr.getAddress()); + emitDestructiveProjectEnumDataCall(IGF, T, enumAddr); } void storeTag(IRGenFunction &IGF, @@ -4283,17 +4348,18 @@ namespace { Address enumAddr, EnumElementDecl *Case) const override { emitDestructiveInjectEnumTagCall(IGF, T, - getTagIndex(Case), - enumAddr.getAddress()); + getResilientTagIndex(Case), + enumAddr); } llvm::Value * emitIndirectCaseTest(IRGenFunction &IGF, SILType T, Address enumAddr, EnumElementDecl *Case) const override { - llvm::Value *tag = emitGetEnumTagCall(IGF, T, enumAddr.getAddress()); - llvm::Value *expectedTag = llvm::ConstantInt::get(IGF.IGM.Int32Ty, - getTagIndex(Case)); + llvm::Value *tag = emitGetEnumTagCall(IGF, T, enumAddr); + llvm::Value *expectedTag = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, + getResilientTagIndex(Case)); return IGF.Builder.CreateICmpEQ(tag, expectedTag); } @@ -4304,7 +4370,7 @@ namespace { llvm::BasicBlock*>> dests, llvm::BasicBlock *defaultDest) const override { // Switch on the tag value. - llvm::Value *tag = emitGetEnumTagCall(IGF, T, enumAddr.getAddress()); + llvm::Value *tag = emitGetEnumTagCall(IGF, T, enumAddr); // Create a map of the destination blocks for quicker lookup. llvm::DenseMap destMap(dests.begin(), @@ -4321,29 +4387,20 @@ namespace { auto *tagSwitch = IGF.Builder.CreateSwitch(tag, defaultDest, NumElements); - unsigned tagIndex = 0; - - // Payload tags come first. - for (auto &elt : ElementsWithPayload) { + auto emitCase = [&](Element elt) { + auto tagVal = + llvm::ConstantInt::get(IGF.IGM.Int32Ty, + getResilientTagIndex(elt.decl)); auto found = destMap.find(elt.decl); - if (found != destMap.end()) { - auto tagVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tagIndex); + if (found != destMap.end()) tagSwitch->addCase(tagVal, found->second); - } - ++tagIndex; - } + }; - // Next come empty tags. - for (auto &elt : ElementsWithNoPayload) { - auto found = destMap.find(elt.decl); - if (found != destMap.end()) { - auto tagVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tagIndex); - tagSwitch->addCase(tagVal, found->second); - } - ++tagIndex; - } + for (auto &elt : ElementsWithPayload) + emitCase(elt); - assert(tagIndex == NumElements); + for (auto &elt : ElementsWithNoPayload) + emitCase(elt); // Delete the unreachable default block if we didn't use it, or emit it // if we did. @@ -4359,33 +4416,33 @@ namespace { SILType T) const override { emitAssignWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress()); + dest, src); } void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { emitAssignWithTakeCall(IGF, T, - dest.getAddress(), src.getAddress()); + dest, src); } void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { emitInitializeWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress()); + dest, src); } void initializeWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { emitInitializeWithTakeCall(IGF, T, - dest.getAddress(), src.getAddress()); + dest, src); } void destroy(IRGenFunction &IGF, Address addr, SILType T) const override { - emitDestroyCall(IGF, T, addr.getAddress()); + emitDestroyCall(IGF, T, addr); } void getSchema(ExplosionSchema &schema) const override { @@ -4535,14 +4592,14 @@ namespace { llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, SILType T) const override { - return emitGetExtraInhabitantIndexCall(IGF, T, src.getAddress()); + return emitGetExtraInhabitantIndexCall(IGF, T, src); } void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, Address dest, SILType T) const override { - emitStoreExtraInhabitantCall(IGF, T, index, dest.getAddress()); + emitStoreExtraInhabitantCall(IGF, T, index, dest); } APInt @@ -4570,9 +4627,29 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC, unsigned numElements = 0; TypeInfoKind tik = Loadable; IsFixedSize_t alwaysFixedSize = IsFixedSize; + bool allowFixedLayoutOptimizations = true; std::vector elementsWithPayload; std::vector elementsWithNoPayload; + // Resilient enums are manipulated as opaque values, except we still + // make the following assumptions: + // 1) Physical case indices won't change + // 2) The indirect-ness of cases won't change + // 3) Payload types won't change in a non-resilient way + bool isResilient = TC.IGM.isResilient(theEnum, ResilienceExpansion::Maximal); + + // The most general resilience scope where the enum type is visible. + // Case numbering must not depend on any information that is not static + // in this resilience scope. + ResilienceExpansion accessScope = + TC.IGM.getResilienceExpansionForAccess(theEnum); + + // The most general resilience scope where the enum's layout is known. + // Fixed-size optimizations can be applied if all payload types are + // fixed-size from this resilience scope. + ResilienceExpansion layoutScope = + TC.IGM.getResilienceExpansionForLayout(theEnum); + for (auto elt : theEnum->getAllElements()) { numElements++; @@ -4601,14 +4678,18 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC, = TC.tryGetCompleteTypeInfo(origArgLoweredTy.getSwiftRValueType()); assert(origArgTI && "didn't complete type info?!"); - // If the unsubstituted argument contains a generic parameter type, or if - // the substituted argument is not universally fixed-size, we need to - // constrain our layout optimizations to what the runtime can reproduce. - if (!origArgTI->isFixedSize(ResilienceScope::Universal)) - alwaysFixedSize = IsNotFixedSize; - - auto loadableOrigArgTI = dyn_cast(origArgTI); - if (loadableOrigArgTI && loadableOrigArgTI->isKnownEmpty()) { + // If the unsubstituted argument contains a generic parameter type, or + // is not fixed-size in all resilience domains that have knowledge of + // this enum's layout, we need to constrain our layout optimizations to + // what the runtime can reproduce. + if (!isResilient && + !origArgTI->isFixedSize(layoutScope)) + allowFixedLayoutOptimizations = false; + + // If the payload is empty, turn the case into a no-payload case, but + // only if case numbering remains unchanged from all resilience domains + // that can see the enum. + if (origArgTI->isKnownEmpty(accessScope)) { elementsWithNoPayload.push_back({elt, nullptr, nullptr}); } else { // *Now* apply the substitutions and get the type info for the instance's @@ -4618,30 +4699,36 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC, auto *substArgTI = &TC.IGM.getTypeInfo(fieldTy); elementsWithPayload.push_back({elt, substArgTI, origArgTI}); - if (!substArgTI->isFixedSize()) - tik = Opaque; - else if (!substArgTI->isLoadable() && tik > Fixed) - tik = Fixed; - // If the substituted argument contains a type that is not universally - // fixed-size, we need to constrain our layout optimizations to what - // the runtime can reproduce. - if (!substArgTI->isFixedSize(ResilienceScope::Universal)) - alwaysFixedSize = IsNotFixedSize; + if (!isResilient) { + if (!substArgTI->isFixedSize(ResilienceExpansion::Maximal)) + tik = Opaque; + else if (!substArgTI->isLoadable() && tik > Fixed) + tik = Fixed; + + // If the substituted argument contains a type that is not fixed-size + // in all resilience domains that have knowledge of this enum's layout, + // we need to constrain our layout optimizations to what the runtime + // can reproduce. + if (!substArgTI->isFixedSize(layoutScope)) { + alwaysFixedSize = IsNotFixedSize; + allowFixedLayoutOptimizations = false; + } + } } } + // Resilient tag numbering decreases for payload tags, so reverse the + // payload tags if this enum is resilient from any context. + if (TC.IGM.isResilient(theEnum, ResilienceExpansion::Minimal)) + std::reverse(elementsWithPayload.begin(), elementsWithPayload.end()); + assert(numElements == elementsWithPayload.size() + elementsWithNoPayload.size() && "not all elements accounted for"); - // Resilient enums are manipulated as opaque values, except we still - // make the following assumptions: - // 1) Physical case indices won't change - // 2) The indirect-ness of cases won't change - // 3) Payload types won't change in a non-resilient way - if (TC.IGM.isResilient(theEnum, ResilienceScope::Component)) { + if (isResilient) { return new ResilientEnumImplStrategy(TC.IGM, numElements, std::move(elementsWithPayload), @@ -4665,6 +4752,7 @@ EnumImplStrategy *EnumImplStrategy::get(TypeConverter &TC, std::move(elementsWithNoPayload)); if (elementsWithPayload.size() > 1) return new MultiPayloadEnumImplStrategy(TC.IGM, tik, alwaysFixedSize, + allowFixedLayoutOptimizations, numElements, std::move(elementsWithPayload), std::move(elementsWithNoPayload)); @@ -4929,7 +5017,7 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC, // Use the singleton element's storage type if fixed-size. if (eltTI.isFixedSize()) { - llvm::Type *body[] = { eltTI.StorageType }; + llvm::Type *body[] = { eltTI.getStorageType() }; enumTy->setBody(body, /*isPacked*/ true); } else { enumTy->setBody(ArrayRef{}, /*isPacked*/ true); @@ -4941,8 +5029,8 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC, alignment); return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy, alignment, - eltTI.isPOD(ResilienceScope::Component), - eltTI.isBitwiseTakable(ResilienceScope::Component))); + eltTI.isPOD(ResilienceExpansion::Maximal), + eltTI.isBitwiseTakable(ResilienceExpansion::Maximal))); } else { auto &fixedEltTI = cast(eltTI); auto alignment = fixedEltTI.getFixedAlignment(); @@ -4953,8 +5041,8 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC, fixedEltTI.getFixedSize(), fixedEltTI.getSpareBits(), alignment, - fixedEltTI.isPOD(ResilienceScope::Component), - fixedEltTI.isBitwiseTakable(ResilienceScope::Component)); + fixedEltTI.isPOD(ResilienceExpansion::Maximal), + fixedEltTI.isBitwiseTakable(ResilienceExpansion::Maximal)); } } } @@ -5013,7 +5101,7 @@ CCompatibleEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC, auto &rawTI = TC.getCompleteTypeInfo( theEnum->getRawType()->getCanonicalType()); auto &rawFixedTI = cast(rawTI); - assert(rawFixedTI.isPOD(ResilienceScope::Component) + assert(rawFixedTI.isPOD(ResilienceExpansion::Maximal) && "c-compatible raw type isn't POD?!"); ExplosionSchema rawSchema = rawTI.getSchema(); assert(rawSchema.size() == 1 @@ -5029,7 +5117,7 @@ CCompatibleEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC, applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/true, alignment); - assert(!TC.IGM.isResilient(theEnum, ResilienceScope::Universal) && + assert(!TC.IGM.isResilient(theEnum, ResilienceExpansion::Minimal) && "C-compatible enums cannot be resilient"); return registerEnumTypeInfo(new LoadableEnumTypeInfo(*this, enumTy, @@ -5103,8 +5191,8 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout( return getFixedEnumTypeInfo(enumTy, Size(sizeWithTag), std::move(spareBits), alignment, - payloadTI.isPOD(ResilienceScope::Component), - payloadTI.isBitwiseTakable(ResilienceScope::Component)); + payloadTI.isPOD(ResilienceExpansion::Maximal), + payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal)); } TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout( @@ -5126,8 +5214,8 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout( return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy, alignment, - payloadTI.isPOD(ResilienceScope::Component), - payloadTI.isBitwiseTakable(ResilienceScope::Component))); + payloadTI.isPOD(ResilienceExpansion::Maximal), + payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal))); } TypeInfo * @@ -5158,23 +5246,28 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC, Alignment worstAlignment(1); IsPOD_t isPOD = IsPOD; IsBitwiseTakable_t isBT = IsBitwiseTakable; + PayloadSize = 0; for (auto &elt : ElementsWithPayload) { auto &fixedPayloadTI = cast(*elt.ti); if (fixedPayloadTI.getFixedAlignment() > worstAlignment) worstAlignment = fixedPayloadTI.getFixedAlignment(); - if (!fixedPayloadTI.isPOD(ResilienceScope::Component)) + if (!fixedPayloadTI.isPOD(ResilienceExpansion::Maximal)) isPOD = IsNotPOD; - if (!fixedPayloadTI.isBitwiseTakable(ResilienceScope::Component)) + if (!fixedPayloadTI.isBitwiseTakable(ResilienceExpansion::Maximal)) isBT = IsNotBitwiseTakable; + unsigned payloadBytes = fixedPayloadTI.getFixedSize().getValue(); unsigned payloadBits = fixedPayloadTI.getFixedSize().getValueInBits(); - + + if (payloadBytes > PayloadSize) + PayloadSize = payloadBytes; + // See what spare bits from the payload we can use for layout optimization. // The runtime currently does not track spare bits, so we can't use them // if the type is layout-dependent. (Even when the runtime does, it will // likely only track a subset of the spare bits.) - if (!AlwaysFixedSize || TIK < Loadable) { + if (!AllowFixedLayoutOptimizations || TIK < Loadable) { if (CommonSpareBits.size() < payloadBits) CommonSpareBits.extendWithClearBits(payloadBits); continue; @@ -5303,8 +5396,8 @@ TypeInfo *MultiPayloadEnumImplStrategy::completeDynamicLayout( for (auto &element : ElementsWithPayload) { auto &payloadTI = *element.ti; alignment = std::max(alignment, payloadTI.getBestKnownAlignment()); - pod &= payloadTI.isPOD(ResilienceScope::Component); - bt &= payloadTI.isBitwiseTakable(ResilienceScope::Component); + pod &= payloadTI.isPOD(ResilienceExpansion::Maximal); + bt &= payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal); } applyLayoutAttributes(TC.IGM, Type.getSwiftRValueType(), /*fixed*/false, @@ -5338,7 +5431,7 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type, llvm::StructType *storageType; // Resilient enum types lower down to the same opaque type. - if (IGM.isResilient(theEnum, ResilienceScope::Component)) + if (IGM.isResilient(theEnum, ResilienceExpansion::Maximal)) storageType = cast(IGM.OpaquePtrTy->getElementType()); else storageType = IGM.createNominalType(theEnum); diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h index 14e836c0c6c25..c45baa9d17451 100644 --- a/lib/IRGen/GenEnum.h +++ b/lib/IRGen/GenEnum.h @@ -1,8 +1,8 @@ -//===--- GenEnum.h - Swift IR Generation For 'enum' Types -------* C++ *-===// +//===--- GenEnum.h - Swift IR Generation For 'enum' Types -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -177,8 +177,8 @@ class EnumImplStrategy { return cast(getTypeInfo().getStorageType()); } - IsPOD_t isPOD(ResilienceScope scope) const { - return getTypeInfo().isPOD(scope); + IsPOD_t isPOD(ResilienceExpansion expansion) const { + return getTypeInfo().isPOD(expansion); } /// \group Query enum layout @@ -200,8 +200,13 @@ class EnumImplStrategy { return ElementsWithNoPayload; } + /// Return a tag index in the range [0..NumElements]. unsigned getTagIndex(EnumElementDecl *Case) const; + /// Return a tag index in the range + /// [-ElementsWithPayload..ElementsWithNoPayload-1]. + int getResilientTagIndex(EnumElementDecl *Case) const; + /// Map the given element to the appropriate index in the /// discriminator type. /// Returns -1 if this is not supported by the enum implementation. @@ -407,6 +412,7 @@ class EnumImplStrategy { unsigned offset) const = 0; virtual bool needsPayloadSizeInMetadata() const = 0; + virtual unsigned getPayloadSizeForMetadata() const; virtual llvm::Value *loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc, Address addr) const; diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index d278af7b74417..43ed18b3d6a2a 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -77,10 +77,9 @@ namespace { return getFixedBufferAlignment(IGM); } - /* - friend bool operator==(ExistentialLayout a, ExistentialLayout b) { - return a.NumTables == b.NumTables; - }*/ + // friend bool operator==(ExistentialLayout a, ExistentialLayout b) { + // return a.NumTables == b.NumTables; + // } /// Given the address of an existential object, drill down to the /// buffer. @@ -102,8 +101,7 @@ namespace { /// Given the address of an existential object, load its witness table. llvm::Value *loadWitnessTable(IRGenFunction &IGF, Address addr, unsigned which) const { - return IGF.Builder.CreateLoad(projectWitnessTable(IGF, addr, which), - "witness-table"); + return IGF.Builder.CreateLoad(projectWitnessTable(IGF, addr, which)); } /// Given the address of an existential object, drill down to the @@ -115,8 +113,7 @@ namespace { /// Given the address of an existential object, load its metadata /// object. llvm::Value *loadMetadataRef(IRGenFunction &IGF, Address addr) { - return IGF.Builder.CreateLoad(projectMetadataRef(IGF, addr), - addr.getAddress()->getName() + ".metadata"); + return IGF.Builder.CreateLoad(projectMetadataRef(IGF, addr)); } }; } @@ -153,10 +150,6 @@ class ExistentialTypeInfoBase : public Base { } protected: - const ExistentialTypeInfoBase &asExistentialTI() const { - return *this; - } - const Derived &asDerived() const { return *static_cast(this); } @@ -337,7 +330,8 @@ class OpaqueExistentialTypeInfo : Address srcBuffer = layout.projectExistentialBuffer(IGF, src); Address destBuffer = layout.projectExistentialBuffer(IGF, dest); emitInitializeBufferWithCopyOfBufferCall(IGF, metadata, - destBuffer, srcBuffer); + destBuffer, + srcBuffer); } void initializeWithTake(IRGenFunction &IGF, @@ -352,7 +346,8 @@ class OpaqueExistentialTypeInfo : Address srcBuffer = layout.projectExistentialBuffer(IGF, src); Address destBuffer = layout.projectExistentialBuffer(IGF, dest); emitInitializeBufferWithTakeOfBufferCall(IGF, metadata, - destBuffer, srcBuffer); + destBuffer, + srcBuffer); } void destroy(IRGenFunction &IGF, Address addr, SILType T) const { @@ -1040,7 +1035,7 @@ class ClassExistentialTypeInfo public: - bool isSingleRetainablePointer(ResilienceScope scope, + bool isSingleRetainablePointer(ResilienceExpansion expansion, ReferenceCounting *refcounting) const override{ if (refcounting) *refcounting = Refcounting; return getNumStoredProtocols() == 0; @@ -1501,6 +1496,8 @@ static llvm::Constant *getAssignExistentialsFunction(IRGenModule &IGM, // Project down to the buffers. IGF.Builder.emitBlock(contBB); + // We don't need a ConditionalDominanceScope here because (1) there's no + // code in the other condition and (2) we immediately return. Address destBuffer = layout.projectExistentialBuffer(IGF, dest); Address srcBuffer = layout.projectExistentialBuffer(IGF, src); @@ -1516,16 +1513,18 @@ static llvm::Constant *getAssignExistentialsFunction(IRGenModule &IGM, IGF.Builder.CreateICmpEQ(destMetadata, srcMetadata, "sameMetadata"); IGF.Builder.CreateCondBr(sameMetadata, matchBB, noMatchBB); - { // (scope to avoid contaminating other branches with these values) - - // If so, do a direct assignment. - IGF.Builder.emitBlock(matchBB); + // If so, do a direct assignment. + IGF.Builder.emitBlock(matchBB); + { + ConditionalDominanceScope matchCondition(IGF); llvm::Value *destObject = emitProjectBufferCall(IGF, destMetadata, destBuffer); llvm::Value *srcObject = emitProjectBufferCall(IGF, destMetadata, srcBuffer); - emitAssignWithCopyCall(IGF, destMetadata, destObject, srcObject); + emitAssignWithCopyCall(IGF, destMetadata, + Address(destObject, Alignment(1)), + Address(srcObject, Alignment(1))); IGF.Builder.CreateBr(doneBB); } @@ -1537,29 +1536,33 @@ static llvm::Constant *getAssignExistentialsFunction(IRGenModule &IGM, // the madnesses that boost::variant has to go through, with the // advantage of address-invariance. IGF.Builder.emitBlock(noMatchBB); + { + ConditionalDominanceScope noMatchCondition(IGF); - // Store the metadata ref. - IGF.Builder.CreateStore(srcMetadata, destMetadataSlot); + // Store the metadata ref. + IGF.Builder.CreateStore(srcMetadata, destMetadataSlot); - // Store the protocol witness tables. - unsigned numTables = layout.getNumTables(); - for (unsigned i = 0, e = numTables; i != e; ++i) { - Address destTableSlot = layout.projectWitnessTable(IGF, dest, i); - llvm::Value *srcTable = layout.loadWitnessTable(IGF, src, i); + // Store the protocol witness tables. + unsigned numTables = layout.getNumTables(); + for (unsigned i = 0, e = numTables; i != e; ++i) { + Address destTableSlot = layout.projectWitnessTable(IGF, dest, i); + llvm::Value *srcTable = layout.loadWitnessTable(IGF, src, i); - // Overwrite the old witness table. - IGF.Builder.CreateStore(srcTable, destTableSlot); - } + // Overwrite the old witness table. + IGF.Builder.CreateStore(srcTable, destTableSlot); + } - // Destroy the old value. - emitDestroyBufferCall(IGF, destMetadata, destBuffer); + // Destroy the old value. + emitDestroyBufferCall(IGF, destMetadata, destBuffer); - // Copy-initialize with the new value. Again, pull a value - // witness table from the source metadata if we can't use a - // protocol witness table. - emitInitializeBufferWithCopyOfBufferCall(IGF, srcMetadata, - destBuffer, srcBuffer); - IGF.Builder.CreateBr(doneBB); + // Copy-initialize with the new value. Again, pull a value + // witness table from the source metadata if we can't use a + // protocol witness table. + emitInitializeBufferWithCopyOfBufferCall(IGF, srcMetadata, + destBuffer, + srcBuffer); + IGF.Builder.CreateBr(doneBB); + } // All done. IGF.Builder.emitBlock(doneBB); @@ -1567,30 +1570,19 @@ static llvm::Constant *getAssignExistentialsFunction(IRGenModule &IGM, }); } -/// Retrieve the protocol witness table for a conformance. -static llvm::Value *getProtocolWitnessTable(IRGenFunction &IGF, - CanType srcType, - const TypeInfo &srcTI, - ProtocolEntry protoEntry, - ProtocolConformance *conformance) { - return emitWitnessTableRef(IGF, srcType, srcTI, - protoEntry.getProtocol(), - protoEntry.getInfo(), - conformance); -} - /// Emit protocol witness table pointers for the given protocol conformances, /// passing each emitted witness table index into the given function body. static void forEachProtocolWitnessTable(IRGenFunction &IGF, - CanType srcType, CanType destType, + CanType srcType, llvm::Value **srcMetadataCache, + CanType destType, ArrayRef protocols, - ArrayRef conformances, + ArrayRef conformances, std::function body) { // Collect the conformances that need witness tables. SmallVector destProtocols; destType.getAnyExistentialTypeProtocols(destProtocols); - SmallVector witnessConformances; + SmallVector witnessConformances; assert(destProtocols.size() == conformances.size() && "mismatched protocol conformances"); for (unsigned i = 0, size = destProtocols.size(); i < size; ++i) @@ -1600,10 +1592,11 @@ static void forEachProtocolWitnessTable(IRGenFunction &IGF, assert(protocols.size() == witnessConformances.size() && "mismatched protocol conformances"); - auto &srcTI = IGF.getTypeInfoForUnlowered(srcType); for (unsigned i = 0, e = protocols.size(); i < e; ++i) { - auto table = getProtocolWitnessTable(IGF, srcType, srcTI, - protocols[i], witnessConformances[i]); + auto table = emitWitnessTableRef(IGF, srcType, srcMetadataCache, + protocols[i].getProtocol(), + protocols[i].getInfo(), + witnessConformances[i]); body(i, table); } } @@ -1618,12 +1611,11 @@ static bool _isErrorType(SILType baseTy) { } #endif -/// Project the address of the value inside a boxed existential container, -/// and open an archetype to its contained type. -Address irgen::emitBoxedExistentialProjection(IRGenFunction &IGF, +/// Project the address of the value inside a boxed existential container. +ContainedAddress irgen::emitBoxedExistentialProjection(IRGenFunction &IGF, Explosion &base, SILType baseTy, - CanArchetypeType openedArchetype){ + CanType projectedType) { // TODO: Non-ErrorType boxed existentials. assert(_isErrorType(baseTy)); @@ -1641,11 +1633,24 @@ Address irgen::emitBoxedExistentialProjection(IRGenFunction &IGF, scratch.getAddress(), out.getAddress()}); // Load the 'out' values. - auto &openedTI = IGF.getTypeInfoForLowered(openedArchetype); + auto &projectedTI = IGF.getTypeInfoForLowered(projectedType); auto projectedPtrAddr = IGF.Builder.CreateStructGEP(out, 0, Size(0)); - auto projectedPtr = IGF.Builder.CreateLoad(projectedPtrAddr); - auto projected = openedTI.getAddressForPointer(projectedPtr); - + llvm::Value *projectedPtr = IGF.Builder.CreateLoad(projectedPtrAddr); + projectedPtr = IGF.Builder.CreateBitCast(projectedPtr, + projectedTI.getStorageType()->getPointerTo()); + auto projected = projectedTI.getAddressForPointer(projectedPtr); + return ContainedAddress(out, projected); +} + +/// Project the address of the value inside a boxed existential container, +/// and open an archetype to its contained type. +Address irgen::emitOpenExistentialBox(IRGenFunction &IGF, + Explosion &base, + SILType baseTy, + CanArchetypeType openedArchetype) { + ContainedAddress box = emitBoxedExistentialProjection(IGF, base, baseTy, + openedArchetype); + Address out = box.getContainer(); auto metadataAddr = IGF.Builder.CreateStructGEP(out, 1, IGF.IGM.getPointerSize()); auto metadata = IGF.Builder.CreateLoad(metadataAddr); @@ -1654,30 +1659,26 @@ Address irgen::emitBoxedExistentialProjection(IRGenFunction &IGF, auto witness = IGF.Builder.CreateLoad(witnessAddr); IGF.bindArchetype(openedArchetype, metadata, witness); - - return projected; + return box.getAddress(); } /// Allocate a boxed existential container with uninitialized space to hold a /// value of a given type. -Address irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, - Explosion &dest, +OwnedAddress irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, SILType destType, CanType formalSrcType, - SILType loweredSrcType, - ArrayRef conformances){ + ArrayRef conformances) { // TODO: Non-ErrorType boxed existentials. assert(_isErrorType(destType)); auto &destTI = IGF.getTypeInfo(destType).as(); - auto &srcTI = IGF.getTypeInfo(loweredSrcType); - auto srcMetadata = IGF.emitTypeMetadataRef(formalSrcType); // Should only be one conformance, for the ErrorType protocol. assert(conformances.size() == 1 && destTI.getStoredProtocols().size() == 1); const ProtocolEntry &entry = destTI.getStoredProtocols()[0]; - auto witness = getProtocolWitnessTable(IGF, formalSrcType, srcTI, - entry, conformances[0]); + auto witness = emitWitnessTableRef(IGF, formalSrcType, &srcMetadata, + entry.getProtocol(), entry.getInfo(), + conformances[0]); // Call the runtime to allocate the box. // TODO: When there's a store or copy_addr immediately into the box, peephole @@ -1690,11 +1691,13 @@ Address irgen::emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, // Extract the box and value address from the result. auto box = IGF.Builder.CreateExtractValue(result, 0); auto addr = IGF.Builder.CreateExtractValue(result, 1); - dest.add(box); - + + auto archetype = ArchetypeType::getOpened(destType.getSwiftRValueType()); + auto &srcTI = IGF.getTypeInfoForUnlowered(AbstractionPattern(archetype), + formalSrcType); addr = IGF.Builder.CreateBitCast(addr, srcTI.getStorageType()->getPointerTo()); - return srcTI.getAddressForPointer(addr); + return OwnedAddress(srcTI.getAddressForPointer(addr), box); } /// Deallocate a boxed existential container with uninitialized space to hold a @@ -1735,7 +1738,7 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF, llvm::Value *instance, CanType instanceFormalType, SILType instanceLoweredType, - ArrayRef conformances) { + ArrayRef conformances) { // As a special case, an ErrorType existential can represented as a reference // to an already existing NSError or CFError instance. SmallVector protocols; @@ -1771,7 +1774,8 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF, out.add(opaqueInstance); // Emit the witness table pointers. - forEachProtocolWitnessTable(IGF, instanceFormalType, + llvm::Value *instanceMetadata = nullptr; + forEachProtocolWitnessTable(IGF, instanceFormalType, &instanceMetadata, outType.getSwiftRValueType(), destTI.getStoredProtocols(), conformances, @@ -1788,7 +1792,7 @@ Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF, SILType destType, CanType formalSrcType, SILType loweredSrcType, - ArrayRef conformances) { + ArrayRef conformances) { assert(!destType.isClassExistentialType() && "initializing a class existential container as opaque"); auto &destTI = IGF.getTypeInfo(destType).as(); @@ -1801,7 +1805,8 @@ Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF, // Next, write the protocol witness tables. - forEachProtocolWitnessTable(IGF, formalSrcType, destType.getSwiftRValueType(), + forEachProtocolWitnessTable(IGF, formalSrcType, &metadata, + destType.getSwiftRValueType(), destTI.getStoredProtocols(), conformances, [&](unsigned i, llvm::Value *ptable) { Address ptableSlot = destLayout.projectWitnessTable(IGF, dest, i); @@ -1819,7 +1824,7 @@ Address irgen::emitOpaqueExistentialContainerInit(IRGenFunction &IGF, void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF, Explosion &out, SILType outType, llvm::Value *metatype, SILType metatypeType, - ArrayRef conformances) { + ArrayRef conformances) { assert(outType.is()); auto &destTI = IGF.getTypeInfo(outType).as(); out.add(metatype); @@ -1832,7 +1837,8 @@ void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF, } // Emit the witness table pointers. - forEachProtocolWitnessTable(IGF, srcType, destType, + llvm::Value *srcMetadata = nullptr; + forEachProtocolWitnessTable(IGF, srcType, &srcMetadata, destType, destTI.getStoredProtocols(), conformances, [&](unsigned i, llvm::Value *ptable) { @@ -1852,7 +1858,8 @@ void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address addr, // Project the buffer and apply the 'typeof' value witness. Address buffer = existLayout.projectExistentialBuffer(IGF, addr); - llvm::Value *object = emitProjectBufferCall(IGF, metadata, buffer); + llvm::Value *object = + emitProjectBufferCall(IGF, metadata, buffer); llvm::Value *dynamicType = IGF.Builder.CreateCall(IGF.IGM.getGetDynamicTypeFn(), {object, metadata}); @@ -1988,7 +1995,8 @@ irgen::emitIndirectExistentialProjectionWithMetadata(IRGenFunction &IGF, llvm::Value *metadata = layout.loadMetadataRef(IGF, base); Address buffer = layout.projectExistentialBuffer(IGF, base); - llvm::Value *object = emitProjectBufferCall(IGF, metadata, buffer); + llvm::Value *object = + emitProjectBufferCall(IGF, metadata, buffer); // If we are projecting into an opened archetype, capture the // witness tables. diff --git a/lib/IRGen/GenExistential.h b/lib/IRGen/GenExistential.h index 3edfb2ad0fa3d..f737ae02698b8 100644 --- a/lib/IRGen/GenExistential.h +++ b/lib/IRGen/GenExistential.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,6 +17,7 @@ #ifndef SWIFT_IRGEN_GENEXISTENTIAL_H #define SWIFT_IRGEN_GENEXISTENTIAL_H +#include "Address.h" #include "swift/Basic/LLVM.h" #include "swift/AST/Types.h" @@ -25,7 +26,7 @@ namespace llvm { } namespace swift { - class ProtocolConformance; + class ProtocolConformanceRef; class SILType; namespace irgen { @@ -40,7 +41,7 @@ namespace irgen { SILType destType, CanType formalSrcType, SILType loweredSrcType, - ArrayRef conformances); + ArrayRef conformances); /// Emit an existential metatype container from a metatype value /// as an explosion. @@ -49,7 +50,7 @@ namespace irgen { SILType outType, llvm::Value *metatype, SILType metatypeType, - ArrayRef conformances); + ArrayRef conformances); /// Emit a class existential container from a class instance value @@ -60,16 +61,14 @@ namespace irgen { llvm::Value *instance, CanType instanceFormalType, SILType instanceLoweredType, - ArrayRef conformances); + ArrayRef conformances); /// Allocate a boxed existential container with uninitialized space to hold a /// value of a given type. - Address emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, - Explosion &dest, + OwnedAddress emitBoxedExistentialContainerAllocation(IRGenFunction &IGF, SILType destType, CanType formalSrcType, - SILType loweredSrcType, - ArrayRef conformances); + ArrayRef conformances); /// "Deinitialize" an existential container whose contained value is allocated /// but uninitialized, by deallocating the buffer owned by the container if any. @@ -112,12 +111,18 @@ namespace irgen { SILType baseTy, CanType openedTy); + /// Project the address of the value inside a boxed existential container. + ContainedAddress emitBoxedExistentialProjection(IRGenFunction &IGF, + Explosion &base, + SILType baseTy, + CanType projectedType); + /// Project the address of the value inside a boxed existential container, /// and open an archetype to its contained type. - Address emitBoxedExistentialProjection(IRGenFunction &IGF, - Explosion &base, - SILType baseTy, - CanArchetypeType openedArchetype); + Address emitOpenExistentialBox(IRGenFunction &IGF, + Explosion &base, + SILType baseTy, + CanArchetypeType openedArchetype); /// Emit the existential metatype of an opaque existential value. void emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address addr, diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 99d3f586f2c5e..474900f446952 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -144,7 +144,7 @@ static void addDereferenceableAttributeToBuilder(IRGenModule &IGM, const TypeInfo &ti) { // The addresses of empty values are undefined, so we can't safely mark them // dereferenceable. - if (ti.isKnownEmpty()) + if (ti.isKnownEmpty(ResilienceExpansion::Maximal)) return; // If we know the type to have a fixed nonempty size, then the pointer is @@ -266,41 +266,10 @@ namespace { CallResult() : CurState(State::Invalid) {} ~CallResult() { reset(); } - /// Configure this result to carry a number of direct values at - /// the given explosion level. - Explosion &initForDirectValues() { - assert(CurState == State::Invalid); - CurState = State::Direct; - return *new (&CurValue.Direct) Explosion(); - } - - /// As a potential efficiency, set that this is a direct result - /// with no values. - void setAsEmptyDirect() { - initForDirectValues(); - } - - /// Set this result so that it carries a single directly-returned - /// maximally-fragile value without management. - void setAsSingleDirectUnmanagedFragileValue(llvm::Value *value) { - initForDirectValues().add(value); - } - - void setAsIndirectAddress(Address address) { - assert(CurState == State::Invalid); - CurState = State::Indirect; - CurValue.Indirect = address; - } - bool isInvalid() const { return CurState == State::Invalid; } bool isDirect() const { return CurState == State::Direct; } bool isIndirect() const { return CurState == State::Indirect; } - Explosion &getDirectValues() { - assert(isDirect()); - return CurValue.Direct; - } - Address getIndirectAddress() const { assert(isIndirect()); return CurValue.Indirect; @@ -724,8 +693,8 @@ const TypeInfo *TypeConverter::convertBlockStorageType(SILBlockStorageType *T) { spareBits.extendWithSetBits(captureOffset.getValueInBits()); size = captureOffset + fixedCapture->getFixedSize(); spareBits.append(fixedCapture->getSpareBits()); - pod = fixedCapture->isPOD(ResilienceScope::Component); - bt = fixedCapture->isBitwiseTakable(ResilienceScope::Component); + pod = fixedCapture->isPOD(ResilienceExpansion::Maximal); + bt = fixedCapture->isBitwiseTakable(ResilienceExpansion::Maximal); } llvm::Type *storageElts[] = { @@ -1367,17 +1336,7 @@ void SignatureExpansion::expand(SILParameterInfo param) { case ParameterConvention::Direct_Owned: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Guaranteed: - // Go ahead and further decompose tuples. - if (auto tuple = dyn_cast(param.getType())) { - for (auto elt : tuple.getElementTypes()) { - // Propagate the same ownedness down to the element. - expand(SILParameterInfo(elt, param.getConvention())); - } - return; - } - SWIFT_FALLTHROUGH; case ParameterConvention::Direct_Deallocating: - switch (FnType->getLanguage()) { case SILFunctionLanguage::C: { llvm_unreachable("Unexpected C/ObjC method in parameter expansion!"); @@ -1830,7 +1789,7 @@ if (Builtin.ID == BuiltinValueKind::id) { \ return; \ } // FIXME: We could generate the code to dynamically report the overflow if the - // thrid argument is true. Now, we just ignore it. + // third argument is true. Now, we just ignore it. #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ if (Builtin.ID == BuiltinValueKind::id) \ @@ -3153,21 +3112,27 @@ void IRGenFunction::emitEpilogue() { AllocaIP->eraseFromParent(); } -Address irgen::allocateForCoercion(IRGenFunction &IGF, - llvm::Type *fromTy, - llvm::Type *toTy, - const llvm::Twine &basename) { +std::pair +irgen::allocateForCoercion(IRGenFunction &IGF, + llvm::Type *fromTy, + llvm::Type *toTy, + const llvm::Twine &basename) { auto &DL = IGF.IGM.DataLayout; - auto bufferTy = DL.getTypeSizeInBits(fromTy) >= DL.getTypeSizeInBits(toTy) + auto fromSize = DL.getTypeSizeInBits(fromTy); + auto toSize = DL.getTypeSizeInBits(toTy); + auto bufferTy = fromSize >= toSize ? fromTy : toTy; auto alignment = std::max(DL.getABITypeAlignment(fromTy), DL.getABITypeAlignment(toTy)); - return IGF.createAlloca(bufferTy, Alignment(alignment), - basename + ".coerced"); + auto buffer = IGF.createAlloca(bufferTy, Alignment(alignment), + basename + ".coerced"); + + Size size(std::max(fromSize, toSize)); + return {buffer, size}; } llvm::Value* IRGenFunction::coerceValue(llvm::Value *value, llvm::Type *toTy, @@ -3193,12 +3158,16 @@ llvm::Value* IRGenFunction::coerceValue(llvm::Value *value, llvm::Type *toTy, } // Otherwise we need to store, bitcast, and load. - auto address = allocateForCoercion(*this, fromTy, toTy, - value->getName() + ".coercion"); + Address address; Size size; + std::tie(address, size) = allocateForCoercion(*this, fromTy, toTy, + value->getName() + ".coercion"); + Builder.CreateLifetimeStart(address, size); auto orig = Builder.CreateBitCast(address, fromTy->getPointerTo()); Builder.CreateStore(value, orig); auto coerced = Builder.CreateBitCast(address, toTy->getPointerTo()); - return Builder.CreateLoad(coerced); + auto loaded = Builder.CreateLoad(coerced); + Builder.CreateLifetimeEnd(address, size); + return loaded; } void IRGenFunction::emitScalarReturn(llvm::Type *resultType, @@ -3553,7 +3522,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM, case ParameterConvention::Direct_Unowned: // If the type is nontrivial, keep the context alive since the field // depends on the context to not be deallocated. - if (!fieldTI.isPOD(ResilienceScope::Component)) + if (!fieldTI.isPOD(ResilienceExpansion::Maximal)) dependsOnContextLifetime = true; SWIFT_FALLTHROUGH; case ParameterConvention::Direct_Deallocating: @@ -3797,7 +3766,7 @@ void irgen::emitFunctionPartialApplication(IRGenFunction &IGF, continue; } - if (ti.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + if (ti.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { hasSingleSwiftRefcountedContext = Yes; singleRefcountedConvention = param.getConvention(); } else { @@ -4071,7 +4040,7 @@ void irgen::emitBlockHeader(IRGenFunction &IGF, uint32_t flags = 0; auto &captureTL = IGF.getTypeInfoForLowered(blockTy->getCaptureType()); - bool isPOD = captureTL.isPOD(ResilienceScope::Component); + bool isPOD = captureTL.isPOD(ResilienceExpansion::Maximal); if (!isPOD) flags |= 1 << 25; diff --git a/lib/IRGen/GenFunc.h b/lib/IRGen/GenFunc.h index a07eff5e97f7a..c0105f001407e 100644 --- a/lib/IRGen/GenFunc.h +++ b/lib/IRGen/GenFunc.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -111,10 +111,11 @@ namespace irgen { /// Allocate a stack buffer of the appropriate size to bitwise-coerce a value /// between two LLVM types. - Address allocateForCoercion(IRGenFunction &IGF, - llvm::Type *fromTy, - llvm::Type *toTy, - const llvm::Twine &basename); + std::pair + allocateForCoercion(IRGenFunction &IGF, + llvm::Type *fromTy, + llvm::Type *toTy, + const llvm::Twine &basename); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 6deef17c90618..cddd852bd6212 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -24,6 +24,7 @@ #include "swift/Basic/Fallthrough.h" #include "swift/Basic/SourceLoc.h" #include "swift/ABI/MetadataValues.h" +#include "swift/AST/IRGenOptions.h" #include "Explosion.h" #include "GenProto.h" @@ -1169,9 +1170,39 @@ void IRGenFunction::emitNativeUnownedTakeAssign(Address dest, Address src) { emitNativeUnownedRelease(oldValue); } +llvm::Constant *IRGenModule::getFixLifetimeFn() { + if (FixLifetimeFn) + return FixLifetimeFn; + + // Generate a private stub function for the LLVM ARC optimizer to recognize. + auto fixLifetimeTy = llvm::FunctionType::get(VoidTy, RefCountedPtrTy, + /*isVarArg*/ false); + auto fixLifetime = llvm::Function::Create(fixLifetimeTy, + llvm::GlobalValue::PrivateLinkage, + "__swift_fixLifetime", + &Module); + assert(fixLifetime->getName().equals("__swift_fixLifetime") + && "fixLifetime symbol name got mangled?!"); + // Don't inline the function, so it stays as a signal to the ARC passes. + // The ARC passes will remove references to the function when they're + // no longer needed. + fixLifetime->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::NoInline); + + // Give the function an empty body. + auto entry = llvm::BasicBlock::Create(LLVMContext, "", fixLifetime); + llvm::ReturnInst::Create(LLVMContext, entry); + + FixLifetimeFn = fixLifetime; + return fixLifetime; +} + /// Fix the lifetime of a live value. This communicates to the LLVM level ARC /// optimizer not to touch this value. void IRGenFunction::emitFixLifetime(llvm::Value *value) { + // If we aren't running the LLVM ARC optimizer, we don't need to emit this. + if (!IGM.Opts.Optimize || IGM.Opts.DisableLLVMARCOpts) + return; if (doesNotRequireRefCounting(value)) return; emitUnaryRefCountCall(*this, IGM.getFixLifetimeFn(), value); } @@ -1451,14 +1482,14 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) { auto &fixedTI = cast(eltTI); // For empty types, we don't really need to allocate anything. - if (fixedTI.isKnownEmpty()) { + if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) { if (!EmptyBoxTI) EmptyBoxTI = new EmptyBoxTypeInfo(IGM); return EmptyBoxTI; } // We can share box info for all similarly-shaped POD types. - if (fixedTI.isPOD(ResilienceScope::Component)) { + if (fixedTI.isPOD(ResilienceExpansion::Maximal)) { auto stride = fixedTI.getFixedStride(); auto align = fixedTI.getFixedAlignment(); auto foundPOD = PODBoxTI.find({stride.getValue(),align.getValue()}); @@ -1472,7 +1503,7 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) { } // We can share box info for all single-refcounted types. - if (fixedTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + if (fixedTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { if (!SwiftRetainablePointerBoxTI) SwiftRetainablePointerBoxTI = new SingleRefcountedBoxTypeInfo(IGM, ReferenceCounting::Native); diff --git a/lib/IRGen/GenHeap.h b/lib/IRGen/GenHeap.h index c77918be496ce..56750c8f1e911 100644 --- a/lib/IRGen/GenHeap.h +++ b/lib/IRGen/GenHeap.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenInit.cpp b/lib/IRGen/GenInit.cpp index 7a13df7bee74e..14450768b058f 100644 --- a/lib/IRGen/GenInit.cpp +++ b/lib/IRGen/GenInit.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,41 +33,50 @@ using namespace irgen; /// Emit a global variable. Address IRGenModule::emitSILGlobalVariable(SILGlobalVariable *var) { - auto &type = getTypeInfo(var->getLoweredType()); - - // If the variable is empty, don't actually emit it; just return undef. - if (type.isKnownEmpty()) { - return type.getUndefAddress(); - } + auto &ti = getTypeInfo(var->getLoweredType()); + // If the variable is empty in all resilience domains, don't actually emit it; + // just return undef. + if (ti.isKnownEmpty(ResilienceExpansion::Minimal)) + return ti.getUndefAddress(); + /// Get the global variable. - Address addr = getAddrOfSILGlobalVariable(var, + Address addr = getAddrOfSILGlobalVariable(var, ti, var->isDefinition() ? ForDefinition : NotForDefinition); /// Add a zero initializer. if (var->isDefinition()) { auto gvar = cast(addr.getAddress()); - gvar->setInitializer(llvm::Constant::getNullValue(type.getStorageType())); + gvar->setInitializer(llvm::Constant::getNullValue(gvar->getValueType())); } + return addr; } ContainedAddress FixedTypeInfo::allocateStack(IRGenFunction &IGF, SILType T, const Twine &name) const { // If the type is known to be empty, don't actually allocate anything. - if (isKnownEmpty()) { + if (isKnownEmpty(ResilienceExpansion::Maximal)) { auto addr = getUndefAddress(); return { addr, addr }; } Address alloca = IGF.createAlloca(getStorageType(), getFixedAlignment(), name); - // TODO: lifetime intrinsics? - + IGF.Builder.CreateLifetimeStart(alloca, getFixedSize()); + return { alloca, alloca }; } +void FixedTypeInfo::destroyStack(IRGenFunction &IGF, Address addr, + SILType T) const { + destroy(IGF, addr, T); + FixedTypeInfo::deallocateStack(IGF, addr, T); +} + void FixedTypeInfo::deallocateStack(IRGenFunction &IGF, Address addr, SILType T) const { - // TODO: lifetime intrinsics? + if (isKnownEmpty(ResilienceExpansion::Maximal)) + return; + IGF.Builder.CreateLifetimeEnd(addr, getFixedSize()); } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 0e7d0f483edcc..e61728a99871d 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -59,6 +59,12 @@ using namespace irgen; static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF, llvm::Value *object); +static llvm::LoadInst * +emitLoadFromMetadataAtIndex(IRGenFunction &IGF, + llvm::Value *metadata, + int index, + llvm::Type *objectTy, + const llvm::Twine &suffix = ""); /// Produce a constant to place in a metatype's isa field /// corresponding to the given metadata kind. @@ -79,11 +85,15 @@ static Address createPointerSizedGEP(IRGenFunction &IGF, offset); } -static llvm::Constant *getMangledTypeName(IRGenModule &IGM, CanType type) { +// FIXME: willBeRelativelyAddressed is only needed to work around an ld64 bug +// resolving relative references to coalesceable symbols. +// It should be removed when fixed. rdar://problem/22674524 +static llvm::Constant *getMangledTypeName(IRGenModule &IGM, CanType type, + bool willBeRelativelyAddressed = false) { auto name = LinkEntity::forTypeMangling(type); llvm::SmallString<32> mangling; name.mangle(mangling); - return IGM.getAddrOfGlobalString(mangling); + return IGM.getAddrOfGlobalString(mangling, willBeRelativelyAddressed); } llvm::Value *irgen::emitObjCMetadataRefForMetadata(IRGenFunction &IGF, @@ -113,30 +123,54 @@ namespace { /// nominal metadata reference. The structure produced here is /// consumed by swift_getGenericMetadata() and must correspond to /// the fill operations that the compiler emits for the bound decl. + /// + /// FIXME: Rework to use GenericSignature instead of AllArchetypes + /// FIXME: Rework for nested generics struct GenericArguments { /// The values to use to initialize the arguments structure. SmallVector Values; SmallVector Types; + void collectTypes(IRGenModule &IGM, const NominalTypeDecl *nominal) { + auto generics = nominal->getGenericParamsOfContext(); + collectTypes(IGM, generics->getForwardingSubstitutions(IGM.Context)); + } + + void collectTypes(IRGenModule &IGM, ArrayRef subs) { + // Add all the argument archetypes. + Types.append(subs.size(), IGM.TypeMetadataPtrTy); + + // Add protocol witness tables for all those archetypes. + for (auto sub : subs) { + auto conformances = sub.getConformances(); + + for (auto &conformance : conformances) { + auto *proto = conformance.getRequirement(); + if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto)) + continue; + + Types.push_back(IGM.WitnessTablePtrTy); + } + } + } + void collect(IRGenFunction &IGF, BoundGenericType *type) { + auto subs = type->getSubstitutions(/*FIXME:*/nullptr, nullptr); + // Add all the argument archetypes. - // TODO: only the *primary* archetypes - // TODO: not archetypes from outer contexts - // TODO: but we are partially determined by the outer context! - for (auto &sub : type->getSubstitutions(/*FIXME:*/nullptr, nullptr)) { + for (auto &sub : subs) { CanType subbed = sub.getReplacement()->getCanonicalType(); Values.push_back(IGF.emitTypeMetadataRef(subbed)); } - // All of those values are metadata pointers. - Types.append(Values.size(), IGF.IGM.TypeMetadataPtrTy); - // Add protocol witness tables for all those archetypes. - for (auto &sub : type->getSubstitutions(/*FIXME:*/nullptr, nullptr)) - emitWitnessTableRefs(IGF, sub, Values); + for (auto i : indices(subs)) { + llvm::Value *metadata = Values[i]; + emitWitnessTableRefs(IGF, subs[i], &metadata, Values); + } - // All of those values are witness table pointers. - Types.append(Values.size() - Types.size(), IGF.IGM.WitnessTablePtrTy); + collectTypes(IGF.IGM, subs); + assert(Types.size() == Values.size()); } }; } @@ -162,56 +196,30 @@ static void emitPolymorphicParametersFromArray(IRGenFunction &IGF, llvm::Value *metadata = claimNext(IGF.IGM.TypeMetadataPtrTy); metadata->setName(archetype->getFullName()); IGF.setUnscopedLocalTypeData(CanType(archetype), - LocalTypeData::forMetatype(), + LocalTypeDataKind::forTypeMetadata(), metadata); } // Bind all the argument witness tables. for (auto archetype : generics.getAllArchetypes()) { - unsigned nextProtocolIndex = 0; for (auto protocol : archetype->getConformsTo()) { - LocalTypeData key - = LocalTypeData::forArchetypeProtocolWitness(nextProtocolIndex); - nextProtocolIndex++; if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) continue; llvm::Value *wtable = claimNext(IGF.IGM.WitnessTablePtrTy); + auto key = LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol); IGF.setUnscopedLocalTypeData(CanType(archetype), key, wtable); } } } -/// If true, we lazily initialize metadata at runtime because the layout -/// is only partially known. Otherwise, we can emit a direct reference a -/// constant metadata symbol. -static bool hasMetadataPattern(IRGenModule &IGM, NominalTypeDecl *theDecl) { - // Protocols must be special-cased in a few places. - assert(!isa(theDecl)); - - // Classes imported from Objective-C never have a metadata pattern. - if (theDecl->hasClangNode()) - return false; - - // A generic class, struct, or enum is always initialized at runtime. - if (theDecl->isGenericContext()) - return true; - - // If we have fields of resilient type, the metadata still has to be - // initialized at runtime. - if (!IGM.getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize()) - return true; - - return false; -} - /// Attempts to return a constant heap metadata reference for a /// nominal type. -llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM, +llvm::Constant *irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM, CanType type) { auto theDecl = type->getAnyNominal(); assert(theDecl && "emitting constant metadata ref for non-nominal type?"); - if (hasMetadataPattern(IGM, theDecl)) + if (IGM.hasMetadataPattern(theDecl)) return nullptr; if (auto theClass = type->getClassOrBoundGenericClass()) @@ -253,131 +261,55 @@ static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF, } /// Returns a metadata reference for a nominal type. +/// +/// This is only valid in a couple of special cases: +/// 1) The nominal type is generic, in which case we emit a call to the +/// generic metadata accessor function, which must be defined separately. +/// 2) The nominal type is a value type with a fixed size from this +/// resilience domain, in which case we can reference the constant +/// metadata directly. +/// +/// In any other case, a metadata accessor should be called instead. static llvm::Value *emitNominalMetadataRef(IRGenFunction &IGF, NominalTypeDecl *theDecl, CanType theType) { assert(!isa(theDecl)); - // Non-native Swift classes need to be handled differently. - if (auto theClass = dyn_cast(theDecl)) { - // We emit a completely different pattern for foreign classes. - if (theClass->isForeign()) { - return emitForeignTypeMetadataRef(IGF, theType); - } - - // Classes that might not have Swift metadata use a different - // symbol name. - if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) { - assert(!theDecl->getGenericParamsOfContext() && - "ObjC class cannot be generic"); - return emitObjCMetadataRef(IGF, theClass); - } - } else if (theDecl->hasClangNode()) { - // Imported Clang types require foreign metadata uniquing too. - return emitForeignTypeMetadataRef(IGF, theType); - } - - bool isPattern = hasMetadataPattern(IGF.IGM, theDecl); - - // If this is generic, check to see if we've maybe got a local - // reference already. - if (isPattern) { - if (auto cache = IGF.tryGetLocalTypeData(theType, - LocalTypeData::forMetatype())) - return cache; + if (!theDecl->isGenericContext()) { + assert(!IGF.IGM.isResilient(theDecl, ResilienceExpansion::Maximal)); + // TODO: If Obj-C interop is off, we can relax this to allow referencing + // class metadata too. + assert(isa(theDecl) || isa(theDecl)); + return IGF.IGM.getAddrOfTypeMetadata(theType, false); } - // Grab a reference to the metadata or metadata template. - CanType declaredType = theDecl->getDeclaredType()->getCanonicalType(); - llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(declaredType,isPattern); - - // If we don't have a metadata pattern, that's all we need. - if (!isPattern) { - assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); - - // If this is a class, we need to force ObjC initialization, - // but only if we're doing Objective-C interop. - if (IGF.IGM.ObjCInterop && isa(theDecl)) { - metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy); - metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(), - metadata); - metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy); - } - - return metadata; - } - - // Okay, we need to call swift_getGenericMetadata. - assert(metadata->getType() == IGF.IGM.TypeMetadataPatternPtrTy); - - // If we have a pattern but no generic substitutions, we're just - // doing resilient type layout. - if (isPattern && !theDecl->isGenericContext()) { - llvm::Constant *getter = IGF.IGM.getGetResilientMetadataFn(); - - auto result = IGF.Builder.CreateCall(getter, {metadata}); - result->setDoesNotThrow(); - result->addAttribute(llvm::AttributeSet::FunctionIndex, - llvm::Attribute::ReadNone); - IGF.setScopedLocalTypeData(theType, LocalTypeData::forMetatype(), result); - return result; - } - - // Grab the substitutions. + // We are applying generic parameters to a generic type. auto boundGeneric = cast(theType); assert(boundGeneric->getDecl() == theDecl); + // Check to see if we've maybe got a local reference already. + if (auto cache = IGF.tryGetLocalTypeData(theType, + LocalTypeDataKind::forTypeMetadata())) + return cache; + + // Grab the substitutions. GenericArguments genericArgs; genericArgs.collect(IGF, boundGeneric); - - // If we have less than four arguments, use a fast entry point. assert(genericArgs.Values.size() > 0 && "no generic args?!"); - if (genericArgs.Values.size() <= 4) { - llvm::Constant *fastGetter; - switch (genericArgs.Values.size()) { - case 1: fastGetter = IGF.IGM.getGetGenericMetadata1Fn(); break; - case 2: fastGetter = IGF.IGM.getGetGenericMetadata2Fn(); break; - case 3: fastGetter = IGF.IGM.getGetGenericMetadata3Fn(); break; - case 4: fastGetter = IGF.IGM.getGetGenericMetadata4Fn(); break; - default: llvm_unreachable("bad number of generic arguments"); - } - - SmallVector args; - args.push_back(metadata); - for (auto value : genericArgs.Values) - args.push_back(IGF.Builder.CreateBitCast(value, IGF.IGM.Int8PtrTy)); - auto result = IGF.Builder.CreateCall(fastGetter, args); - result->setDoesNotThrow(); - result->addAttribute(llvm::AttributeSet::FunctionIndex, - llvm::Attribute::ReadNone); - IGF.setScopedLocalTypeData(theType, LocalTypeData::forMetatype(), result); - return result; - } - // Slam that information directly into the generic arguments buffer. - auto argsBufferTy = - llvm::StructType::get(IGF.IGM.LLVMContext, genericArgs.Types); - Address argsBuffer = IGF.createAlloca(argsBufferTy, - IGF.IGM.getPointerAlignment(), - "generic.arguments"); - for (unsigned i = 0, e = genericArgs.Values.size(); i != e; ++i) { - Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i, - IGF.IGM.getPointerSize() * i); - IGF.Builder.CreateStore(genericArgs.Values[i], elt); - } - - // Cast to void*. - llvm::Value *arguments = - IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGF.IGM.Int8PtrTy); + // Call the generic metadata accessor function. + llvm::Function *accessor = + IGF.IGM.getAddrOfGenericTypeMetadataAccessFunction(theDecl, + genericArgs.Types, + NotForDefinition); - // Make the call. - auto result = IGF.Builder.CreateCall(IGF.IGM.getGetGenericMetadataFn(), - {metadata, arguments}); + auto result = IGF.Builder.CreateCall(accessor, genericArgs.Values); result->setDoesNotThrow(); result->addAttribute(llvm::AttributeSet::FunctionIndex, - llvm::Attribute::ReadOnly); + llvm::Attribute::ReadNone); - IGF.setScopedLocalTypeData(theType, LocalTypeData::forMetatype(), result); + IGF.setScopedLocalTypeData(theType, LocalTypeDataKind::forTypeMetadata(), + result); return result; } @@ -422,16 +354,43 @@ bool irgen::hasKnownVTableEntry(IRGenModule &IGM, return hasKnownSwiftImplementation(IGM, theClass); } -/// If we have a non-generic struct or enum whose size does not -/// depend on any opaque resilient types, we can access metadata -/// directly. Otherwise, call an accessor. -/// -/// FIXME: Really, we want to use accessors for any nominal type -/// defined in a different module, too. -static bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) { - if (isa(type) || isa(type)) - if (IGM.getTypeInfoForLowered(type).isFixedSize()) - return true; +/// Is it basically trivial to access the given metadata? If so, we don't +/// need a cache variable in its accessor. +bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) { + assert(!type->hasArchetype()); + assert(!type->hasUnboundGenericType()); + + // Value type metadata only requires dynamic initialization on first + // access if it contains a resilient type. + if (isa(type) || isa(type)) { + assert(!type->getAnyNominal()->isGenericContext() && + "shouldn't be called for a generic type"); + + // Imported type metadata always requires an accessor. + if (type->getAnyNominal()->hasClangNode()) + return false; + + // Resiliently-sized metadata access always requires an accessor. + return (IGM.getTypeInfoForLowered(type).isFixedSize()); + } + + // The empty tuple type has a singleton metadata. + if (auto tuple = dyn_cast(type)) + return tuple->getNumElements() == 0; + + // The builtin types generally don't require metadata, but some of them + // have nodes in the runtime anyway. + if (isa(type)) + return true; + + // SIL box types are artificial, but for the purposes of dynamic layout, + // we use the NativeObject metadata. + if (isa(type)) + return true; + + // DynamicSelfType is actually local. + if (type->hasDynamicSelfType()) + return true; return false; } @@ -439,8 +398,9 @@ static bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) { /// Return the standard access strategy for getting a non-dependent /// type metadata object. MetadataAccessStrategy -irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type, - bool preferDirectAccess) { +irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type) { + // We should not be emitting accessors for partially-substituted + // generic types. assert(!type->hasArchetype()); // Non-generic structs, enums, and classes are special cases. @@ -448,16 +408,21 @@ irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type, // Note that while protocol types don't have a metadata pattern, // we still require an accessor since we actually want to get // the metadata for the existential type. - auto nominal = dyn_cast(type); - if (nominal && !isa(nominal)) { - assert(!nominal->getDecl()->isGenericContext()); + auto nominal = type->getAnyNominal(); + if (nominal && !isa(nominal)) { + // Metadata accessors for fully-substituted generic types are + // emitted with shared linkage. + if (nominal->isGenericContext()) { + if (isa(type)) + return MetadataAccessStrategy::NonUniqueAccessor; + assert(isa(type)); + } - if (preferDirectAccess && - isTypeMetadataAccessTrivial(IGM, type)) - return MetadataAccessStrategy::Direct; + // If the type doesn't guarantee that it has an access function, + // we might have to use a non-unique accessor. // Everything else requires accessors. - switch (getDeclLinkage(nominal->getDecl())) { + switch (getDeclLinkage(nominal)) { case FormalLinkage::PublicUnique: return MetadataAccessStrategy::PublicUniqueAccessor; case FormalLinkage::HiddenUnique: @@ -472,23 +437,6 @@ irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type, llvm_unreachable("bad formal linkage"); } - // Builtin types are assumed to be implemented with metadata in the runtime. - if (isa(type)) - return MetadataAccessStrategy::Direct; - - // DynamicSelfType is actually local. - if (type->hasDynamicSelfType()) - return MetadataAccessStrategy::Direct; - - // The zero-element tuple has special metadata in the runtime. - if (auto tuple = dyn_cast(type)) - if (tuple->getNumElements() == 0) - return MetadataAccessStrategy::Direct; - - // SIL box types are opaque to the runtime; NativeObject stands in for them. - if (isa(type)) - return MetadataAccessStrategy::Direct; - // Everything else requires a shared accessor function. return MetadataAccessStrategy::NonUniqueAccessor; } @@ -661,6 +609,8 @@ namespace { elements.size()); Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(), "tuple-elements"); + IGF.Builder.CreateLifetimeStart(buffer, + IGF.IGM.getPointerSize() * elements.size()); for (unsigned i = 0, e = elements.size(); i != e; ++i) { // Find the metadata pointer for this element. llvm::Value *eltMetadata = IGF.emitTypeMetadataRef(elements[i]); @@ -686,6 +636,9 @@ namespace { call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); + IGF.Builder.CreateLifetimeEnd(buffer, + IGF.IGM.getPointerSize() * elements.size()); + return setLocal(type, call); } } @@ -810,6 +763,8 @@ namespace { Address buffer = IGF.createAlloca(arrayTy, IGF.IGM.getPointerAlignment(), "function-arguments"); + IGF.Builder.CreateLifetimeStart(buffer, + IGF.IGM.getPointerSize() * arguments.size()); Address pointerToFirstArg = IGF.Builder.CreateStructGEP(buffer, 0, Size(0)); Address flagsPtr = IGF.Builder.CreateBitCast(pointerToFirstArg, @@ -835,6 +790,10 @@ namespace { pointerToFirstArg.getAddress()); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); + + IGF.Builder.CreateLifetimeEnd(buffer, + IGF.IGM.getPointerSize() * arguments.size()); + return setLocal(type, call); } } @@ -882,6 +841,8 @@ namespace { Address descriptorArray = IGF.createAlloca(descriptorArrayTy, IGF.IGM.getPointerAlignment(), "protocols"); + IGF.Builder.CreateLifetimeStart(descriptorArray, + IGF.IGM.getPointerSize() * protocols.size()); descriptorArray = IGF.Builder.CreateBitCast(descriptorArray, IGF.IGM.ProtocolDescriptorPtrTy->getPointerTo()); @@ -899,6 +860,8 @@ namespace { descriptorArray.getAddress()}); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); + IGF.Builder.CreateLifetimeEnd(descriptorArray, + IGF.IGM.getPointerSize() * protocols.size()); return setLocal(type, call); } @@ -920,7 +883,7 @@ namespace { } llvm::Value *visitArchetypeType(CanArchetypeType type) { - return IGF.getLocalTypeData(type, LocalTypeData::forMetatype()); + return IGF.getLocalTypeData(type, LocalTypeDataKind::forTypeMetadata()); } llvm::Value *visitGenericTypeParamType(CanGenericTypeParamType type) { @@ -949,12 +912,12 @@ namespace { /// Try to find the metatype in local data. llvm::Value *tryGetLocal(CanType type) { - return IGF.tryGetLocalTypeData(type, LocalTypeData::forMetatype()); + return IGF.tryGetLocalTypeData(type, LocalTypeDataKind::forTypeMetadata()); } /// Set the metatype in local data. llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) { - IGF.setScopedLocalTypeData(type, LocalTypeData::forMetatype(), + IGF.setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), metatype); return metatype; } @@ -978,70 +941,6 @@ static Address emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF, return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize()); } -static void emitInitializeSuperclassOfMetaclass(IRGenFunction &IGF, - llvm::Value *metaclass, - llvm::Value *superMetadata) { - assert(IGF.IGM.ObjCInterop && "metaclasses only matter for ObjC interop"); - - // The superclass of the metaclass is the metaclass of the superclass. - - // Read the superclass's metaclass. - llvm::Value *superMetaClass = - emitLoadOfObjCHeapMetadataRef(IGF, superMetadata); - superMetaClass = IGF.Builder.CreateBitCast(superMetaClass, - IGF.IGM.TypeMetadataPtrTy); - - // Write to the new metaclass's superclass field. - Address metaSuperField - = emitAddressOfSuperclassRefInClassMetadata(IGF, metaclass); - - IGF.Builder.CreateStore(superMetaClass, metaSuperField); -} - -static llvm::Value *emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF, - CanType type, - ForDefinition_t shouldDefine); - -/// Emit runtime initialization that must occur before a type metadata access. -/// -/// This initialization must be dependency-ordered-before any loads from -/// the initialized metadata pointer. -static void emitDirectTypeMetadataInitialization(IRGenFunction &IGF, - CanType type) { - // Currently only concrete subclasses of generic bases need this. - auto classDecl = type->getClassOrBoundGenericClass(); - if (!classDecl) - return; - if (classDecl->isGenericContext()) - return; - auto superclass = type->getSuperclass(nullptr); - if (!superclass) - return; - - // If any ancestors are generic, we need to trigger the superclass's - // initialization. - auto ancestor = superclass; - while (ancestor) { - if (ancestor->getClassOrBoundGenericClass()->isGenericContext()) - goto initialize_super; - - ancestor = ancestor->getSuperclass(nullptr); - } - // No generic ancestors. - return; - -initialize_super: - auto classMetadata = IGF.IGM.getAddrOfTypeMetadata(type, /*pattern*/ false); - // Get the superclass metadata. - auto superMetadata = IGF.emitTypeMetadataRef(superclass->getCanonicalType()); - - // Ask the runtime to initialize the superclass of the metaclass. - // This function will ensure the initialization is dependency-ordered-before - // any loads from the base class metadata. - auto initFn = IGF.IGM.getInitializeSuperclassFn(); - IGF.Builder.CreateCall(initFn, {classMetadata, superMetadata}); -} - /// Emit the body of a lazy cache accessor. /// /// If cacheVariable is null, we perform the direct access every time. @@ -1129,11 +1028,127 @@ void irgen::emitLazyCacheAccessFunction(IRGenModule &IGM, IGF.Builder.CreateRet(phi); } +static llvm::Value *emitGenericMetadataAccessFunction(IRGenFunction &IGF, + NominalTypeDecl *nominal, + GenericArguments genericArgs) { + CanType declaredType = nominal->getDeclaredType()->getCanonicalType(); + llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(declaredType, true); + + // Collect input arguments to the generic metadata accessor, as laid out + // by the GenericArguments class. + for (auto &arg : IGF.CurFn->args()) + genericArgs.Values.push_back(&arg); + assert(genericArgs.Values.size() == genericArgs.Types.size()); + assert(genericArgs.Values.size() > 0 && "no generic args?!"); + + // Slam that information directly into the generic arguments buffer. + auto argsBufferTy = + llvm::StructType::get(IGF.IGM.LLVMContext, genericArgs.Types); + Address argsBuffer = IGF.createAlloca(argsBufferTy, + IGF.IGM.getPointerAlignment(), + "generic.arguments"); + IGF.Builder.CreateLifetimeStart(argsBuffer, + IGF.IGM.getPointerSize() * genericArgs.Values.size()); + for (unsigned i = 0, e = genericArgs.Values.size(); i != e; ++i) { + Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i, + IGF.IGM.getPointerSize() * i); + IGF.Builder.CreateStore(genericArgs.Values[i], elt); + } + + // Cast to void*. + llvm::Value *arguments = + IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGF.IGM.Int8PtrTy); + + // Make the call. + auto result = IGF.Builder.CreateCall(IGF.IGM.getGetGenericMetadataFn(), + {metadata, arguments}); + result->setDoesNotThrow(); + result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadOnly); + + IGF.Builder.CreateLifetimeEnd(argsBuffer, + IGF.IGM.getPointerSize() * genericArgs.Values.size()); + + return result; + +} + +/// Emit the body of a metadata accessor function for the given type. +static llvm::Value *emitMetadataAccessFunction(IRGenFunction &IGF, + CanType type) { + if (auto nominal = type->getAnyNominal()) { + if (nominal->isGenericContext()) { + // This is a metadata accessor for a fully substituted generic type. + assert(!type->hasArchetype() && + "partially substituted types do not have accessors"); + return emitDirectTypeMetadataRef(IGF, type); + } + + // We should not be emitting metadata accessors for types unless + // we have full knowledge of their layout. + assert(!IGF.IGM.isResilient(nominal, ResilienceExpansion::Maximal)); + + // We will still have a metadata pattern if the type is not generic, + // but contains resiliently-sized fields. + bool isPattern = IGF.IGM.hasMetadataPattern(nominal); + + // Non-native Swift classes need to be handled differently. + if (auto classDecl = dyn_cast(nominal)) { + // We emit a completely different pattern for foreign classes. + if (classDecl->isForeign()) { + return emitForeignTypeMetadataRef(IGF, type); + } + + // Classes that might not have Swift metadata use a different + // symbol name. + if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) { + assert(!classDecl->isGenericContext() && + "ObjC class cannot be generic"); + return emitObjCMetadataRef(IGF, classDecl); + } + + // If this is a class with constant metadata, we still need to + // force ObjC initialization if we're doing Objective-C interop. + if (IGF.IGM.ObjCInterop && !isPattern) { + llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false); + metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy); + metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(), + metadata); + return IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy); + } + + // Imported value types require foreign metadata uniquing too. + } else if (nominal->hasClangNode()) { + return emitForeignTypeMetadataRef(IGF, type); + } + + // If we have a pattern but no generic substitutions, we're just + // doing resilient type layout. + if (isPattern) { + llvm::Constant *getter = IGF.IGM.getGetResilientMetadataFn(); + + llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, true); + auto result = IGF.Builder.CreateCall(getter, {metadata}); + result->setDoesNotThrow(); + result->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::ReadNone); + return result; + } + + // Accessor is trivial, just return pointer to constant metadata. + return IGF.IGM.getAddrOfTypeMetadata(type, false); + } + + return emitDirectTypeMetadataRef(IGF, type); +} + /// Get or create an accessor function to the given non-dependent type. static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, - CanType type, - ForDefinition_t shouldDefine) { + CanType type, + ForDefinition_t shouldDefine) { assert(!type->hasArchetype()); + assert(!isa(type)); + llvm::Function *accessor = IGM.getAddrOfTypeMetadataAccessFunction(type, shouldDefine); @@ -1154,8 +1169,33 @@ static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, emitLazyCacheAccessFunction(IGM, accessor, cacheVariable, [&](IRGenFunction &IGF) -> llvm::Value* { - emitDirectTypeMetadataInitialization(IGF, type); - return emitDirectTypeMetadataRef(IGF, type); + return emitMetadataAccessFunction(IGF, type); + }); + + return accessor; +} + +/// Get or create an accessor function to the given generic type. +static llvm::Function *getGenericTypeMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *nominal, + ForDefinition_t shouldDefine) { + assert(nominal->isGenericContext()); + + GenericArguments genericArgs; + genericArgs.collectTypes(IGM, nominal); + + llvm::Function *accessor = + IGM.getAddrOfGenericTypeMetadataAccessFunction( + nominal, genericArgs.Types, shouldDefine); + + // If we're not supposed to define the accessor, or if we already + // have defined it, just return the pointer. + if (!shouldDefine || !accessor->empty()) + return accessor; + + emitLazyCacheAccessFunction(IGM, accessor, /*cacheVariable=*/nullptr, + [&](IRGenFunction &IGF) -> llvm::Value* { + return emitGenericMetadataAccessFunction(IGF, nominal, genericArgs); }); return accessor; @@ -1165,16 +1205,13 @@ static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, /// for the given type. static void maybeEmitTypeMetadataAccessFunction(IRGenModule &IGM, NominalTypeDecl *theDecl) { - CanType declaredType = theDecl->getDeclaredType()->getCanonicalType(); + if (theDecl->isGenericContext()) { + (void) getGenericTypeMetadataAccessFunction(IGM, theDecl, ForDefinition); + return; + } - // FIXME: Also do this for generic structs. - // FIXME: Internal types with availability from another module can be - // referenced from @_transparent functions. - if (!theDecl->isGenericContext() && - (isa(theDecl) || - theDecl->getFormalAccess() == Accessibility::Public || - !IGM.getTypeInfoForLowered(declaredType).isFixedSize())) - (void) getTypeMetadataAccessFunction(IGM, declaredType, ForDefinition); + CanType declaredType = theDecl->getDeclaredType()->getCanonicalType(); + (void) getTypeMetadataAccessFunction(IGM, declaredType, ForDefinition); } /// Emit a call to the type metadata accessor for the given function. @@ -1182,7 +1219,8 @@ static llvm::Value *emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF, CanType type, ForDefinition_t shouldDefine) { // If we already cached the metadata, use it. - if (auto local = IGF.tryGetLocalTypeData(type, LocalTypeData::forMetatype())) + if (auto local = + IGF.tryGetLocalTypeData(type, LocalTypeDataKind::forTypeMetadata())) return local; llvm::Constant *accessor = @@ -1193,29 +1231,45 @@ static llvm::Value *emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF, call->setDoesNotThrow(); // Save the metadata for future lookups. - IGF.setScopedLocalTypeData(type, LocalTypeData::forMetatype(), call); + IGF.setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), call); return call; } /// Produce the type metadata pointer for the given type. llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) { - if (!type->hasArchetype()) { - switch (getTypeMetadataAccessStrategy(IGM, type, - /*preferDirectAccess=*/true)) { - case MetadataAccessStrategy::Direct: - return emitDirectTypeMetadataRef(*this, type); - case MetadataAccessStrategy::PublicUniqueAccessor: - case MetadataAccessStrategy::HiddenUniqueAccessor: - case MetadataAccessStrategy::PrivateAccessor: - return emitCallToTypeMetadataAccessFunction(*this, type, NotForDefinition); - case MetadataAccessStrategy::NonUniqueAccessor: - return emitCallToTypeMetadataAccessFunction(*this, type, ForDefinition); - } - llvm_unreachable("bad type metadata access strategy"); + if (type->hasArchetype() || + isTypeMetadataAccessTrivial(IGM, type)) { + return emitDirectTypeMetadataRef(*this, type); + } + + switch (getTypeMetadataAccessStrategy(IGM, type)) { + case MetadataAccessStrategy::PublicUniqueAccessor: + case MetadataAccessStrategy::HiddenUniqueAccessor: + case MetadataAccessStrategy::PrivateAccessor: + return emitCallToTypeMetadataAccessFunction(*this, type, NotForDefinition); + case MetadataAccessStrategy::NonUniqueAccessor: + return emitCallToTypeMetadataAccessFunction(*this, type, ForDefinition); } + llvm_unreachable("bad type metadata access strategy"); +} - return emitDirectTypeMetadataRef(*this, type); +/// Return the address of a function that will return type metadata +/// for the given non-dependent type. +llvm::Function *irgen::getOrCreateTypeMetadataAccessFunction(IRGenModule &IGM, + CanType type) { + assert(!type->hasArchetype() && + "cannot create global function to return dependent type metadata"); + + switch (getTypeMetadataAccessStrategy(IGM, type)) { + case MetadataAccessStrategy::PublicUniqueAccessor: + case MetadataAccessStrategy::HiddenUniqueAccessor: + case MetadataAccessStrategy::PrivateAccessor: + return getTypeMetadataAccessFunction(IGM, type, NotForDefinition); + case MetadataAccessStrategy::NonUniqueAccessor: + return getTypeMetadataAccessFunction(IGM, type, ForDefinition); + } + llvm_unreachable("bad type metadata access strategy"); } namespace { @@ -1307,6 +1361,8 @@ namespace { elements.size()); Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(), "tuple-elements"); + IGF.Builder.CreateLifetimeStart(buffer, + IGF.IGM.getPointerSize() * elements.size()); for (unsigned i = 0, e = elements.size(); i != e; ++i) { // Find the metadata pointer for this element. llvm::Value *eltMetadata = visit(elements[i]); @@ -1333,6 +1389,9 @@ namespace { call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); + IGF.Builder.CreateLifetimeEnd(buffer, + IGF.IGM.getPointerSize() * elements.size()); + return setLocal(type, call); } } @@ -1395,13 +1454,13 @@ namespace { llvm::Value *tryGetLocal(CanType type) { return IGF.tryGetLocalTypeDataForLayout( SILType::getPrimitiveObjectType(type), - LocalTypeData::forMetatype()); + LocalTypeDataKind::forTypeMetadata()); } /// Set the metatype in local data. llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) { IGF.setScopedLocalTypeDataForLayout(SILType::getPrimitiveObjectType(type), - LocalTypeData::forMetatype(), + LocalTypeDataKind::forTypeMetadata(), metatype); return metatype; } @@ -1503,7 +1562,7 @@ namespace { // If the type is a singleton aggregate, the field's layout is equivalent // to the aggregate's. if (SILType singletonFieldTy = getSingletonAggregateFieldType(IGF.IGM, - silTy, ResilienceScope::Component)) + silTy, ResilienceExpansion::Maximal)) return visit(singletonFieldTy.getSwiftRValueType()); // If the type is fixed-layout, emit a copy of its layout. @@ -1675,6 +1734,17 @@ llvm::Value *IRGenFunction::emitTypeLayoutRef(SILType type) { return EmitTypeLayoutRef(*this).visit(type.getSwiftRValueType()); } +void IRGenModule::setTrueConstGlobal(llvm::GlobalVariable *var) { + switch (TargetInfo.OutputObjectFormat) { + case llvm::Triple::MachO: + var->setSection("__TEXT, __const"); + break; + // TODO: ELF? + default: + break; + } +} + /// Produce the heap metadata pointer for the given class type. For /// Swift-defined types, this is equivalent to the metatype for the /// class, but for Objective-C-defined types, this is the class @@ -1790,18 +1860,13 @@ namespace { IRGenModule &IGM = Base::IGM; private: + llvm::GlobalVariable *relativeAddressBase = nullptr; llvm::SmallVector Fields; Size NextOffset = Size(0); protected: Size getNextOffset() const { return NextOffset; } - /// Add a uintptr_t value that represents the given offset, but - /// scaled to a number of words. - void addConstantWordInWords(Size value) { - addConstantWord(getOffsetInWords(IGM, value)); - } - /// Add a constant word-sized value. void addConstantWord(int64_t value) { addWord(llvm::ConstantInt::get(IGM.SizeTy, value)); @@ -1816,7 +1881,58 @@ namespace { NextOffset += IGM.getPointerSize(); } - /// Add a uint32_t value that represents the given offset, but + void setRelativeAddressBase(llvm::GlobalVariable *base) { + relativeAddressBase = base; + } + + llvm::Constant *getRelativeAddressFromNextField(llvm::Constant *referent) { + assert(relativeAddressBase && "no relative address base set"); + // Determine the address of the next field in the initializer. + llvm::Constant *fieldAddr = + llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.SizeTy); + fieldAddr = llvm::ConstantExpr::getAdd(fieldAddr, + llvm::ConstantInt::get(IGM.SizeTy, + getNextOffset().getValue())); + referent = llvm::ConstantExpr::getPtrToInt(referent, IGM.SizeTy); + + llvm::Constant *relative + = llvm::ConstantExpr::getSub(referent, fieldAddr); + + if (relative->getType() != IGM.RelativeAddressTy) + relative = llvm::ConstantExpr::getTrunc(relative, + IGM.RelativeAddressTy); + return relative; + } + + /// Add a 32-bit relative address from the current location in the local + /// being built to another global variable. + void addRelativeAddress(llvm::Constant *referent) { + addInt32(getRelativeAddressFromNextField(referent)); + } + + /// Add a 32-bit relative address from the current location in the local + /// being built to another global variable, or null if a null referent + /// is passed. + void addRelativeAddressOrNull(llvm::Constant *referent) { + if (referent) + addRelativeAddress(referent); + else + addConstantInt32(0); + } + + /// Add a 32-bit relative address from the current location in the local + /// being built to another global variable. Pack a constant integer into + /// the alignment bits of the pointer. + void addRelativeAddressWithTag(llvm::Constant *referent, + unsigned tag) { + assert(tag < 4 && "tag too big to pack in relative address"); + llvm::Constant *relativeAddr = getRelativeAddressFromNextField(referent); + relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, + llvm::ConstantInt::get(IGM.RelativeAddressTy, tag)); + addInt32(relativeAddr); + } + + /// Add a uint32_t value that represents the given offset /// scaled to a number of words. void addConstantInt32InWords(Size value) { addConstantInt32(getOffsetInWords(IGM, value)); @@ -1848,6 +1964,19 @@ namespace { NextOffset += Size(2); } + /// Add a constant 8-bit value. + void addConstantInt8(int8_t value) { + addInt8(llvm::ConstantInt::get(IGM.Int8Ty, value)); + } + + /// Add an 8-bit value. + void addInt8(llvm::Constant *value) { + assert(value->getType() == IGM.Int8Ty); + assert(NextOffset.isMultipleOf(Size(1))); + Fields.push_back(value); + NextOffset += Size(1); + } + /// Add a constant of the given size. void addStruct(llvm::Constant *value, Size size) { assert(size.getValue() @@ -1900,34 +2029,32 @@ namespace { NominalTypeDescriptorBuilderBase(IRGenModule &IGM) : ConstantBuilder(IGM) {} void layout() { - asImpl().addKind(); asImpl().addName(); asImpl().addKindDependentFields(); - asImpl().addGenericMetadataPattern(); + asImpl().addGenericMetadataPatternAndKind(); asImpl().addGenericParams(); } - void addKind() { - addConstantWord(asImpl().getKind()); - } - void addName() { NominalTypeDecl *ntd = asImpl().getTarget(); - addWord(getMangledTypeName(IGM, - ntd->getDeclaredType()->getCanonicalType())); + addRelativeAddress(getMangledTypeName(IGM, + ntd->getDeclaredType()->getCanonicalType(), + /*willBeRelativelyAddressed*/ true)); } - void addGenericMetadataPattern() { + void addGenericMetadataPatternAndKind() { NominalTypeDecl *ntd = asImpl().getTarget(); - if (!ntd->getGenericParams()) { - // If there are no generic parameters, there's no pattern to link. - addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPatternPtrTy)); + auto kind = asImpl().getKind(); + if (!IGM.hasMetadataPattern(ntd)) { + // There's no pattern to link. + addConstantInt32(kind); return; } - - addWord(IGM.getAddrOfTypeMetadata(ntd->getDeclaredType() - ->getCanonicalType(), - /*pattern*/ true)); + + addRelativeAddressWithTag( + IGM.getAddrOfTypeMetadata(ntd->getDeclaredType()->getCanonicalType(), + /*pattern*/ true), + kind); } void addGenericParams() { @@ -1976,6 +2103,11 @@ namespace { } llvm::Constant *emit() { + // Set up a dummy global to stand in for the constant. + std::unique_ptr tempBase( + new llvm::GlobalVariable(IGM.Int8Ty, true, + llvm::GlobalValue::PrivateLinkage)); + setRelativeAddressBase(tempBase.get()); asImpl().layout(); auto init = getInit(); @@ -1984,6 +2116,11 @@ namespace { init->getType())); var->setConstant(true); var->setInitializer(init); + IGM.setTrueConstGlobal(var); + + auto replacer = llvm::ConstantExpr::getBitCast(var, IGM.Int8PtrTy); + tempBase->replaceAllUsesWith(replacer); + return var; } @@ -2305,14 +2442,15 @@ namespace { addConstantInt32(numFields); addConstantInt32InWords(FieldVectorOffset); - addWord(IGM.getAddrOfGlobalString(fieldNames)); + addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames, + /*willBeRelativelyAddressed*/ true)); // Build the field type accessor function. llvm::Function *fieldTypeVectorAccessor = getFieldTypeAccessorFn(IGM, Target, Target->getStoredProperties()); - addWord(fieldTypeVectorAccessor); + addRelativeAddress(fieldTypeVectorAccessor); } }; @@ -2389,14 +2527,15 @@ namespace { addConstantInt32(numFields); addConstantInt32InWords(FieldVectorOffset); - addWord(IGM.getAddrOfGlobalString(fieldNames)); + addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames, + /*willBeRelativelyAddressed*/ true)); // Build the field type accessor function. llvm::Function *fieldTypeVectorAccessor = getFieldTypeAccessorFn(IGM, Target, Target->getStoredProperties()); - addWord(fieldTypeVectorAccessor); + addRelativeAddress(fieldTypeVectorAccessor); } }; @@ -2479,14 +2618,14 @@ namespace { // # empty cases addConstantInt32(strategy.getElementsWithNoPayload().size()); - addWord(strategy.emitCaseNames()); + addRelativeAddressOrNull(strategy.emitCaseNames()); // Build the case type accessor. llvm::Function *caseTypeVectorAccessor = getFieldTypeAccessorFn(IGM, Target, strategy.getElementsWithPayload()); - addWord(caseTypeVectorAccessor); + addRelativeAddress(caseTypeVectorAccessor); } }; } @@ -2507,7 +2646,9 @@ irgen::emitFieldTypeAccessor(IRGenModule &IGM, IRGenFunction IGF(IGM, fn); auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo(); + CanType formalType = type->getDeclaredTypeInContext()->getCanonicalType(); llvm::Value *metadata = IGF.collectParameters().claimNext(); + setTypeMetadataName(IGM, metadata, formalType); // Get the address at which the field type vector reference should be // cached. @@ -2556,7 +2697,7 @@ irgen::emitFieldTypeAccessor(IRGenModule &IGM, // Bind the metadata instance to our local type data so we // use it to provide metadata for generic parameters in field types. - emitPolymorphicParametersForGenericValueWitness(IGF, type, metadata); + IGF.bindLocalTypeDataFromTypeMetadata(formalType, IsExact, metadata); // Allocate storage for the field vector. unsigned allocSize = fieldTypes.size() * IGM.getPointerSize().getValue(); @@ -2718,10 +2859,11 @@ namespace { for (auto &fillOp : FillOps) { llvm::Value *value; if (fillOp.Protocol) { - value = emitWitnessTableRef(IGF, fillOp.Archetype, fillOp.Protocol); + value = emitArchetypeWitnessTableRef(IGF, fillOp.Archetype, + fillOp.Protocol); } else { value = IGF.getLocalTypeData(fillOp.Archetype, - LocalTypeData::forMetatype()); + LocalTypeDataKind::forTypeMetadata()); } value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy); auto dest = createPointerSizedGEP(IGF, metadataWords, @@ -2897,11 +3039,13 @@ namespace { using super::addStruct; using super::getNextOffset; const StructLayout &Layout; + const ClassLayout &FieldLayout; SILVTable *VTable; ClassMetadataBuilderBase(IRGenModule &IGM, ClassDecl *theClass, - const StructLayout &layout) - : super(IGM, theClass), Layout(layout) { + const StructLayout &layout, + const ClassLayout &fieldLayout) + : super(IGM, theClass), Layout(layout), FieldLayout(fieldLayout) { VTable = IGM.SILMod->lookUpVTable(Target); } @@ -2910,8 +3054,8 @@ namespace { ClassObjectExtents = getSizeOfMetadata(IGM, Target); } - bool HasRuntimeBase = false; bool HasRuntimeParent = false; + public: /// The 'metadata flags' field in a class is actually a pointer to /// the metaclass object for the class. @@ -2988,48 +3132,10 @@ namespace { if (!addReferenceToType(parentType->getCanonicalType())) HasRuntimeParent = true; } - - void addSuperClass() { - // If this is a root class, use SwiftObject as our formal parent. - if (!Target->hasSuperclass()) { - // This is only required for ObjC interoperation. - if (!IGM.ObjCInterop) { - addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); - return; - } - - // We have to do getAddrOfObjCClass ourselves here because - // the ObjC runtime base needs to be ObjC-mangled but isn't - // actually imported from a clang module. - addWord(IGM.getAddrOfObjCClass( - IGM.getObjCRuntimeBaseForSwiftRootClass(Target), - NotForDefinition)); - return; - } - - Type superclassTy - = ArchetypeBuilder::mapTypeIntoContext(Target, - Target->getSuperclass()); - // If the class has any generic heritage, wait until runtime to set up - // the superclass reference. - auto ancestorTy = superclassTy; - while (ancestorTy) { - if (ancestorTy->getClassOrBoundGenericClass()->isGenericContext()) { - // Add a nil placeholder and continue. - addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); - HasRuntimeBase = true; - return; - } - ancestorTy = ancestorTy->getSuperclass(nullptr); - } - - if (!addReferenceToType(superclassTy->getCanonicalType())) - HasRuntimeBase = true; - } bool addReferenceToType(CanType type) { if (llvm::Constant *metadata - = tryEmitConstantHeapMetadataRef(IGM, type)) { + = tryEmitConstantTypeMetadataRef(IGM, type)) { addWord(metadata); return true; } else { @@ -3123,12 +3229,67 @@ namespace { } void addFieldOffset(VarDecl *var) { - // Use a fixed offset if we have one. - if (auto offset = tryEmitClassConstantFragileFieldOffset(IGM,Target,var)) - addWord(offset); - // Otherwise, leave a placeholder for the runtime to populate at runtime. - else - addWord(llvm::ConstantInt::get(IGM.IntPtrTy, 0)); + assert(var->hasStorage()); + + unsigned fieldIndex = FieldLayout.getFieldIndex(var); + llvm::Constant *fieldOffsetOrZero; + auto &element = Layout.getElement(fieldIndex); + + if (element.getKind() == ElementLayout::Kind::Fixed) { + // Use a fixed offset if we have one. + fieldOffsetOrZero = IGM.getSize(element.getByteOffset()); + } else { + // Otherwise, leave a placeholder for the runtime to populate at runtime. + fieldOffsetOrZero = llvm::ConstantInt::get(IGM.IntPtrTy, 0); + } + addWord(fieldOffsetOrZero); + + if (var->getDeclContext() == Target) { + auto access = FieldLayout.AllFieldAccesses[fieldIndex]; + switch (access) { + case FieldAccess::ConstantDirect: + case FieldAccess::NonConstantDirect: { + // Emit a global variable storing the constant field offset. + // If the superclass was imported from Objective-C, the offset + // does not include the superclass size; we rely on the + // Objective-C runtime sliding it down. + // + // TODO: Don't emit the symbol if field has a fixed offset and size + // in all resilience domains + auto offsetAddr = IGM.getAddrOfFieldOffset(var, /*indirect*/ false, + ForDefinition); + auto offsetVar = cast(offsetAddr.getAddress()); + offsetVar->setInitializer(fieldOffsetOrZero); + + // If we know the offset won't change, make it a constant. + offsetVar->setConstant(access == FieldAccess::ConstantDirect); + + break; + } + + case FieldAccess::ConstantIndirect: + // No global variable is needed. + break; + + case FieldAccess::NonConstantIndirect: + // Emit a global variable storing an offset into the field offset + // vector within the class metadata. This access pattern is used + // when the field offset depends on generic parameters. As above, + // the Objective-C runtime will slide the field offsets within the + // class metadata to adjust for the superclass size. + // + // TODO: This isn't plumbed through all the way yet. + auto offsetAddr = IGM.getAddrOfFieldOffset(var, /*indirect*/ true, + ForDefinition); + auto offsetVar = cast(offsetAddr.getAddress()); + offsetVar->setConstant(false); + auto offset = getClassFieldOffset(IGM, Target, var).getValue(); + auto offsetVal = llvm::ConstantInt::get(IGM.IntPtrTy, offset); + offsetVar->setInitializer(offsetVal); + + break; + } + } } void addMethod(SILDeclRef fn) { @@ -3150,7 +3311,7 @@ namespace { } else { // The method is removed by dead method elimination. // It should be never called. We add a pointer to an error function. - addWord(llvm::ConstantExpr::getBitCast(IGM.getDeadMethodErrorFn(), + addWord(llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(), IGM.FunctionPtrTy)); } } @@ -3163,23 +3324,56 @@ namespace { ProtocolDecl *protocol, ClassDecl *forClass) { addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy)); } - - bool hasRuntimeBase() const { - return HasRuntimeBase; - } }; class ClassMetadataBuilder : public ClassMetadataBuilderBase { public: ClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, - const StructLayout &layout) - : ClassMetadataBuilderBase(IGM, theClass, layout) {} + const StructLayout &layout, + const ClassLayout &fieldLayout) + : ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout) { + + assert(layout.isFixedLayout() && + "non-fixed layout classes require a template"); + // FIXME: Distinguish Objective-C sliding from resilient layout + assert((fieldLayout.MetadataAccess == FieldAccess::ConstantDirect || + fieldLayout.MetadataAccess == FieldAccess::NonConstantDirect) && + "resilient superclasses require a template"); + } llvm::Constant *getInit() { return getInitWithSuggestedType(NumHeapMetadataFields, IGM.FullHeapMetadataStructTy); } + + void addSuperClass() { + // If this is a root class, use SwiftObject as our formal parent. + if (!Target->hasSuperclass()) { + // This is only required for ObjC interoperation. + if (!IGM.ObjCInterop) { + addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); + return; + } + + // We have to do getAddrOfObjCClass ourselves here because + // the ObjC runtime base needs to be ObjC-mangled but isn't + // actually imported from a clang module. + addWord(IGM.getAddrOfObjCClass( + IGM.getObjCRuntimeBaseForSwiftRootClass(Target), + NotForDefinition)); + return; + } + + Type superclassTy + = ArchetypeBuilder::mapTypeIntoContext(Target, + Target->getSuperclass()); + + bool constantSuperclass = + addReferenceToType(superclassTy->getCanonicalType()); + assert(constantSuperclass && "need template if superclass is dependent"); + (void) constantSuperclass; + } }; Address emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF, @@ -3208,14 +3402,6 @@ namespace { { typedef GenericMetadataBuilderBase super; - bool HasDependentSuperclass = false; - bool HasDependentFieldOffsetVector = false; - - std::vector> - AncestorFieldOffsetVectors; - - std::vector AncestorFillOps; - Size MetaclassPtrOffset = Size::invalid(); Size ClassRODataPtrOffset = Size::invalid(); Size MetaclassRODataPtrOffset = Size::invalid(); @@ -3224,19 +3410,18 @@ namespace { Size DependentMetaclassRODataPoint = Size::invalid(); public: GenericClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, - const StructLayout &layout) - : super(IGM, theClass, layout) + const StructLayout &layout, + const ClassLayout &fieldLayout) + : super(IGM, theClass, layout, fieldLayout) { // We need special initialization of metadata objects to trick the ObjC // runtime into initializing them. HasDependentMetadata = true; - - // If the superclass is generic, we'll need to initialize the superclass - // reference at runtime. - if (theClass->hasSuperclass() && - theClass->getSuperclass()->is()) { - HasDependentSuperclass = true; - } + } + + void addSuperClass() { + // Filled in by the runtime. + addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); } llvm::Value *emitAllocateMetadata(IRGenFunction &IGF, @@ -3288,16 +3473,7 @@ namespace { auto isa = IGM.getAddrOfMetaclassObject(rootClass, NotForDefinition); addWord(isa); // super, which is dependent if the superclass is generic - llvm::Constant *super; - if (HasDependentSuperclass) - super = llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy); - else if (Target->hasSuperclass()) - super = IGM.getAddrOfMetaclassObject( - Target->getSuperclass()->getClassOrBoundGenericClass(), - NotForDefinition); - else - super = isa; - addWord(super); + addWord(llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy)); // cache addWord(IGM.getObjCEmptyCachePtr()); // vtable @@ -3321,35 +3497,12 @@ namespace { void addDependentValueWitnessTablePattern() { llvm_unreachable("classes should never have dependent vwtables"); } - + void noteStartOfFieldOffsets(ClassDecl *whichClass) { HasDependentMetadata = true; - - if (whichClass == Target) { - // If the metadata contains a field offset vector for the class itself, - // then we need to initialize it at runtime. - HasDependentFieldOffsetVector = true; - return; - } - - // If we have a field offset vector for an ancestor class, we will copy - // it from our superclass metadata at instantiation time. - AncestorFieldOffsetVectors.emplace_back(whichClass, - asImpl().getNextOffset(), - Size::invalid()); } - void noteEndOfFieldOffsets(ClassDecl *whichClass) { - if (whichClass == Target) - return; - - // Mark the end of the ancestor field offset vector. - assert(!AncestorFieldOffsetVectors.empty() - && "no start of ancestor field offsets?!"); - assert(std::get<0>(AncestorFieldOffsetVectors.back()) == whichClass - && "mismatched start of ancestor field offsets?!"); - std::get<2>(AncestorFieldOffsetVectors.back()) = asImpl().getNextOffset(); - } + void noteEndOfFieldOffsets(ClassDecl *whichClass) {} // Suppress GenericMetadataBuilderBase's default behavior of introducing // fill ops for generic arguments unless they belong directly to the target @@ -3360,10 +3513,9 @@ namespace { // Introduce the fill op. GenericMetadataBuilderBase::addGenericArgument(type, forClass); } else { - // Lay out the field, but don't provide the fill op, which we'll get - // from the superclass. + // Lay out the field, but don't fill it in, we will copy it from + // the superclass. HasDependentMetadata = true; - AncestorFillOps.push_back(getNextOffset()); ClassMetadataBuilderBase::addGenericArgument(type, forClass); } } @@ -3377,14 +3529,40 @@ namespace { } else { // Lay out the field, but don't provide the fill op, which we'll get // from the superclass. - HasDependentMetadata = true; - AncestorFillOps.push_back(getNextOffset()); ClassMetadataBuilderBase::addGenericWitnessTable(type, protocol, forClass); } } + // The Objective-C runtime will copy field offsets from the field offset + // vector into field offset globals for us, if present. If there's no + // Objective-C runtime, we have to do this ourselves. + void emitInitializeFieldOffsets(IRGenFunction &IGF, + llvm::Value *metadata) { + unsigned index = FieldLayout.InheritedStoredProperties.size(); + + for (auto prop : Target->getStoredProperties()) { + auto access = FieldLayout.AllFieldAccesses[index]; + if (access == FieldAccess::NonConstantDirect) { + Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop, + /*indirect*/ false, + ForDefinition); + + // We can't use emitClassFieldOffset() here because that creates + // an invariant load, which could be hoisted above the point + // where the metadata becomes fully initialized + Size offset = getClassFieldOffset(IGF.IGM, Target, prop); + int index = getOffsetInWords(IGF.IGM, offset); + auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index, + IGF.IGM.SizeTy); + IGF.Builder.CreateStore(offsetVal, offsetA); + } + + index++; + } + } + void emitInitializeMetadata(IRGenFunction &IGF, llvm::Value *metadata, llvm::Value *vwtable) { @@ -3443,7 +3621,7 @@ namespace { // NOTE: Unlike other bits of the metadata that should later be removed, // this one is important because things check this value's flags to // determine what kind of object it is. That said, if those checks - // are determined to be removeable, we can remove this as well per + // are determined to be removable, we can remove this as well per // rdar://problem/18801263 assert(!ClassRODataPtrOffset.isInvalid()); Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr, @@ -3472,75 +3650,13 @@ namespace { IGF.Builder.CreateStore(rodata, rodataPtrSlot); } - if (IGF.IGM.ObjCInterop) { - // Generate the runtime name for the class and poke it into the rodata. - auto name = IGF.Builder.CreateCall(IGM.getGetGenericClassObjCNameFn(), - metadata); - name->setDoesNotThrow(); - Size nameOffset(IGM.getPointerAlignment().getValue() > 4 ? 24 : 16); - for (Address rodataPtr : {classRODataPtr, metaclassRODataPtr}) { - auto namePtr = createPointerSizedGEP(IGF, rodataPtr, nameOffset); - namePtr = IGF.Builder.CreateBitCast(namePtr, IGM.Int8PtrPtrTy); - IGF.Builder.CreateStore(name, namePtr); - } - } - - // Get the superclass metadata. - llvm::Value *superMetadata; - if (Target->hasSuperclass()) { - Address superField - = emitAddressOfSuperclassRefInClassMetadata(IGF, metadata); - superMetadata = IGF.Builder.CreateLoad(superField); - } else { - assert(!HasDependentSuperclass - && "dependent superclass without superclass?!"); - superMetadata - = llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy); - } - - // If the superclass is generic, we need to populate the - // superclass field of the metaclass. - if (IGF.IGM.ObjCInterop && HasDependentSuperclass) { - emitInitializeSuperclassOfMetaclass(IGF, metaclass, superMetadata); - } - - // If we have any ancestor generic parameters or field offset vectors, - // copy them from the superclass metadata. - if (!AncestorFieldOffsetVectors.empty() || !AncestorFillOps.empty()) { - Address superBase(superMetadata, IGF.IGM.getPointerAlignment()); - Address selfBase(metadata, IGF.IGM.getPointerAlignment()); - superBase = IGF.Builder.CreateBitCast(superBase, - IGF.IGM.SizeTy->getPointerTo()); - selfBase = IGF.Builder.CreateBitCast(selfBase, - IGF.IGM.SizeTy->getPointerTo()); - - for (Size ancestorOp : AncestorFillOps) { - ancestorOp -= AddressPoint; - Address superOp = createPointerSizedGEP(IGF, superBase, ancestorOp); - Address selfOp = createPointerSizedGEP(IGF, selfBase, ancestorOp); - IGF.Builder.CreateStore(IGF.Builder.CreateLoad(superOp), selfOp); - } - - for (auto &ancestorFields : AncestorFieldOffsetVectors) { - ClassDecl *ancestor; - Size startIndex, endIndex; - std::tie(ancestor, startIndex, endIndex) = ancestorFields; - assert(startIndex <= endIndex); - if (startIndex == endIndex) - continue; - Size size = endIndex - startIndex; - startIndex -= AddressPoint; - - Address superVec = createPointerSizedGEP(IGF, superBase, startIndex); - Address selfVec = createPointerSizedGEP(IGF, selfBase, startIndex); - - IGF.Builder.CreateMemCpy(selfVec, superVec, size); - } - } - - // If the field layout is dependent, ask the runtime to populate the - // offset vector. - if (HasDependentFieldOffsetVector) { + // If we have fields that are not fixed-size, ask the runtime to + // populate the offset vector. + // + // FIXME: if only the superclass is resilient, we can get away + // with sliding field offsets instead of doing the entire layout all + // over again. + if (!Layout.isFixedLayout()) { llvm::Value *fieldVector = emitAddressOfFieldOffsetVectorInClassMetadata(IGF, Target, metadata) @@ -3557,6 +3673,9 @@ namespace { llvm::ArrayType::get(IGF.IGM.SizeTy, storedProperties.size() * 2), IGF.IGM.getPointerAlignment(), "classFields"); + IGF.Builder.CreateLifetimeStart(fields, + IGF.IGM.getPointerSize() * storedProperties.size() * 2); + Address firstField; unsigned index = 0; for (auto prop : storedProperties) { @@ -3588,16 +3707,29 @@ namespace { // Ask the runtime to lay out the class. auto numFields = IGF.IGM.getSize(Size(storedProperties.size())); IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(), - {metadata, superMetadata, numFields, + {metadata, numFields, firstField.getAddress(), fieldVector}); + IGF.Builder.CreateLifetimeEnd(fields, + IGF.IGM.getPointerSize() * storedProperties.size() * 2); - } else if (IGF.IGM.ObjCInterop) { - // Register the class with the ObjC runtime. - llvm::Value *instantiateObjC = IGF.IGM.getInstantiateObjCClassFn(); - IGF.Builder.CreateCall(instantiateObjC, metadata); + } else { + // If we have any ancestor generic parameters or field offset vectors, + // copy them from the superclass metadata. + auto initFn = IGF.IGM.getInitializeSuperclassFn(); + + bool copyFieldOffsetVectors = false; + if (FieldLayout.MetadataAccess != FieldAccess::ConstantDirect) + copyFieldOffsetVectors = true; + + IGF.Builder.CreateCall(initFn, + {metadata, + llvm::ConstantInt::get(IGF.IGM.Int1Ty, + copyFieldOffsetVectors)}); } + + if (!IGF.IGM.ObjCInterop) + emitInitializeFieldOffsets(IGF, metadata); } - }; } @@ -3622,25 +3754,23 @@ static void emitObjCClassSymbol(IRGenModule &IGM, /// Emit the type metadata or metadata template for a class. void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, - const StructLayout &layout) { + const StructLayout &layout, + const ClassLayout &fieldLayout) { assert(!classDecl->isForeign()); // TODO: classes nested within generic types llvm::Constant *init; bool isPattern; - bool hasRuntimeBase; - if (classDecl->isGenericContext()) { - GenericClassMetadataBuilder builder(IGM, classDecl, layout); + if (IGM.hasMetadataPattern(classDecl)) { + GenericClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout); builder.layout(); init = builder.getInit(); isPattern = true; - hasRuntimeBase = builder.hasRuntimeBase(); } else { - ClassMetadataBuilder builder(IGM, classDecl, layout); + ClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout); builder.layout(); init = builder.getInit(); isPattern = false; - hasRuntimeBase = builder.hasRuntimeBase(); } maybeEmitTypeMetadataAccessFunction(IGM, classDecl); @@ -3662,7 +3792,7 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, /*isConstant*/ false, init, section); // Add non-generic classes to the ObjC class list. - if (IGM.ObjCInterop && !isPattern && !isIndirect && !hasRuntimeBase) { + if (IGM.ObjCInterop && !isPattern && !isIndirect) { // Emit the ObjC class symbol to make the class visible to ObjC. if (classDecl->isObjC()) { emitObjCClassSymbol(IGM, classDecl, var); @@ -3686,14 +3816,11 @@ void IRGenFunction::setDereferenceableLoad(llvm::LoadInst *load, } /// Emit a load from the given metadata at a constant index. -/// -/// The load is marked invariant. This function should not be called -/// on metadata objects that are in the process of being initialized. -static llvm::LoadInst *emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, - llvm::Value *metadata, - int index, - llvm::PointerType *objectTy, - const llvm::Twine &suffix = ""){ +static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF, + llvm::Value *metadata, + int index, + llvm::Type *objectTy, + const llvm::Twine &suffix) { // Require the metadata to be some type that we recognize as a // metadata pointer. assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); @@ -3701,6 +3828,8 @@ static llvm::LoadInst *emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, // We require objectType to be a pointer type so that the GEP will // scale by the right amount. We could load an arbitrary type using // some extra bitcasting. + assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) == + IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy)); // Cast to T*. auto objectPtrTy = objectTy->getPointerTo(); @@ -3713,8 +3842,21 @@ static llvm::LoadInst *emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, IGF.IGM.getPointerAlignment()); // Load. - auto result = IGF.Builder.CreateLoad(slot, - metadata->getName() + suffix); + return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix); +} + +/// Emit a load from the given metadata at a constant index. +/// +/// The load is marked invariant. This function should not be called +/// on metadata objects that are in the process of being initialized. +static llvm::LoadInst * +emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, + llvm::Value *metadata, + int index, + llvm::Type *objectTy, + const Twine &suffix = Twine::createNull()) { + auto result = emitLoadFromMetadataAtIndex(IGF, metadata, index, objectTy, + suffix); IGF.setInvariantLoad(result); return result; } @@ -3724,13 +3866,14 @@ llvm::Value * IRGenFunction::emitValueWitnessTableRef(CanType type) { // See if we have a cached projection we can use. if (auto cached = tryGetLocalTypeData(type, - LocalTypeData::forValueWitnessTable())) { + LocalTypeDataKind::forValueWitnessTable())) { return cached; } auto metadata = emitTypeMetadataRef(type); auto vwtable = emitValueWitnessTableRefForMetadata(metadata); - setScopedLocalTypeData(type, LocalTypeData::forValueWitnessTable(), vwtable); + setScopedLocalTypeData(type, LocalTypeDataKind::forValueWitnessTable(), + vwtable); return vwtable; } @@ -3738,8 +3881,8 @@ IRGenFunction::emitValueWitnessTableRef(CanType type) { llvm::Value * IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) { auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, -1, - IGM.WitnessTablePtrTy, - ".valueWitnesses"); + IGM.WitnessTablePtrTy, + ".valueWitnesses"); // A value witness table is dereferenceable to the number of value witness // pointers. @@ -3758,14 +3901,14 @@ llvm::Value * IRGenFunction::emitValueWitnessTableRefForLayout(SILType type) { // See if we have a cached projection we can use. if (auto cached = tryGetLocalTypeDataForLayout(type, - LocalTypeData::forValueWitnessTable())) { + LocalTypeDataKind::forValueWitnessTable())) { return cached; } auto metadata = emitTypeMetadataRefForLayout(type); auto vwtable = emitValueWitnessTableRefForMetadata(metadata); setScopedLocalTypeDataForLayout(type, - LocalTypeData::forValueWitnessTable(), + LocalTypeDataKind::forValueWitnessTable(), vwtable); return vwtable; } @@ -3775,7 +3918,7 @@ static llvm::Value *emitLoadOfMetadataRefAtIndex(IRGenFunction &IGF, llvm::Value *metadata, int index) { return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index, - IGF.IGM.TypeMetadataPtrTy); + IGF.IGM.TypeMetadataPtrTy); } /// Load the protocol witness table reference at the given index. @@ -3783,7 +3926,7 @@ static llvm::Value *emitLoadOfWitnessTableRefAtIndex(IRGenFunction &IGF, llvm::Value *metadata, int index) { return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index, - IGF.IGM.WitnessTablePtrTy); + IGF.IGM.WitnessTablePtrTy); } namespace { @@ -3977,8 +4120,8 @@ llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF, llvm::Value *metadata) { irgen::Size offset = getClassFieldOffset(IGF.IGM, theClass, field); int index = getOffsetInWords(IGF.IGM, offset); - llvm::Value *val = emitLoadOfWitnessTableRefAtIndex(IGF, metadata, index); - return IGF.Builder.CreatePtrToInt(val, IGF.IGM.SizeTy); + return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index, + IGF.IGM.SizeTy); } /// Given a reference to class metadata of the given type, @@ -4120,7 +4263,8 @@ static llvm::Value *emitLoadOfHeapMetadataRef(IRGenFunction &IGF, auto metadata = IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment())); - metadata->setName(llvm::Twine(object->getName()) + ".metadata"); + if (IGF.IGM.EnableValueNames && object->hasName()) + metadata->setName(llvm::Twine(object->getName()) + ".metadata"); return metadata; } @@ -4242,7 +4386,8 @@ llvm::Value *irgen::emitClassHeapMetadataRefForMetatype(IRGenFunction &IGF, // a select here instead, which might be profitable. IGF.Builder.emitBlock(wrapBB); auto classFromWrapper = - emitInvariantLoadFromMetadataAtIndex(IGF, metatype, 1, IGF.IGM.TypeMetadataPtrTy); + emitInvariantLoadFromMetadataAtIndex(IGF, metatype, 1, + IGF.IGM.TypeMetadataPtrTy); IGF.Builder.CreateBr(contBB); // Continuation block. @@ -4300,8 +4445,7 @@ llvm::Value *irgen::emitVirtualMethodValue(IRGenFunction &IGF, instanceTy = SILType::getPrimitiveObjectType(metaTy.getInstanceType()); if (IGF.IGM.isResilient(instanceTy.getClassOrBoundGenericClass(), - ResilienceScope::Component) || - IGF.IGM.Opts.ForceResilientSuperDispatch) { + ResilienceExpansion::Maximal)) { // The derived type that is making the super call is resilient, // for example we may be in an extension of a class outside of our // resilience domain. So, we need to load the superclass metadata @@ -4472,7 +4616,7 @@ namespace { llvm::Value *vwtable) { // Nominal types are always preserved through SIL lowering. auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType(); - IGM.getTypeInfoForLowered(CanType(Target->getDeclaredTypeInContext())) + IGM.getTypeInfoForLowered(structTy) .initializeMetadata(IGF, metadata, vwtable, SILType::getPrimitiveAddressType(structTy)); } @@ -4484,7 +4628,7 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) { // TODO: structs nested within generic types llvm::Constant *init; bool isPattern; - if (hasMetadataPattern(IGM, structDecl)) { + if (IGM.hasMetadataPattern(structDecl)) { GenericStructMetadataBuilder builder(IGM, structDecl); builder.layout(); init = builder.getInit(); @@ -4562,7 +4706,16 @@ class EnumMetadataBuilder } void addPayloadSize() { - llvm_unreachable("nongeneric enums shouldn't need payload size in metadata"); + auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType(); + auto &enumTI = IGM.getTypeInfoForLowered(enumTy); + (void) enumTI; + assert(enumTI.isFixedSize(ResilienceExpansion::Maximal) && + "emitting constant enum metadata for resilient-sized type?"); + assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) && + "non-generic, non-resilient enums don't need payload size in metadata"); + + auto &strategy = getEnumImplStrategy(IGM, enumTy); + addConstantWord(strategy.getPayloadSizeForMetadata()); } }; @@ -4598,6 +4751,11 @@ class GenericEnumMetadataBuilder void addPayloadSize() { // In all cases where a payload size is demanded in the metadata, it's // runtime-dependent, so fill in a zero here. + auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType(); + auto &enumTI = IGM.getTypeInfoForLowered(enumTy); + (void) enumTI; + assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) && + "non-generic, non-resilient enums don't need payload size in metadata"); addConstantWord(0); } @@ -4606,7 +4764,7 @@ class GenericEnumMetadataBuilder llvm::Value *vwtable) { // Nominal types are always preserved through SIL lowering. auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType(); - IGM.getTypeInfoForLowered(CanType(Target->getDeclaredTypeInContext())) + IGM.getTypeInfoForLowered(enumTy) .initializeMetadata(IGF, metadata, vwtable, SILType::getPrimitiveAddressType(enumTy)); } @@ -4619,7 +4777,7 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) { llvm::Constant *init; bool isPattern; - if (hasMetadataPattern(IGM, theEnum)) { + if (IGM.hasMetadataPattern(theEnum)) { GenericEnumMetadataBuilder builder(IGM, theEnum); builder.layout(); init = builder.getInit(); diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h index 8a54726b7798f..3654c119dd7ce 100644 --- a/lib/IRGen/GenMeta.h +++ b/lib/IRGen/GenMeta.h @@ -1,8 +1,8 @@ -//===--- GenMeta.h - Swift IR generation for metadata ----------*- C++ -*-===// +//===--- GenMeta.h - Swift IR generation for metadata -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,6 +23,8 @@ namespace llvm { template class ArrayRef; class Constant; + class Function; + class GlobalVariable; class Value; } @@ -44,6 +46,7 @@ namespace irgen { class IRGenModule; class Size; class StructLayout; + struct ClassLayout; /// Is the given class known to have Swift-compatible metadata? bool hasKnownSwiftMetadata(IRGenModule &IGM, ClassDecl *theClass); @@ -76,7 +79,7 @@ namespace irgen { /// Emit a reference to a compile-time constant piece of type metadata, or /// return a null pointer if the type's metadata cannot be represented by a /// constant. - llvm::Constant *tryEmitConstantHeapMetadataRef(IRGenModule &IGM, + llvm::Constant *tryEmitConstantTypeMetadataRef(IRGenModule &IGM, CanType type); enum class MetadataValueType { ObjCClass, TypeMetadata }; @@ -103,7 +106,8 @@ namespace irgen { /// Emit the metadata associated with the given class declaration. void emitClassMetadata(IRGenModule &IGM, ClassDecl *theClass, - const StructLayout &layout); + const StructLayout &layout, + const ClassLayout &fieldLayout); /// Emit the constant initializer of the type metadata candidate for /// the given foreign class declaration. @@ -267,17 +271,22 @@ namespace irgen { /// There is no unique accessor function for the given type metadata, but /// one should be made automatically. - NonUniqueAccessor, - - /// The given type metadata should be accessed directly. - Direct, + NonUniqueAccessor }; + /// Is it basically trivial to access the given metadata? If so, we don't + /// need a cache variable in its accessor. + bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type); + /// Determine how the given type metadata should be accessed. MetadataAccessStrategy getTypeMetadataAccessStrategy(IRGenModule &IGM, - CanType type, - bool preferDirectAccess); + CanType type); + /// Return the address of a function that will return type metadata + /// for the given non-dependent type. + llvm::Function *getOrCreateTypeMetadataAccessFunction(IRGenModule &IGM, + CanType type); + /// Get the runtime identifier for a special protocol, if any. SpecialProtocol getSpecialProtocolID(ProtocolDecl *P); diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index 93c41ed83dd8f..478a30373f3db 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -292,12 +292,13 @@ llvm::Constant *IRGenModule::getAddrOfObjCMethodName(StringRef selector) { // If not, create it. This implicitly adds a trailing null. auto init = llvm::ConstantDataArray::getString(LLVMContext, selector); - auto global = new llvm::GlobalVariable(Module, init->getType(), true, - llvm::GlobalValue::InternalLinkage, + auto global = new llvm::GlobalVariable(Module, init->getType(), false, + llvm::GlobalValue::PrivateLinkage, init, llvm::Twine("\01L_selector_data(") + selector + ")"); global->setSection("__TEXT,__objc_methname,cstring_literals"); global->setAlignment(1); + addCompilerUsedGlobal(global); // Drill down to make an i8*. auto zero = llvm::ConstantInt::get(SizeTy, 0); @@ -323,16 +324,17 @@ llvm::Constant *IRGenModule::getAddrOfObjCSelectorRef(StringRef selector) { // choose something descriptive to make the IR readable. auto init = getAddrOfObjCMethodName(selector); auto global = new llvm::GlobalVariable(Module, init->getType(), false, - llvm::GlobalValue::InternalLinkage, + llvm::GlobalValue::PrivateLinkage, init, llvm::Twine("\01L_selector(") + selector + ")"); + global->setExternallyInitialized(true); global->setAlignment(getPointerAlignment().getValue()); // This section name is magical for the Darwin static and dynamic linkers. global->setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip"); // Make sure that this reference does not get optimized away. - addUsedGlobal(global); + addCompilerUsedGlobal(global); // Cache and return. entry = global; @@ -341,7 +343,7 @@ llvm::Constant *IRGenModule::getAddrOfObjCSelectorRef(StringRef selector) { /// Get or create an ObjC protocol record. Always returns an i8*. We lazily /// create ObjC protocol_t records for protocols, storing references to the -/// record into the __objc_protolist and and __objc_protorefs sections to be +/// record into the __objc_protolist and __objc_protorefs sections to be /// fixed up by the runtime. /// /// It is not correct to use this value as a Protocol* reference directly. The @@ -356,7 +358,7 @@ llvm::Constant *IRGenModule::getAddrOfObjCProtocolRecord(ProtocolDecl *proto, /// Get or create an ObjC protocol reference. Always returns an i8**. We lazily /// create ObjC protocol_t records for protocols, storing references to the -/// record into the __objc_protolist and and __objc_protorefs sections to be +/// record into the __objc_protolist and __objc_protorefs sections to be /// fixed up by the runtime. llvm::Constant *IRGenModule::getAddrOfObjCProtocolRef(ProtocolDecl *proto, ForDefinition_t forDefinition) { @@ -570,6 +572,7 @@ static void emitSuperArgument(IRGenFunction &IGF, bool isInstanceMethod, Address super = IGF.createAlloca(IGF.IGM.ObjCSuperStructTy, IGF.IGM.getPointerAlignment(), "objc_super"); + // TODO: Track lifetime markers for function args. llvm::Value *self = IGF.Builder.CreateBitCast(selfValue, IGF.IGM.ObjCPtrTy); @@ -1098,7 +1101,7 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, } // Parameter types. - // TODO. Encode type qualifer, 'in', 'inout', etc. for the parameter. + // TODO. Encode type qualifier, 'in', 'inout', etc. for the parameter. std::string paramsString; for (auto param : params) { auto clangType = IGM.getClangType(param.getType()); @@ -1106,7 +1109,7 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); // TODO. Some stuff related to Array and Function type is missing. - // TODO. Encode type qualifer, 'in', 'inout', etc. for the parameter. + // TODO. Encode type qualifier, 'in', 'inout', etc. for the parameter. HelperGetObjCEncodingForType(clangASTContext, clangType, paramsString, useExtendedEncoding); paramsString += llvm::itostr(parmOffset); diff --git a/lib/IRGen/GenObjC.h b/lib/IRGen/GenObjC.h index fbcbda6f16be3..db048cc52f538 100644 --- a/lib/IRGen/GenObjC.h +++ b/lib/IRGen/GenObjC.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index f467fbc9cdeae..da324e56df5d0 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -159,7 +159,7 @@ static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) { ->getPointerTo(); } - /// unsigned (*getEnumTag)(T *obj, M *self); + /// int (*getEnumTag)(T *obj, M *self); case ValueWitness::GetEnumTag: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; @@ -183,7 +183,7 @@ static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) { ->getPointerTo(); } - /// void (*destructiveInjectEnumTag)(T *obj, unsigned tag, M *self); + /// void (*destructiveInjectEnumTag)(T *obj, int tag, M *self); case ValueWitness::DestructiveInjectEnumTag: { llvm::Type *voidTy = IGM.VoidTy; llvm::Type *ptrTy = IGM.OpaquePtrTy; @@ -320,25 +320,26 @@ static llvm::Value *emitLoadOfValueWitnessFromMetadata(IRGenFunction &IGF, llvm::Value *IRGenFunction::emitValueWitness(CanType type, ValueWitness index) { if (auto witness = - tryGetLocalTypeData(type, LocalTypeData::forValueWitness(index))) + tryGetLocalTypeData(type, LocalTypeDataKind::forValueWitness(index))) return witness; auto vwtable = emitValueWitnessTableRef(type); auto witness = emitLoadOfValueWitness(*this, vwtable, index); - setScopedLocalTypeData(type, LocalTypeData::forValueWitness(index), witness); + setScopedLocalTypeData(type, LocalTypeDataKind::forValueWitness(index), + witness); return witness; } llvm::Value *IRGenFunction::emitValueWitnessForLayout(SILType type, ValueWitness index) { if (auto witness = tryGetLocalTypeDataForLayout(type, - LocalTypeData::forValueWitness(index))) + LocalTypeDataKind::forValueWitness(index))) return witness; auto vwtable = emitValueWitnessTableRefForLayout(type); auto witness = emitLoadOfValueWitness(*this, vwtable, index); setScopedLocalTypeDataForLayout(type, - LocalTypeData::forValueWitness(index), witness); + LocalTypeDataKind::forValueWitness(index), witness); return witness; } @@ -380,15 +381,29 @@ llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::InitializeBufferWithCopyOfBuffer); llvm::CallInst *call = - IGF.Builder.CreateCall( - copyFn, - {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); + IGF.Builder.CreateCall(copyFn, + {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributesForAggResult(call, false); return call; } +llvm::Value *irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, + SILType T, + Address destBuffer, + Address srcBuffer) { + auto metadata = IGF.emitTypeMetadataRefForLayout(T); + llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, + ValueWitness::InitializeBufferWithTakeOfBuffer); + llvm::CallInst *call = + IGF.Builder.CreateCall(copyFn, + {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); + call->setCallingConv(IGF.IGM.RuntimeCC); + call->setDoesNotThrow(); + return call; +} + /// Emit a call to do an 'initializeBufferWithTakeOfBuffer' operation. llvm::Value *irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, llvm::Value *metadata, @@ -397,15 +412,29 @@ llvm::Value *irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::InitializeBufferWithTakeOfBuffer); llvm::CallInst *call = - IGF.Builder.CreateCall( - copyFn, - {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); + IGF.Builder.CreateCall(copyFn, + {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributesForAggResult(call, false); return call; } +llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, + SILType T, + Address destBuffer, + Address srcBuffer) { + auto metadata = IGF.emitTypeMetadataRefForLayout(T); + llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, + ValueWitness::InitializeBufferWithCopyOfBuffer); + llvm::CallInst *call = + IGF.Builder.CreateCall(copyFn, + {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); + call->setCallingConv(IGF.IGM.RuntimeCC); + call->setDoesNotThrow(); + return call; +} + /// Emit a call to do an 'allocateBuffer' operation. llvm::Value *irgen::emitAllocateBufferCall(IRGenFunction &IGF, SILType T, @@ -420,6 +449,20 @@ llvm::Value *irgen::emitAllocateBufferCall(IRGenFunction &IGF, return result; } +/// Emit a call to do a 'projectBuffer' operation. +llvm::Value *irgen::emitProjectBufferCall(IRGenFunction &IGF, + SILType T, + Address buffer) { + llvm::Value *metadata = IGF.emitTypeMetadataRefForLayout(T); + llvm::Value *fn + = IGF.emitValueWitnessForLayout(T, ValueWitness::ProjectBuffer); + llvm::CallInst *result = + IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); + result->setCallingConv(IGF.IGM.RuntimeCC); + result->setDoesNotThrow(); + return result; +} + /// Emit a call to do a 'projectBuffer' operation. llvm::Value *irgen::emitProjectBufferCall(IRGenFunction &IGF, llvm::Value *metadata, @@ -436,26 +479,28 @@ llvm::Value *irgen::emitProjectBufferCall(IRGenFunction &IGF, /// Emit a call to do an 'initializeWithCopy' operation. void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeWithCopy); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } llvm::Value *irgen::emitInitializeBufferWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithTake); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); return call; @@ -463,13 +508,14 @@ llvm::Value *irgen::emitInitializeBufferWithTakeCall(IRGenFunction &IGF, llvm::Value *irgen::emitInitializeBufferWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithCopy); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); return call; @@ -478,15 +524,16 @@ llvm::Value *irgen::emitInitializeBufferWithCopyCall(IRGenFunction &IGF, /// Emit a call to do an 'initializeArrayWithCopy' operation. void irgen::emitInitializeArrayWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithCopy); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, count, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -494,13 +541,14 @@ void irgen::emitInitializeArrayWithCopyCall(IRGenFunction &IGF, /// Emit a call to do an 'initializeWithTake' operation. void irgen::emitInitializeWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeWithTake); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -508,14 +556,15 @@ void irgen::emitInitializeWithTakeCall(IRGenFunction &IGF, /// Emit a call to do an 'initializeArrayWithTakeFrontToBack' operation. void irgen::emitInitializeArrayWithTakeFrontToBackCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithTakeFrontToBack); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, count, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -523,14 +572,15 @@ void irgen::emitInitializeArrayWithTakeFrontToBackCall(IRGenFunction &IGF, /// Emit a call to do an 'initializeArrayWithTakeBackToFront' operation. void irgen::emitInitializeArrayWithTakeBackToFrontCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithTakeBackToFront); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, count, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -538,24 +588,26 @@ void irgen::emitInitializeArrayWithTakeBackToFrontCall(IRGenFunction &IGF, /// Emit a call to do an 'assignWithCopy' operation. void irgen::emitAssignWithCopyCall(IRGenFunction &IGF, llvm::Value *metadata, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::AssignWithCopy); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } void irgen::emitAssignWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::AssignWithCopy); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -563,13 +615,14 @@ void irgen::emitAssignWithCopyCall(IRGenFunction &IGF, /// Emit a call to do an 'assignWithTake' operation. void irgen::emitAssignWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject) { + Address destObject, + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::AssignWithTake); llvm::CallInst *call = - IGF.Builder.CreateCall(copyFn, {destObject, srcObject, metadata}); + IGF.Builder.CreateCall(copyFn, + {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotThrow(); } @@ -577,11 +630,12 @@ void irgen::emitAssignWithTakeCall(IRGenFunction &IGF, /// Emit a call to do a 'destroy' operation. void irgen::emitDestroyCall(IRGenFunction &IGF, SILType T, - llvm::Value *object) { + Address object) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::Destroy); - llvm::CallInst *call = IGF.Builder.CreateCall(fn, {object, metadata}); + llvm::CallInst *call = + IGF.Builder.CreateCall(fn, {object.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); } @@ -589,17 +643,29 @@ void irgen::emitDestroyCall(IRGenFunction &IGF, /// Emit a call to do a 'destroyArray' operation. void irgen::emitDestroyArrayCall(IRGenFunction &IGF, SILType T, - llvm::Value *object, + Address object, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestroyArray); - llvm::CallInst *call = IGF.Builder.CreateCall(fn, {object, count, metadata}); + llvm::CallInst *call = + IGF.Builder.CreateCall(fn, {object.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); } /// Emit a call to do a 'destroyBuffer' operation. +void irgen::emitDestroyBufferCall(IRGenFunction &IGF, + SILType T, + Address buffer) { + auto metadata = IGF.emitTypeMetadataRefForLayout(T); + llvm::Value *fn = IGF.emitValueWitnessForLayout(T, + ValueWitness::DestroyBuffer); + llvm::CallInst *call = + IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); + call->setCallingConv(IGF.IGM.RuntimeCC); + setHelperAttributes(call); +} void irgen::emitDestroyBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address buffer) { @@ -638,13 +704,13 @@ void irgen::emitDeallocateBufferCall(IRGenFunction &IGF, /// The type must be dynamically known to have extra inhabitant witnesses. llvm::Value *irgen::emitGetExtraInhabitantIndexCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject) { + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::GetExtraInhabitantIndex); llvm::CallInst *call = - IGF.Builder.CreateCall(fn, {srcObject, metadata}); + IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); return call; @@ -655,12 +721,12 @@ llvm::Value *irgen::emitGetExtraInhabitantIndexCall(IRGenFunction &IGF, llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF, SILType T, llvm::Value *index, - llvm::Value *destObject) { + Address destObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::StoreExtraInhabitant); llvm::CallInst *call = - IGF.Builder.CreateCall(fn, {destObject, index, metadata}); + IGF.Builder.CreateCall(fn, {destObject.getAddress(), index, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); return call; @@ -669,12 +735,12 @@ llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF, /// Emit a call to the 'getEnumTag' operation. llvm::Value *irgen::emitGetEnumTagCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject) { + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::GetEnumTag); llvm::CallInst *call = - IGF.Builder.CreateCall(fn, {srcObject, metadata}); + IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); return call; @@ -684,12 +750,12 @@ llvm::Value *irgen::emitGetEnumTagCall(IRGenFunction &IGF, /// The type must be dynamically known to have enum witnesses. void irgen::emitDestructiveProjectEnumDataCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject) { + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestructiveProjectEnumData); llvm::CallInst *call = - IGF.Builder.CreateCall(fn, {srcObject, metadata}); + IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); } @@ -699,14 +765,14 @@ void irgen::emitDestructiveProjectEnumDataCall(IRGenFunction &IGF, void irgen::emitDestructiveInjectEnumTagCall(IRGenFunction &IGF, SILType T, unsigned tag, - llvm::Value *srcObject) { + Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestructiveInjectEnumTag); llvm::Value *tagValue = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tag); llvm::CallInst *call = - IGF.Builder.CreateCall(fn, {srcObject, tagValue, metadata}); + IGF.Builder.CreateCall(fn, {srcObject.getAddress(), tagValue, metadata}); call->setCallingConv(IGF.IGM.RuntimeCC); setHelperAttributes(call); } diff --git a/lib/IRGen/GenOpaque.h b/lib/IRGen/GenOpaque.h index 7d227037957db..24a9f22fd6160 100644 --- a/lib/IRGen/GenOpaque.h +++ b/lib/IRGen/GenOpaque.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -52,12 +52,24 @@ namespace irgen { Address destBuffer, Address srcBuffer); + /// Emit a call to do an 'initializeBufferWithCopyOfBuffer' operation. + llvm::Value *emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, + SILType T, + Address destBuffer, + Address srcBuffer); + /// Emit a call to do an 'initializeBufferWithTakeOfBuffer' operation. llvm::Value *emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address destBuffer, Address srcBuffer); + /// Emit a call to do an 'initializeBufferWithTakeOfBuffer' operation. + llvm::Value *emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, + SILType T, + Address destBuffer, + Address srcBuffer); + /// Emit a call to do an 'allocateBuffer' operation. llvm::Value *emitAllocateBufferCall(IRGenFunction &IGF, SILType T, @@ -68,121 +80,130 @@ namespace irgen { llvm::Value *metadata, Address buffer); + /// Emit a call to do a 'projectBuffer' operation. + llvm::Value *emitProjectBufferCall(IRGenFunction &IGF, + SILType T, + Address buffer); + /// Emit a call to do an 'initializeWithCopy' operation. void emitInitializeWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destObject, + Address srcObject); + /// Emit a call to do an 'initializeBufferWithCopy' operation. llvm::Value *emitInitializeBufferWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destBuffer, + Address srcObject); /// Emit a call to do an 'initializeBufferWithTake' operation. llvm::Value *emitInitializeBufferWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destBuffer, + Address srcObject); /// Emit a call to do an 'initializeArrayWithCopy' operation. void emitInitializeArrayWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count); /// Emit a call to do an 'initializeWithTake' operation. void emitInitializeWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destObject, + Address srcObject); /// Emit a call to do an 'initializeArrayWithTakeFrontToBack' operation. void emitInitializeArrayWithTakeFrontToBackCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count); /// Emit a call to do an 'initializeArrayWithTakeBackToFront' operation. void emitInitializeArrayWithTakeBackToFrontCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject, + Address destObject, + Address srcObject, llvm::Value *count); /// Emit a call to do an 'assignWithCopy' operation. void emitAssignWithCopyCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destObject, + Address srcObject); void emitAssignWithCopyCall(IRGenFunction &IGF, llvm::Value *metadata, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destObject, + Address srcObject); /// Emit a call to do an 'assignWithTake' operation. void emitAssignWithTakeCall(IRGenFunction &IGF, SILType T, - llvm::Value *destObject, - llvm::Value *srcObject); + Address destObject, + Address srcObject); /// Emit a call to do a 'destroy' operation. void emitDestroyCall(IRGenFunction &IGF, SILType T, - llvm::Value *object); + Address object); /// Emit a call to do a 'destroyArray' operation. void emitDestroyArrayCall(IRGenFunction &IGF, SILType T, - llvm::Value *object, + Address object, llvm::Value *count); /// Emit a call to do a 'destroyBuffer' operation. void emitDestroyBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address buffer); + void emitDestroyBufferCall(IRGenFunction &IGF, + SILType T, + Address buffer); /// Emit a call to do a 'deallocateBuffer' operation. void emitDeallocateBufferCall(IRGenFunction &IGF, - SILType T, + llvm::Value *metadata, Address buffer); void emitDeallocateBufferCall(IRGenFunction &IGF, - llvm::Value *metadata, + SILType T, Address buffer); /// Emit a call to the 'getExtraInhabitantIndex' operation. /// The type must be dynamically known to have extra inhabitant witnesses. llvm::Value *emitGetExtraInhabitantIndexCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject); + Address srcObject); /// Emit a call to the 'storeExtraInhabitant' operation. /// The type must be dynamically known to have extra inhabitant witnesses. llvm::Value *emitStoreExtraInhabitantCall(IRGenFunction &IGF, SILType T, llvm::Value *index, - llvm::Value *destObject); + Address destObject); /// Emit a call to the 'getEnumTag' operation. llvm::Value *emitGetEnumTagCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject); + Address srcObject); /// Emit a call to the 'destructiveProjectEnumData' operation. /// The type must be dynamically known to have enum witnesses. void emitDestructiveProjectEnumDataCall(IRGenFunction &IGF, SILType T, - llvm::Value *srcObject); + Address srcObject); /// Emit a call to the 'destructiveInjectEnumTag' operation. /// The type must be dynamically known to have enum witnesses. void emitDestructiveInjectEnumTagCall(IRGenFunction &IGF, SILType T, unsigned tag, - llvm::Value *srcObject); + Address srcObject); /// Emit a load of the 'size' value witness. llvm::Value *emitLoadOfSize(IRGenFunction &IGF, SILType T); diff --git a/lib/IRGen/GenPoly.cpp b/lib/IRGen/GenPoly.cpp index 00c314d4830c9..52764f3184572 100644 --- a/lib/IRGen/GenPoly.cpp +++ b/lib/IRGen/GenPoly.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenPoly.h b/lib/IRGen/GenPoly.h index b32625f61e4ec..4c28d72ac3d8f 100644 --- a/lib/IRGen/GenPoly.h +++ b/lib/IRGen/GenPoly.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index b8455392738e4..e0ed7dcf6b4e6 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -72,6 +72,43 @@ using namespace swift; using namespace irgen; +static bool shouldSetName(IRGenModule &IGM, llvm::Value *value, CanType type) { + // If value names are globally disabled, honor that. + if (!IGM.EnableValueNames) return false; + + // Suppress value names for values with opened existentials. + if (type->hasOpenedExistential()) return false; + + // If the value already has a name, honor that. + if (value->hasName()) return false; + + // Only do this for local values. + return (isa(value) || isa(value)); +} + +void irgen::setTypeMetadataName(IRGenModule &IGM, llvm::Value *metadata, + CanType type) { + if (!shouldSetName(IGM, metadata, type)) return; + + SmallString<128> name; { + llvm::raw_svector_ostream out(name); + type.print(out); + } + metadata->setName(type->getString()); +} + +void irgen::setProtocolWitnessTableName(IRGenModule &IGM, llvm::Value *wtable, + CanType type, + ProtocolDecl *requirement) { + if (!shouldSetName(IGM, wtable, type)) return; + + SmallString<128> name; { + llvm::raw_svector_ostream out(name); + type.print(out); + out << '.' << requirement->getNameStr(); + } + wtable->setName(name); +} namespace { /// A concrete witness table, together with its known layout. @@ -273,7 +310,7 @@ namespace { /// tables to be dependently-generated? static bool isDependentConformance(IRGenModule &IGM, const NormalProtocolConformance *conformance, - ResilienceScope resilienceScope) { + ResilienceExpansion expansion) { // If the conforming type isn't dependent, this is never true. if (!conformance->getDeclContext()->isGenericContext()) return false; @@ -291,7 +328,7 @@ static bool isDependentConformance(IRGenModule &IGM, // Check whether any of the associated types are dependent. for (auto &entry : conformance->getInheritedConformances()) { if (isDependentConformance(IGM, entry.second->getRootNormalConformance(), - resilienceScope)) { + expansion)) { return true; } } @@ -305,7 +342,8 @@ class irgen::ConformanceInfo { public: virtual ~ConformanceInfo() {} virtual llvm::Value *getTable(IRGenFunction &IGF, - CanType conformingType) const = 0; + CanType conformingType, + llvm::Value **conformingMetadataCache) const = 0; /// Try to get this table as a constant pointer. This might just /// not be supportable at all. virtual llvm::Constant *tryGetConstantTable(IRGenModule &IGM, @@ -315,16 +353,20 @@ class irgen::ConformanceInfo { static llvm::Value * emitWitnessTableAccessorCall(IRGenFunction &IGF, const NormalProtocolConformance *conformance, - CanType conformingType) { + CanType conformingType, + llvm::Value **srcMetadataCache) { auto accessor = IGF.IGM.getAddrOfWitnessTableAccessFunction(conformance, NotForDefinition); - // If the conforming type is generic, the accessor takes the metatype + // If the conformance is generic, the accessor takes the metatype // as an argument. llvm::CallInst *call; if (conformance->getDeclContext()->isGenericContext()) { - auto metadata = IGF.emitTypeMetadataRef(conformingType); - call = IGF.Builder.CreateCall(accessor, {metadata}); + // Emit the source metadata if we haven't yet. + if (!*srcMetadataCache) { + *srcMetadataCache = IGF.emitTypeMetadataRef(conformingType); + } + call = IGF.Builder.CreateCall(accessor, {*srcMetadataCache}); } else { call = IGF.Builder.CreateCall(accessor, {}); } @@ -358,7 +400,9 @@ getWitnessTableLazyAccessFunction(IRGenModule &IGM, ForDefinition)); emitLazyCacheAccessFunction(IGM, accessor, cacheVariable, [&](IRGenFunction &IGF) -> llvm::Value* { - return emitWitnessTableAccessorCall(IGF, conformance, conformingType); + llvm::Value *conformingMetadataCache = nullptr; + return emitWitnessTableAccessorCall(IGF, conformance, conformingType, + &conformingMetadataCache); }); return accessor; @@ -375,8 +419,8 @@ class DirectConformanceInfo : public ConformanceInfo { DirectConformanceInfo(const NormalProtocolConformance *C) : RootConformance(C) {} - llvm::Value *getTable(IRGenFunction &IGF, - CanType conformingType) const override { + llvm::Value *getTable(IRGenFunction &IGF, CanType conformingType, + llvm::Value **conformingMetadataCache) const override { return IGF.IGM.getAddrOfWitnessTable(RootConformance); } @@ -395,12 +439,14 @@ class AccessorConformanceInfo : public ConformanceInfo { AccessorConformanceInfo(const NormalProtocolConformance *C) : Conformance(C) {} - llvm::Value *getTable(IRGenFunction &IGF, CanType type) const override { + llvm::Value *getTable(IRGenFunction &IGF, CanType type, + llvm::Value **typeMetadataCache) const override { // If the conformance isn't generic, or we're looking up a dependent // type, we don't want to / can't cache the result. if (!Conformance->getDeclContext()->isGenericContext() || type->hasArchetype()) { - return emitWitnessTableAccessorCall(IGF, Conformance, type); + return emitWitnessTableAccessorCall(IGF, Conformance, type, + typeMetadataCache); } // Otherwise, call a lazy-cache function. @@ -432,7 +478,7 @@ static bool isNeverAllocated(FixedPacking packing) { } namespace { - /// An operation to be peformed for various kinds of packing. + /// An operation to be performed for various kinds of packing. struct DynamicPackingOperation { virtual ~DynamicPackingOperation() = default; @@ -447,9 +493,7 @@ namespace { /// Given that we are currently at the beginning of the /// continuation block, complete the operation. - virtual void complete(IRGenFunction &IGF, - SILType T, - const TypeInfo &type) = 0; + virtual void complete(IRGenFunction &IGF) = 0; }; /// A class for merging a particular kind of value across control flow. @@ -459,14 +503,13 @@ namespace { template <> class DynamicPackingPHIMapping { llvm::PHINode *PHI = nullptr; public: - void collect(IRGenFunction &IGF, SILType T, - const TypeInfo &type, llvm::Value *value) { + void collect(IRGenFunction &IGF, llvm::Value *value) { // Add the result to the phi, creating it (unparented) if necessary. if (!PHI) PHI = llvm::PHINode::Create(value->getType(), 2, "dynamic-packing.result"); PHI->addIncoming(value, IGF.Builder.GetInsertBlock()); } - void complete(IRGenFunction &IGF, SILType T, const TypeInfo &type) { + void complete(IRGenFunction &IGF) { assert(PHI); IGF.Builder.Insert(PHI); } @@ -481,13 +524,11 @@ namespace { : private DynamicPackingPHIMapping { typedef DynamicPackingPHIMapping super; public: - void collect(IRGenFunction &IGF, SILType T, - const TypeInfo &type, Address value) { - super::collect(IGF, T, type, value.getAddress()); + void collect(IRGenFunction &IGF, Address value) { + super::collect(IGF, value.getAddress()); } - void complete(IRGenFunction &IGF, SILType T, - const TypeInfo &type) { - super::complete(IGF, T, type); + void complete(IRGenFunction &IGF) { + super::complete(IGF); } Address get(IRGenFunction &IGF, SILType T, const TypeInfo &type) { return type.getAddressForPointer(super::get(IGF, T, type)); @@ -503,12 +544,11 @@ namespace { explicit LambdaDynamicPackingOperation(FnTy &&fn) : Fn(fn) {} void emitForPacking(IRGenFunction &IGF, SILType T, const TypeInfo &type, FixedPacking packing) override { - Mapping.collect(IGF, T, type, Fn(IGF, T, type, packing)); + Mapping.collect(IGF, Fn(IGF, T, type, packing)); } - void complete(IRGenFunction &IGF, SILType T, - const TypeInfo &type) override { - Mapping.complete(IGF, T, type); + void complete(IRGenFunction &IGF) override { + Mapping.complete(IGF); } ResultTy get(IRGenFunction &IGF, SILType T, const TypeInfo &type) { @@ -528,8 +568,7 @@ namespace { FixedPacking packing) override { Fn(IGF, T, type, packing); } - void complete(IRGenFunction &IGF, SILType T, - const TypeInfo &type) override {} + void complete(IRGenFunction &IGF) override {} void get(IRGenFunction &IGF, SILType T, const TypeInfo &type) {} }; } @@ -550,18 +589,22 @@ static void emitDynamicPackingOperation(IRGenFunction &IGF, IGF.Builder.CreateCondBr(isInline, directBB, indirectBB); // Emit the indirect path. - IGF.Builder.emitBlock(indirectBB); - operation.emitForPacking(IGF, T, type, FixedPacking::Allocate); - IGF.Builder.CreateBr(contBB); + IGF.Builder.emitBlock(indirectBB); { + ConditionalDominanceScope condition(IGF); + operation.emitForPacking(IGF, T, type, FixedPacking::Allocate); + IGF.Builder.CreateBr(contBB); + } // Emit the direct path. - IGF.Builder.emitBlock(directBB); - operation.emitForPacking(IGF, T, type, FixedPacking::OffsetZero); - IGF.Builder.CreateBr(contBB); + IGF.Builder.emitBlock(directBB); { + ConditionalDominanceScope condition(IGF); + operation.emitForPacking(IGF, T, type, FixedPacking::OffsetZero); + IGF.Builder.CreateBr(contBB); + } // Enter the continuation block and add the PHI if required. IGF.Builder.emitBlock(contBB); - operation.complete(IGF, T, type); + operation.complete(IGF); } /// A helper function for creating a lambda-based DynamicPackingOperation. @@ -572,31 +615,25 @@ makeLambdaDynamicPackingOperation(FnTy &&fn) { } /// Perform an operation on a type that requires dynamic packing. -template +template static ResultTy emitForDynamicPacking(IRGenFunction &IGF, - ResultTy (*fn)(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - ArgTys... args), + ResultTy (*fn)(ParamTys...), SILType T, const TypeInfo &type, - // using enable_if to block template argument deduction - typename std::enable_if::type... args) { + ArgTys... args) { auto operation = makeLambdaDynamicPackingOperation( - [&](IRGenFunction &IGF, SILType T, const TypeInfo &type, FixedPacking packing) { - return fn(IGF, T, type, packing, args...); + [&](IRGenFunction &IGF, SILType T, const TypeInfo &type, + FixedPacking packing) { + return fn(IGF, args..., T, type, packing); }); emitDynamicPackingOperation(IGF, T, type, operation); return operation.get(IGF, T, type); } /// Emit a 'projectBuffer' operation. Always returns a T*. -static Address emitProjectBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address buffer) { +static Address emitDefaultProjectBuffer(IRGenFunction &IGF, Address buffer, + SILType T, const TypeInfo &type, + FixedPacking packing) { llvm::PointerType *resultTy = type.getStorageType()->getPointerTo(); switch (packing) { case FixedPacking::Allocate: { @@ -611,28 +648,18 @@ static Address emitProjectBuffer(IRGenFunction &IGF, } case FixedPacking::Dynamic: - return emitForDynamicPacking(IGF, &emitProjectBuffer, T, type, buffer); + return emitForDynamicPacking(IGF, &emitDefaultProjectBuffer, + T, type, buffer); } llvm_unreachable("bad packing!"); } -namespace swift { namespace irgen { using ::emitProjectBuffer; } } - -/// Project to the address of a value in a value buffer. -Address irgen::emitProjectBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer) { - const TypeInfo &valueTI = IGF.getTypeInfo(valueType); - FixedPacking packing = valueTI.getFixedPacking(IGF.IGM); - return ::emitProjectBuffer(IGF, valueType, valueTI, packing, buffer); -} /// Emit an 'allocateBuffer' operation. Always returns a T*. -static Address emitAllocateBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address buffer) { +static Address emitDefaultAllocateBuffer(IRGenFunction &IGF, Address buffer, + SILType T, const TypeInfo &type, + FixedPacking packing) { switch (packing) { case FixedPacking::Allocate: { auto sizeAndAlign = type.getSizeAndAlignmentMask(IGF, T); @@ -647,29 +674,21 @@ static Address emitAllocateBuffer(IRGenFunction &IGF, } case FixedPacking::OffsetZero: - return emitProjectBuffer(IGF, T, type, packing, buffer); + return emitDefaultProjectBuffer(IGF, buffer, T, type, packing); case FixedPacking::Dynamic: - return emitForDynamicPacking(IGF, &emitAllocateBuffer, T, type, buffer); + return emitForDynamicPacking(IGF, &emitDefaultAllocateBuffer, + T, type, buffer); } llvm_unreachable("bad packing!"); } -namespace swift { namespace irgen { using ::emitAllocateBuffer; } } - -/// Allocate space for a value in a value buffer. -Address irgen::emitAllocateBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer) { - const TypeInfo &valueTI = IGF.getTypeInfo(valueType); - FixedPacking packing = valueTI.getFixedPacking(IGF.IGM); - return emitAllocateBuffer(IGF, valueType, valueTI, packing, buffer); -} /// Emit a 'deallocateBuffer' operation. -static void emitDeallocateBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address buffer) { +static void emitDefaultDeallocateBuffer(IRGenFunction &IGF, + Address buffer, + SILType T, + const TypeInfo &type, + FixedPacking packing) { switch (packing) { case FixedPacking::Allocate: { Address slot = @@ -685,132 +704,157 @@ static void emitDeallocateBuffer(IRGenFunction &IGF, return; case FixedPacking::Dynamic: - return emitForDynamicPacking(IGF, &emitDeallocateBuffer, T, type, buffer); + return emitForDynamicPacking(IGF, &emitDefaultDeallocateBuffer, + T, type, buffer); } llvm_unreachable("bad packing!"); } -namespace swift { namespace irgen { using ::emitDeallocateBuffer; } } - -/// Deallocate space for a value in a value buffer. -void irgen::emitDeallocateBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer) { - const TypeInfo &valueTI = IGF.getTypeInfo(valueType); - FixedPacking packing = valueTI.getFixedPacking(IGF.IGM); - emitDeallocateBuffer(IGF, valueType, valueTI, packing, buffer); -} /// Emit a 'destroyBuffer' operation. -static void emitDestroyBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address buffer) { +static void emitDefaultDestroyBuffer(IRGenFunction &IGF, Address buffer, + SILType T, const TypeInfo &type, + FixedPacking packing) { // Special-case dynamic packing in order to thread the jumps. if (packing == FixedPacking::Dynamic) - return emitForDynamicPacking(IGF, &emitDestroyBuffer, T, type, buffer); + return emitForDynamicPacking(IGF, &emitDefaultDestroyBuffer, + T, type, buffer); - Address object = emitProjectBuffer(IGF, T, type, packing, buffer); + Address object = emitDefaultProjectBuffer(IGF, buffer, T, type, packing); type.destroy(IGF, object, T); - emitDeallocateBuffer(IGF, T, type, packing, buffer); -} - -/// Emit an 'initializeWithCopy' operation. -static void emitInitializeWithCopy(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - Address dest, Address src) { - type.initializeWithCopy(IGF, dest, src, T); -} - -/// Emit an 'initializeWithTake' operation. -static void emitInitializeWithTake(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - Address dest, Address src) { - type.initializeWithTake(IGF, dest, src, T); + emitDefaultDeallocateBuffer(IGF, buffer, T, type, packing); } /// Emit an 'initializeBufferWithCopyOfBuffer' operation. /// Returns the address of the destination object. -static Address emitInitializeBufferWithCopyOfBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address dest, - Address src) { +static Address +emitDefaultInitializeBufferWithCopyOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType T, + const TypeInfo &type, + FixedPacking packing) { // Special-case dynamic packing in order to thread the jumps. if (packing == FixedPacking::Dynamic) - return emitForDynamicPacking(IGF, &emitInitializeBufferWithCopyOfBuffer, - T, type, dest, src); - - Address destObject = emitAllocateBuffer(IGF, T, type, packing, dest); - Address srcObject = emitProjectBuffer(IGF, T, type, packing, src); - emitInitializeWithCopy(IGF, T, type, destObject, srcObject); + return emitForDynamicPacking(IGF, + &emitDefaultInitializeBufferWithCopyOfBuffer, + T, type, destBuffer, srcBuffer); + + Address destObject = + emitDefaultAllocateBuffer(IGF, destBuffer, T, type, packing); + Address srcObject = + emitDefaultProjectBuffer(IGF, srcBuffer, T, type, packing); + type.initializeWithCopy(IGF, destObject, srcObject, T); return destObject; } /// Emit an 'initializeBufferWithTakeOfBuffer' operation. /// Returns the address of the destination object. -static Address emitInitializeBufferWithTakeOfBuffer(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address dest, - Address src) { +static Address +emitDefaultInitializeBufferWithTakeOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType T, + const TypeInfo &type, + FixedPacking packing) { switch (packing) { case FixedPacking::Dynamic: // Special-case dynamic packing in order to thread the jumps. - return emitForDynamicPacking(IGF, &emitInitializeBufferWithTakeOfBuffer, - T, type, dest, src); + return emitForDynamicPacking(IGF, + &emitDefaultInitializeBufferWithTakeOfBuffer, + T, type, destBuffer, srcBuffer); case FixedPacking::OffsetZero: { // Both of these allocations/projections should be no-ops. - Address destObject = emitAllocateBuffer(IGF, T, type, packing, dest); - Address srcObject = emitProjectBuffer(IGF, T, type, packing, src); - emitInitializeWithTake(IGF, T, type, destObject, srcObject); + Address destObject = + emitDefaultAllocateBuffer(IGF, destBuffer, T, type, packing); + Address srcObject = + emitDefaultProjectBuffer(IGF, srcBuffer, T, type, packing); + type.initializeWithTake(IGF, destObject, srcObject, T); return destObject; } case FixedPacking::Allocate: { // Just copy the out-of-line storage pointers. llvm::Type *ptrTy = type.getStorageType()->getPointerTo()->getPointerTo(); - src = IGF.Builder.CreateBitCast(src, ptrTy); - llvm::Value *addr = IGF.Builder.CreateLoad(src); - dest = IGF.Builder.CreateBitCast(dest, ptrTy); - IGF.Builder.CreateStore(addr, dest); + srcBuffer = IGF.Builder.CreateBitCast(srcBuffer, ptrTy); + llvm::Value *addr = IGF.Builder.CreateLoad(srcBuffer); + destBuffer = IGF.Builder.CreateBitCast(destBuffer, ptrTy); + IGF.Builder.CreateStore(addr, destBuffer); return type.getAddressForPointer(addr); } } llvm_unreachable("bad fixed packing"); } -/// Emit an 'initializeBufferWithCopy' operation. -/// Returns the address of the destination object. -static Address emitInitializeBufferWithCopy(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address dest, - Address srcObject) { - Address destObject = emitAllocateBuffer(IGF, T, type, packing, dest); - emitInitializeWithCopy(IGF, T, type, destObject, srcObject); +static Address emitDefaultInitializeBufferWithCopy(IRGenFunction &IGF, + Address destBuffer, + Address srcObject, + SILType T, + const TypeInfo &type, + FixedPacking packing) { + Address destObject = + emitDefaultAllocateBuffer(IGF, destBuffer, T, type, packing); + type.initializeWithCopy(IGF, destObject, srcObject, T); return destObject; } -/// Emit an 'initializeBufferWithTake' operation. -/// Returns the address of the destination object. -static Address emitInitializeBufferWithTake(IRGenFunction &IGF, - SILType T, - const TypeInfo &type, - FixedPacking packing, - Address dest, - Address srcObject) { - Address destObject = emitAllocateBuffer(IGF, T, type, packing, dest); - emitInitializeWithTake(IGF, T, type, destObject, srcObject); +static Address emitDefaultInitializeBufferWithTake(IRGenFunction &IGF, + Address destBuffer, + Address srcObject, + SILType T, + const TypeInfo &type, + FixedPacking packing) { + Address destObject = + emitDefaultAllocateBuffer(IGF, destBuffer, T, type, packing); + type.initializeWithTake(IGF, destObject, srcObject, T); return destObject; } +// Metaprogram some of the common boilerplate here: +// - the default implementation in TypeInfo +// - the value-witness emitter which tries to avoid some dynamic +// dispatch and the recomputation of the fixed packing + +#define DEFINE_BINARY_BUFFER_OP(LOWER, TITLE) \ +Address TypeInfo::LOWER(IRGenFunction &IGF, Address dest, Address src, \ + SILType T) const { \ + return emitDefault##TITLE(IGF, dest, src, T, *this, \ + getFixedPacking(IGF.IGM)); \ +} \ +static Address emit##TITLE(IRGenFunction &IGF, Address dest, Address src, \ + SILType T, const TypeInfo &type, \ + FixedPacking packing) { \ + if (packing == FixedPacking::Dynamic) \ + return type.LOWER(IGF, dest, src, T); \ + return emitDefault##TITLE(IGF, dest, src, T, type, packing); \ +} +DEFINE_BINARY_BUFFER_OP(initializeBufferWithCopy, + InitializeBufferWithCopy) +DEFINE_BINARY_BUFFER_OP(initializeBufferWithTake, + InitializeBufferWithTake) +DEFINE_BINARY_BUFFER_OP(initializeBufferWithCopyOfBuffer, + InitializeBufferWithCopyOfBuffer) +DEFINE_BINARY_BUFFER_OP(initializeBufferWithTakeOfBuffer, + InitializeBufferWithTakeOfBuffer) +#undef DEFINE_BINARY_BUFFER_OP + +#define DEFINE_UNARY_BUFFER_OP(RESULT, LOWER, TITLE) \ +RESULT TypeInfo::LOWER(IRGenFunction &IGF, Address buffer, SILType T) const { \ + return emitDefault##TITLE(IGF, buffer, T, *this, getFixedPacking(IGF.IGM)); \ +} \ +static RESULT emit##TITLE(IRGenFunction &IGF, Address buffer, SILType T, \ + const TypeInfo &type, FixedPacking packing) { \ + if (packing == FixedPacking::Dynamic) \ + return type.LOWER(IGF, buffer, T); \ + return emitDefault##TITLE(IGF, buffer, T, type, packing); \ +} +DEFINE_UNARY_BUFFER_OP(Address, allocateBuffer, AllocateBuffer) +DEFINE_UNARY_BUFFER_OP(Address, projectBuffer, ProjectBuffer) +DEFINE_UNARY_BUFFER_OP(void, destroyBuffer, DestroyBuffer) +DEFINE_UNARY_BUFFER_OP(void, deallocateBuffer, DeallocateBuffer) +#undef DEFINE_UNARY_BUFFER_OP + static llvm::Value *getArg(llvm::Function::arg_iterator &it, StringRef name) { llvm::Value *arg = &*(it++); @@ -899,7 +943,8 @@ static void buildValueWitnessFunction(IRGenModule &IGM, case ValueWitness::AllocateBuffer: { Address buffer = getArgAsBuffer(IGF, argv, "buffer"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - Address result = emitAllocateBuffer(IGF, concreteType, type, packing, buffer); + Address result = + emitAllocateBuffer(IGF, buffer, concreteType, type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -928,7 +973,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, case ValueWitness::DeallocateBuffer: { Address buffer = getArgAsBuffer(IGF, argv, "buffer"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - emitDeallocateBuffer(IGF, concreteType, type, packing, buffer); + emitDeallocateBuffer(IGF, buffer, concreteType, type, packing); IGF.Builder.CreateRetVoid(); return; } @@ -964,6 +1009,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, IGF.Builder.CreateCondBr(done, exit, loop); IGF.Builder.emitBlock(loop); + ConditionalDominanceScope condition(IGF); type.destroy(IGF, element, concreteType); auto nextCounter = IGF.Builder.CreateSub(counter, llvm::ConstantInt::get(IGM.SizeTy, 1)); @@ -984,7 +1030,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, case ValueWitness::DestroyBuffer: { Address buffer = getArgAsBuffer(IGF, argv, "buffer"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - emitDestroyBuffer(IGF, concreteType, type, packing, buffer); + emitDestroyBuffer(IGF, buffer, concreteType, type, packing); IGF.Builder.CreateRetVoid(); return; } @@ -995,8 +1041,8 @@ static void buildValueWitnessFunction(IRGenModule &IGM, getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); Address result = - emitInitializeBufferWithCopyOfBuffer(IGF, concreteType, - type, packing, dest, src); + emitInitializeBufferWithCopyOfBuffer(IGF, dest, src, concreteType, + type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -1008,8 +1054,8 @@ static void buildValueWitnessFunction(IRGenModule &IGM, getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); Address result = - emitInitializeBufferWithTakeOfBuffer(IGF, concreteType, - type, packing, dest, src); + emitInitializeBufferWithTakeOfBuffer(IGF, dest, src, concreteType, + type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -1021,7 +1067,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); Address result = - emitInitializeBufferWithCopy(IGF, concreteType, type, packing, dest, src); + emitInitializeBufferWithCopy(IGF, dest, src, concreteType, type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -1033,7 +1079,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); Address result = - emitInitializeBufferWithTake(IGF, concreteType, type, packing, dest, src); + emitInitializeBufferWithTake(IGF, dest, src, concreteType, type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -1044,7 +1090,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, Address src = getArgAs(IGF, argv, type, "src"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - emitInitializeWithCopy(IGF, concreteType, type, dest, src); + type.initializeWithCopy(IGF, dest, src, concreteType); dest = IGF.Builder.CreateBitCast(dest, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(dest.getAddress()); return; @@ -1061,7 +1107,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, Address src = getArgAs(IGF, argv, type, "src"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - emitInitializeWithTake(IGF, concreteType, type, dest, src); + type.initializeWithTake(IGF, dest, src, concreteType); dest = IGF.Builder.CreateBitCast(dest, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(dest.getAddress()); return; @@ -1083,7 +1129,7 @@ static void buildValueWitnessFunction(IRGenModule &IGM, Address buffer = getArgAsBuffer(IGF, argv, "buffer"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - Address result = emitProjectBuffer(IGF, concreteType, type, packing, buffer); + Address result = emitProjectBuffer(IGF, buffer, concreteType, type, packing); result = IGF.Builder.CreateBitCast(result, IGF.IGM.OpaquePtrTy); IGF.Builder.CreateRet(result.getAddress()); return; @@ -1119,17 +1165,16 @@ static void buildValueWitnessFunction(IRGenModule &IGM, auto enumAddr = type.getAddressForPointer(value); llvm::Value *result = strategy.emitGetEnumTag(IGF, concreteType, enumAddr); - result = IGF.Builder.CreateZExtOrTrunc(result, IGF.IGM.Int32Ty); - IGF.Builder.CreateRet(result); return; } case ValueWitness::DestructiveProjectEnumData: { + auto &strategy = getEnumImplStrategy(IGM, concreteType); + llvm::Value *value = getArg(argv, "value"); getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - auto &strategy = getEnumImplStrategy(IGM, concreteType); if (strategy.getElementsWithPayload().size() > 0) { strategy.destructiveProjectDataForLoad( IGF, concreteType, @@ -1141,14 +1186,17 @@ static void buildValueWitnessFunction(IRGenModule &IGM, } case ValueWitness::DestructiveInjectEnumTag: { + auto &strategy = getEnumImplStrategy(IGM, concreteType); + llvm::Value *value = getArg(argv, "value"); + auto enumTy = type.getStorageType()->getPointerTo(); value = IGF.Builder.CreateBitCast(value, enumTy); llvm::Value *tag = getArg(argv, "tag"); + getArgAsLocalSelfTypeMetadata(IGF, argv, abstractType); - auto &strategy = getEnumImplStrategy(IGM, concreteType); strategy.emitStoreTag(IGF, concreteType, Address(value, type.getBestKnownAlignment()), tag); @@ -1411,25 +1459,25 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM, goto standard; case ValueWitness::DestroyBuffer: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { if (isNeverAllocated(packing)) return asOpaquePtr(IGM, getNoOpVoidFunction(IGM)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { assert(isNeverAllocated(packing)); return asOpaquePtr(IGM, getDestroyStrongFunction(IGM)); } goto standard; case ValueWitness::Destroy: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getNoOpVoidFunction(IGM)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getDestroyStrongFunction(IGM)); } goto standard; case ValueWitness::DestroyArray: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getNoOpVoidFunction(IGM)); } // TODO: A standard "destroy strong array" entrypoint for arrays of single @@ -1439,9 +1487,9 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM, case ValueWitness::InitializeBufferWithCopyOfBuffer: case ValueWitness::InitializeBufferWithCopy: if (packing == FixedPacking::OffsetZero) { - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getInitWithCopyStrongFunction(IGM)); } } @@ -1451,61 +1499,61 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM, if (packing == FixedPacking::Allocate) { return asOpaquePtr(IGM, getCopyOutOfLinePointerFunction(IGM)); } else if (packing == FixedPacking::OffsetZero && - concreteTI.isBitwiseTakable(ResilienceScope::Component)) { + concreteTI.isBitwiseTakable(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); } goto standard; case ValueWitness::InitializeBufferWithTake: - if (concreteTI.isBitwiseTakable(ResilienceScope::Component) + if (concreteTI.isBitwiseTakable(ResilienceExpansion::Maximal) && packing == FixedPacking::OffsetZero) return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); goto standard; case ValueWitness::InitializeWithTake: - if (concreteTI.isBitwiseTakable(ResilienceScope::Component)) { + if (concreteTI.isBitwiseTakable(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); } goto standard; case ValueWitness::InitializeArrayWithTakeFrontToBack: - if (concreteTI.isBitwiseTakable(ResilienceScope::Component)) { + if (concreteTI.isBitwiseTakable(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemMoveArrayFunction(IGM, concreteTI)); } goto standard; case ValueWitness::InitializeArrayWithTakeBackToFront: - if (concreteTI.isBitwiseTakable(ResilienceScope::Component)) { + if (concreteTI.isBitwiseTakable(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemMoveArrayFunction(IGM, concreteTI)); } goto standard; case ValueWitness::AssignWithCopy: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getAssignWithCopyStrongFunction(IGM)); } goto standard; case ValueWitness::AssignWithTake: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getAssignWithTakeStrongFunction(IGM)); } goto standard; case ValueWitness::InitializeWithCopy: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyFunction(IGM, concreteTI)); - } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceScope::Component)) { + } else if (concreteTI.isSingleSwiftRetainablePointer(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getInitWithCopyStrongFunction(IGM)); } goto standard; case ValueWitness::InitializeArrayWithCopy: - if (concreteTI.isPOD(ResilienceScope::Component)) { + if (concreteTI.isPOD(ResilienceExpansion::Maximal)) { return asOpaquePtr(IGM, getMemCpyArrayFunction(IGM, concreteTI)); } // TODO: A standard "copy strong array" entrypoint for arrays of single @@ -1533,7 +1581,7 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM, // meaningful flags for it. if (auto *fixedTI = dyn_cast(&concreteTI)) { flags |= fixedTI->getFixedAlignment().getValue() - 1; - if (!fixedTI->isPOD(ResilienceScope::Component)) + if (!fixedTI->isPOD(ResilienceExpansion::Maximal)) flags |= ValueWitnessFlags::IsNonPOD; assert(packing == FixedPacking::OffsetZero || packing == FixedPacking::Allocate); @@ -1543,7 +1591,7 @@ static llvm::Constant *getValueWitness(IRGenModule &IGM, if (fixedTI->getFixedExtraInhabitantCount(IGM) > 0) flags |= ValueWitnessFlags::Enum_HasExtraInhabitants; - if (!fixedTI->isBitwiseTakable(ResilienceScope::Component)) + if (!fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal)) flags |= ValueWitnessFlags::IsNonBitwiseTakable; } @@ -1615,35 +1663,14 @@ namespace { IRGenModule &IGM; SmallVectorImpl &Table; CanType ConcreteType; - GenericParamList *ConcreteGenerics = nullptr; - const TypeInfo &ConcreteTI; - const ProtocolConformance &Conformance; - ArrayRef Substitutions; + const NormalProtocolConformance &Conformance; ArrayRef SILEntries; -#ifndef NDEBUG const ProtocolInfo &PI; -#endif - - void computeSubstitutionsForType() { - // FIXME: This is a bit of a hack; the AST doesn't directly encode - // substitutions for the conformance of a generic type to a - // protocol, so we have to dig them out. - Type ty = ConcreteType; - while (ty) { - if (auto nomTy = ty->getAs()) - ty = nomTy->getParent(); - else - break; - } - if (ty) { - if (auto boundTy = ty->getAs()) { - ConcreteGenerics = boundTy->getDecl()->getGenericParams(); - Substitutions = boundTy->getSubstitutions(/*FIXME:*/nullptr, nullptr); - } else { - assert(!ty || !ty->isSpecialized()); - } - } - } + Optional Fulfillments; + SmallVector, 4> + SpecializedBaseConformances; + unsigned NextCacheIndex = 0; + bool RequiresSpecialization = false; public: WitnessTableBuilder(IRGenModule &IGM, @@ -1651,17 +1678,22 @@ namespace { SILWitnessTable *SILWT) : IGM(IGM), Table(table), ConcreteType(SILWT->getConformance()->getType()->getCanonicalType()), - ConcreteTI( - IGM.getTypeInfoForUnlowered(SILWT->getConformance()->getType())), Conformance(*SILWT->getConformance()), - SILEntries(SILWT->getEntries()) -#ifndef NDEBUG - , PI(IGM.getProtocolInfo(SILWT->getConformance()->getProtocol())) -#endif + SILEntries(SILWT->getEntries()), + PI(IGM.getProtocolInfo(SILWT->getConformance()->getProtocol())) { - computeSubstitutionsForType(); + // Cache entries start at the end of the table. + NextCacheIndex = PI.getNumWitnesses(); + // TODO: in conditional conformances, allocate space for the assumed + // conformances here. } + /// The top-level entry point. + void build(); + + /// Create the access function. + void buildAccessFunction(llvm::Constant *wtable); + /// A base protocol is witnessed by a pointer to the conformance /// of this type to that protocol. void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) { @@ -1687,9 +1719,17 @@ namespace { const ConformanceInfo &conf = basePI.getConformance(IGM, baseProto, astConf); + // If we can emit the base witness table as a constant, do so. llvm::Constant *baseWitness = conf.tryGetConstantTable(IGM, ConcreteType); - assert(baseWitness && "couldn't get a constant table!"); - Table.push_back(asOpaquePtr(IGM, baseWitness)); + if (baseWitness) { + Table.push_back(baseWitness); + return; + } + + // Otherwise, we'll need to derive it at instantiation time. + RequiresSpecialization = true; + SpecializedBaseConformances.push_back({Table.size(), &conf}); + Table.push_back(llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); } void addMethodFromSILWitnessTable(AbstractFunctionDecl *iface) { @@ -1716,12 +1756,10 @@ namespace { llvm::Constant *witness = nullptr; if (Func) { witness = IGM.getAddrOfSILFunction(Func, NotForDefinition); - witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy); } else { // The method is removed by dead method elimination. // It should be never called. We add a pointer to an error function. - witness = llvm::ConstantExpr::getBitCast(IGM.getDeadMethodErrorFn(), - IGM.Int8PtrTy); + witness = IGM.getDeletedMethodErrorFn(); } Table.push_back(witness); return; @@ -1735,52 +1773,524 @@ namespace { return addMethodFromSILWitnessTable(iface); } - void addAssociatedType(AssociatedTypeDecl *ty, + void addAssociatedType(AssociatedTypeDecl *requirement, ArrayRef protos) { #ifndef NDEBUG auto &entry = SILEntries.front(); assert(entry.getKind() == SILWitnessTable::AssociatedType && "sil witness table does not match protocol"); - assert(entry.getAssociatedTypeWitness().Requirement == ty + assert(entry.getAssociatedTypeWitness().Requirement == requirement && "sil witness table does not match protocol"); - auto piEntry = PI.getWitnessEntry(ty); + auto piEntry = PI.getWitnessEntry(requirement); assert(piEntry.getAssociatedTypeIndex().getValue() == Table.size() && "offset doesn't match ProtocolInfo layout"); #endif SILEntries = SILEntries.slice(1); - // FIXME: Use info from SILWitnessTable instead of falling through. + const Substitution &sub = + Conformance.getTypeWitness(requirement, nullptr); + assert(protos.size() == sub.getConformances().size()); - // Determine whether the associated type has static metadata. If it - // doesn't, then this witness table is a template that requires runtime - // instantiation. + // This type will be expressed in terms of the archetypes + // of the conforming context. + CanType associate = sub.getReplacement()->getCanonicalType(); + assert(!associate->hasTypeParameter()); - // FIXME: Add static type metadata. - Table.push_back(llvm::ConstantPointerNull::get(IGM.Int8PtrTy)); + llvm::Constant *metadataAccessFunction = + getAssociatedTypeMetadataAccessFunction(requirement, associate); + Table.push_back(metadataAccessFunction); // FIXME: Add static witness tables for type conformances. - for (auto protocol : protos) { + for (auto index : indices(protos)) { + ProtocolDecl *protocol = protos[index]; + auto associatedConformance = sub.getConformances()[index]; + if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) continue; +#ifndef NDEBUG auto &entry = SILEntries.front(); (void)entry; assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol && "sil witness table does not match protocol"); - assert(entry.getAssociatedTypeProtocolWitness().Requirement == ty + auto associatedWitness = entry.getAssociatedTypeProtocolWitness(); + assert(associatedWitness.Requirement == requirement && "sil witness table does not match protocol"); - assert(entry.getAssociatedTypeProtocolWitness().Protocol == protocol + assert(associatedWitness.Protocol == protocol && "sil witness table does not match protocol"); +#endif SILEntries = SILEntries.slice(1); - // FIXME: Use info from SILWitnessTable instead of falling through. - // FIXME: Add static witness table reference. - Table.push_back(llvm::ConstantPointerNull::get(IGM.Int8PtrTy)); + llvm::Constant *wtableAccessFunction = + getAssociatedTypeWitnessTableAccessFunction(requirement, associate, + protocol, associatedConformance); + Table.push_back(wtableAccessFunction); } } + + private: + llvm::Constant *buildInstantiationFunction(); + + llvm::Constant * + getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement, + CanType associatedType); + + llvm::Constant * + getAssociatedTypeWitnessTableAccessFunction(AssociatedTypeDecl *requirement, + CanType associatedType, + ProtocolDecl *protocol, + ProtocolConformanceRef conformance); + + void emitReturnOfCheckedLoadFromCache(IRGenFunction &IGF, + Address destTable, + llvm::Value *selfMetadata, + llvm::function_ref body); + + void bindArchetypes(IRGenFunction &IGF, llvm::Value *selfMetadata); + + /// Allocate another word of private data storage in the conformance table. + unsigned getNextCacheIndex() { + RequiresSpecialization = true; + return NextCacheIndex++; + } + + const FulfillmentMap &getFulfillmentMap() { + if (Fulfillments) return *Fulfillments; + + Fulfillments.emplace(); + if (ConcreteType->hasArchetype()) { + struct Callback : FulfillmentMap::InterestingKeysCallback { + bool isInterestingType(CanType type) const override { + return isa(type); + } + bool hasInterestingType(CanType type) const override { + return type->hasArchetype(); + } + bool hasLimitedInterestingConformances(CanType type) const override { + return false; + } + GenericSignature::ConformsToArray + getInterestingConformances(CanType type) const override { + llvm_unreachable("no limits"); + } + } callback; + Fulfillments->searchTypeMetadata(*IGM.SILMod->getSwiftModule(), + ConcreteType, IsExact, + /*sourceIndex*/ 0, MetadataPath(), + callback); + } + return *Fulfillments; + } + }; +} + +/// Build the witness table. +void WitnessTableBuilder::build() { + visitProtocolDecl(Conformance.getProtocol()); + + // Go through and convert all the entries to i8*. + // TODO: the IR would be more legible if we made a struct instead. + for (auto &entry : Table) { + entry = llvm::ConstantExpr::getBitCast(entry, IGM.Int8PtrTy); + } +} + +/// Return the address of a function which will return the type metadata +/// for an associated type. +llvm::Constant *WitnessTableBuilder:: +getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement, + CanType associatedType) { + // If the associated type is non-dependent, we can use an ordinary + // metadata access function. We'll just end up passing extra arguments. + if (!associatedType->hasArchetype()) { + return getOrCreateTypeMetadataAccessFunction(IGM, associatedType); + } + + // Otherwise, emit an access function. + llvm::Function *accessor = + IGM.getAddrOfAssociatedTypeMetadataAccessFunction(&Conformance, + requirement); + + IRGenFunction IGF(IGM, accessor); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, accessor); + + Explosion parameters = IGF.collectParameters(); + + llvm::Value *self = parameters.claimNext(); + setTypeMetadataName(IGM, self, ConcreteType); + + Address destTable(parameters.claimNext(), IGM.getPointerAlignment()); + setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType, + requirement->getProtocol()); + + // If the associated type is directly fulfillable from the type, + // we don't need a cache entry. + // TODO: maybe we should have a cache entry anyway if the fulfillment + // is expensive. + if (auto fulfillment = + getFulfillmentMap().getTypeMetadata(associatedType)) { + llvm::Value *metadata = + fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, self, + /*cache*/ nullptr); + IGF.Builder.CreateRet(metadata); + return accessor; + } + + // Otherwise, we need a cache entry. + emitReturnOfCheckedLoadFromCache(IGF, destTable, self, + [&]() -> llvm::Value* { + return IGF.emitTypeMetadataRef(associatedType); + }); + + return accessor; +} + +/// Return a function which will return a particular witness table +/// conformance. The function will be passed the metadata for which +/// the conformance is being requested; it may ignore this (perhaps +/// implicitly by taking no arguments). +static llvm::Constant * +getOrCreateWitnessTableAccessFunction(IRGenModule &IGM, CanType type, + ProtocolConformance *conformance) { + assert(!type->hasArchetype() && "cannot do this for dependent type"); + + // We always emit an access function for conformances, and in principle + // it is always possible to just use that here directly. However, + // if it's dependent, doing so won't allow us to cache the result. + // For the specific use case of an associated type conformance, we could + // use a cache in the witness table; but that wastes space per conformance + // and won't let us re-use the cache with other non-dependent uses in + // the module. Therefore, in this case, we use the address of the lazy-cache + // function. + // + // FIXME: we will need to pass additional parameters if the target + // conformance is conditional. + auto rootConformance = conformance->getRootNormalConformance(); + if (rootConformance->getDeclContext()->isGenericContext()) { + return getWitnessTableLazyAccessFunction(IGM, rootConformance, type); + } else { + return IGM.getAddrOfWitnessTableAccessFunction( + conformance->getRootNormalConformance(), + NotForDefinition); + } +} + +llvm::Constant *WitnessTableBuilder:: +getAssociatedTypeWitnessTableAccessFunction(AssociatedTypeDecl *requirement, + CanType associatedType, + ProtocolDecl *associatedProtocol, + ProtocolConformanceRef associatedConformance) { + if (!associatedType->hasArchetype()) { + assert(associatedConformance.isConcrete() && + "no concrete conformance for non-dependent type"); + return getOrCreateWitnessTableAccessFunction(IGM, associatedType, + associatedConformance.getConcrete()); + } + + // Otherwise, emit an access function. + llvm::Function *accessor = + IGM.getAddrOfAssociatedTypeWitnessTableAccessFunction(&Conformance, + requirement, + associatedProtocol); + + IRGenFunction IGF(IGM, accessor); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, accessor); + + Explosion parameters = IGF.collectParameters(); + + llvm::Value *associatedTypeMetadata = parameters.claimNext(); + if (IGM.EnableValueNames) + associatedTypeMetadata->setName(Twine(ConcreteType->getString()) + + "." + requirement->getNameStr()); + + llvm::Value *self = parameters.claimNext(); + setTypeMetadataName(IGM, self, ConcreteType); + + Address destTable(parameters.claimNext(), IGM.getPointerAlignment()); + setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType, + requirement->getProtocol()); + + const ConformanceInfo *conformanceI = nullptr; + if (associatedConformance.isConcrete()) { + const ProtocolInfo &protocolI = IGM.getProtocolInfo(associatedProtocol); + conformanceI = + &protocolI.getConformance(IGM, associatedProtocol, + associatedConformance.getConcrete()); + + // If we can emit a constant table, do so. + // In principle, any time we can do this, we should try to re-use this + // function for other conformances. But that should typically already + // be covered by the !hasArchetype() check above. + if (auto constantTable = + conformanceI->tryGetConstantTable(IGM, associatedType)) { + IGF.Builder.CreateRet(constantTable); + return accessor; + } + } + + // If the witness table is directly fulfillable from the type, + // we don't need a cache entry. + // TODO: maybe we should have a cache entry anyway if the fulfillment + // is expensive. + if (auto fulfillment = + getFulfillmentMap().getWitnessTable(associatedType, + associatedProtocol)) { + llvm::Value *wtable = + fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, self, + /*cache*/ nullptr); + IGF.Builder.CreateRet(wtable); + return accessor; + } + + assert(conformanceI && "no conformance information, but also couldn't " + "fulfill witness table contextually"); + + // Otherwise, we need a cache entry. + emitReturnOfCheckedLoadFromCache(IGF, destTable, self, + [&]() -> llvm::Value* { + return conformanceI->getTable(IGF, associatedType, &associatedTypeMetadata); + }); + + return accessor; +} + +void WitnessTableBuilder:: +emitReturnOfCheckedLoadFromCache(IRGenFunction &IGF, Address destTable, + llvm::Value *selfMetadata, + llvm::function_ref body) { + // Allocate a new cache slot and drill down to it. + unsigned cacheIndex = getNextCacheIndex(); + Address cache = IGF.Builder.CreateConstArrayGEP(destTable, cacheIndex, + IGM.getPointerSize()); + + llvm::Type *expectedTy = IGF.CurFn->getReturnType(); + cache = IGF.Builder.CreateBitCast(cache, expectedTy->getPointerTo()); + + // Load and check whether it was null. + auto cachedResult = IGF.Builder.CreateLoad(cache); + // FIXME: cachedResult->setOrdering(Consume); + auto cacheIsEmpty = IGF.Builder.CreateIsNull(cachedResult); + llvm::BasicBlock *fetchBB = IGF.createBasicBlock("fetch"); + llvm::BasicBlock *contBB = IGF.createBasicBlock("cont"); + llvm::BasicBlock *entryBB = IGF.Builder.GetInsertBlock(); + IGF.Builder.CreateCondBr(cacheIsEmpty, fetchBB, contBB); + + // Create a phi in the continuation block and use the loaded value if + // we branched directly here. Note that we arrange blocks so that we + // fall through into this. + IGF.Builder.emitBlock(contBB); + auto result = IGF.Builder.CreatePHI(expectedTy, 2); + result->addIncoming(cachedResult, entryBB); + IGF.Builder.CreateRet(result); + + // In the fetch block, bind the archetypes and evaluate the body. + IGF.Builder.emitBlock(fetchBB); + bindArchetypes(IGF, selfMetadata); + + llvm::Value *fetchedResult = body(); + + // Store the fetched result back to the cache. + // We need to transitively ensure that any stores initializing the result + // that are visible to us are visible to callers. + IGF.Builder.CreateStore(fetchedResult, cache)->setOrdering(llvm::Release); + + auto fetchedResultBB = IGF.Builder.GetInsertBlock(); + IGF.Builder.CreateBr(contBB); + result->addIncoming(fetchedResult, fetchedResultBB); +} + +/// Within a metadata or witness-table accessor on this conformance, bind +/// the type metadata and witness tables for all the associated types. +void WitnessTableBuilder::bindArchetypes(IRGenFunction &IGF, + llvm::Value *selfMetadata) { + auto generics = + Conformance.getDeclContext()->getGenericParamsOfContext(); + if (!generics) return; + + MetadataPath::Map cache; + + auto &fulfillments = getFulfillmentMap(); + + for (auto archetype : generics->getAllArchetypes()) { + // FIXME: be lazier. + + // Find the type metadata for the archetype. + // + // All of the primary archetypes will be fulfilled by the concrete + // type; otherwise they'd be free. Everything else we should be able + // to derive from some parent archetype and its known conformances. + llvm::Value *archetypeMetadata; + if (auto fulfillment = + fulfillments.getTypeMetadata(CanType(archetype))) { + archetypeMetadata = + fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, + selfMetadata, &cache); + } else { + assert(!archetype->isPrimary() && "free type param in conformance?"); + + // getAllArchetypes is in dependency order, so the parent archetype + // should always be mapped. + auto parentArchetype = CanArchetypeType(archetype->getParent()); + archetypeMetadata = + emitAssociatedTypeMetadataRef(IGF, parentArchetype, + archetype->getAssocType()); + } + + // Find the witness tables for the archetype. + // + // Archetype conformances in a type context can be classified into + // three buckets: + // + // - They can be inherent to the extended type, e.g. Dictionary's + // requirement that its keys be Equatable. These should always + // be fulfillable from the concrete type metadata. + // + // - If the archetype is an associated type, they can be inherent + // to that associated type's requirements. These should always + // be available from the associated type's parent conformance. + // + // - Otherwise, the conformance must be a free requirement on the + // extension; that is, this must be a conditional conformance. + // We don't support this yet, but when we do they'll have to + // be stored in the private section of the witness table. + SmallVector archetypeWitnessTables; + for (auto protocol : archetype->getConformsTo()) { + llvm::Value *wtable; + if (auto fulfillment = + fulfillments.getWitnessTable(CanType(archetype), protocol)) { + wtable = + fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, + selfMetadata, &cache); + } else { + assert(!archetype->isPrimary() && "conditional conformance?"); + auto parentArchetype = CanArchetypeType(archetype->getParent()); + wtable = emitAssociatedTypeWitnessTableRef(IGF, parentArchetype, + archetype->getAssocType(), + archetypeMetadata, + protocol); + } + archetypeWitnessTables.push_back(wtable); + } + + IGF.bindArchetype(archetype, archetypeMetadata, archetypeWitnessTables); + } +} + +/// Emit the access function for this witness table. +void WitnessTableBuilder::buildAccessFunction(llvm::Constant *wtable) { + llvm::Function *fn = + IGM.getAddrOfWitnessTableAccessFunction(&Conformance, ForDefinition); + + IRGenFunction IGF(IGM, fn); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, fn); + + wtable = llvm::ConstantExpr::getBitCast(wtable, IGM.WitnessTablePtrTy); + + // If specialization isn't required, just return immediately. + // TODO: allow dynamic specialization? + if (!RequiresSpecialization) { + IGF.Builder.CreateRet(wtable); + return; + } + + // The target metadata is the first argument. + assert(Conformance.getDeclContext()->isGenericContext()); + Explosion params = IGF.collectParameters(); + llvm::Value *metadata = params.claimNext(); + + // Okay, we need a cache. Build the cache structure. + // struct GenericWitnessTable { + // /// The size of the witness table in words. + // uint16_t WitnessTableSizeInWords; + // + // /// The amount to copy from the pattern in words. The rest is zeroed. + // uint16_t WitnessTableSizeInWordsToCopy; + // + // /// The pattern. + // RelativeDirectPointer WitnessTable; + // + // /// The instantiation function, which is called after the template is copied. + // RelativeDirectPointer Instantiator; + // + // void *PrivateData[swift::NumGenericMetadataPrivateDataWords]; + // }; + + // First, create the global. We have to build this in two phases because + // it contains relative pointers. + auto cache = cast( + IGM.getAddrOfGenericWitnessTableCache(&Conformance, ForDefinition)); + + // We need an instantiation function if the base conformance + // is non-dependent. + // TODO: the conformance might be conditional. + llvm::Constant *instantiationFn; + llvm::Value *instantiationArgs = + llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy); + if (SpecializedBaseConformances.empty()) { + instantiationFn = llvm::ConstantInt::get(IGM.RelativeAddressTy, 0); + } else { + llvm::Constant *fn = buildInstantiationFunction(); + instantiationFn = IGM.emitDirectRelativeReference(fn, cache, { 3 }); + } + + // Fill in the global. + auto cacheTy = cast(cache->getValueType()); + llvm::Constant *cacheData[] = { + llvm::ConstantInt::get(IGM.Int16Ty, NextCacheIndex), + llvm::ConstantInt::get(IGM.Int16Ty, Table.size()), + IGM.emitDirectRelativeReference(wtable, cache, { 2 }), + instantiationFn, + llvm::Constant::getNullValue(cacheTy->getStructElementType(4)) }; + cache->setInitializer(llvm::ConstantStruct::get(cacheTy, cacheData)); + + auto call = IGF.Builder.CreateCall(IGM.getGetGenericWitnessTableFn(), + { cache, metadata, instantiationArgs }); + call->setCallingConv(IGM.RuntimeCC); + call->setDoesNotThrow(); + + IGF.Builder.CreateRet(call); +} + +llvm::Constant *WitnessTableBuilder::buildInstantiationFunction() { + llvm::Function *fn = + IGM.getAddrOfGenericWitnessTableInstantiationFunction(&Conformance); + IRGenFunction IGF(IGM, fn); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, fn); + + // Break out the parameters. + Explosion params = IGF.collectParameters(); + Address wtable(params.claimNext(), IGM.getPointerAlignment()); + llvm::Value *metadata = params.claimNext(); + llvm::Value *instantiationArgs = params.claimNext(); + (void) instantiationArgs; // unused for now + + // TODO: store any required conditional-conformance information + // in the private data. + + // Initialize all the specialized base conformances. + for (auto &base : SpecializedBaseConformances) { + // Ask the ConformanceInfo to emit the wtable. + // TODO: we may need to bind extra information in the IGF in order + // to make conditional conformances work. + llvm::Value *baseWTable = + base.second->getTable(IGF, ConcreteType, &metadata); + baseWTable = IGF.Builder.CreateBitCast(baseWTable, IGM.Int8PtrTy); + + // Store that to the appropriate slot in the new witness table. + Address slot = IGF.Builder.CreateConstArrayGEP(wtable, base.first, + IGM.getPointerSize()); + IGF.Builder.CreateStore(baseWTable, slot); + } + + IGF.Builder.CreateRetVoid(); + return fn; } /// Collect the value witnesses for a particular type. @@ -1822,14 +2332,37 @@ bool irgen::hasDependentValueWitnessTable(IRGenModule &IGM, CanType ty) { return !IGM.getTypeInfoForUnlowered(ty).isFixedSize(); } +/// Given an abstract type --- a type possibly expressed in terms of +/// unbound generic types --- return the formal type within the type's +/// primary defining context. +static CanType getFormalTypeInContext(CanType abstractType) { + // Map the parent of any non-generic nominal type. + if (auto nominalType = dyn_cast(abstractType)) { + // If it doesn't have a parent, or the parent doesn't need remapping, + // do nothing. + auto abstractParentType = nominalType.getParent(); + if (!abstractParentType) return abstractType; + auto parentType = getFormalTypeInContext(abstractParentType); + if (abstractParentType == parentType) return abstractType; + + // Otherwise, rebuild the type. + return CanType(NominalType::get(nominalType->getDecl(), parentType, + nominalType->getDecl()->getASTContext())); + + // Map unbound types into their defining context. + } else if (auto ugt = dyn_cast(abstractType)) { + return ugt->getDecl()->getDeclaredTypeInContext()->getCanonicalType(); + + // Everything else stays the same. + } else { + return abstractType; + } +} + static void addValueWitnessesForAbstractType(IRGenModule &IGM, CanType abstractType, SmallVectorImpl &witnesses) { - // Instantiate unbound generic types on their context archetypes. - CanType concreteFormalType = abstractType; - if (auto ugt = dyn_cast(abstractType)) { - concreteFormalType = ugt->getDecl()->getDeclaredTypeInContext()->getCanonicalType(); - } + CanType concreteFormalType = getFormalTypeInContext(abstractType); auto concreteLoweredType = IGM.SILMod->Types.getLoweredType(concreteFormalType); auto &concreteTI = IGM.getTypeInfo(concreteLoweredType); @@ -1873,8 +2406,8 @@ llvm::Constant *IRGenModule::emitFixedTypeLayout(CanType t, unsigned size = ti.getFixedSize().getValue(); unsigned align = ti.getFixedAlignment().getValue(); - bool pod = ti.isPOD(ResilienceScope::Component); - bool bt = ti.isBitwiseTakable(ResilienceScope::Component); + bool pod = ti.isPOD(ResilienceExpansion::Maximal); + bool bt = ti.isBitwiseTakable(ResilienceExpansion::Maximal); unsigned numExtraInhabitants = ti.getFixedExtraInhabitantCount(*this); // Try to use common type layouts exported by the runtime. @@ -2013,6 +2546,9 @@ ProtocolInfo::~ProtocolInfo() { const ConformanceInfo & ProtocolInfo::getConformance(IRGenModule &IGM, ProtocolDecl *protocol, const ProtocolConformance *conformance) const { + assert(conformance->getProtocol() == protocol && + "conformance is for wrong protocol"); + // Drill down to the root normal conformance. auto normalConformance = conformance->getRootNormalConformance(); @@ -2025,9 +2561,8 @@ ProtocolInfo::getConformance(IRGenModule &IGM, ProtocolDecl *protocol, // If the conformance is dependent in any way, we need to unique it. // TODO: maybe this should apply whenever it's out of the module? // TODO: actually enable this - if ((false) && - isDependentConformance(IGM, normalConformance, - ResilienceScope::Component)) { + if (isDependentConformance(IGM, normalConformance, + ResilienceExpansion::Maximal)) { info = new AccessorConformanceInfo(normalConformance); // Otherwise, we can use a direct-referencing conformance. @@ -2043,16 +2578,19 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { // Don't emit a witness table if it is a declaration. if (wt->isDeclaration()) return; + + bool mustEmitDefinition = !isAvailableExternally(wt->getLinkage()); + // Don't emit a witness table that is available externally if we are emitting // code for the JIT. We do not do any optimization for the JIT and it has // problems with external symbols that get merged with non-external symbols. - if (Opts.UseJIT && isAvailableExternally(wt->getLinkage())) + if (Opts.UseJIT && !mustEmitDefinition) return; // Build the witnesses. SmallVector witnesses; - WitnessTableBuilder(*this, witnesses, wt) - .visitProtocolDecl(wt->getConformance()->getProtocol()); + WitnessTableBuilder wtableBuilder(*this, witnesses, wt); + wtableBuilder.build(); assert(getProtocolInfo(wt->getConformance()->getProtocol()) .getNumWitnesses() == witnesses.size() @@ -2068,8 +2606,13 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { global->setInitializer(initializer); global->setAlignment(getWitnessTableAlignment().getValue()); + // FIXME: resilience; this should use the conformance's publishing scope. + if (mustEmitDefinition) { + wtableBuilder.buildAccessFunction(global); + } + // Build the conformance record, if it lives in this TU. - if (isAvailableExternally(wt->getLinkage())) + if (!mustEmitDefinition) return; addProtocolConformanceRecord(wt->getConformance()); @@ -2121,10 +2664,6 @@ namespace { /// The polymorphic arguments are derived from a Self type binding /// passed via the WitnessMethod convention. WitnessSelf, - - /// The polymorphic arguments are derived from a Self type binding - /// embedded in a thick WitnessMethod function value. - WitnessExtraData, }; static bool requiresSourceIndex(SourceKind kind) { @@ -2218,19 +2757,6 @@ namespace { } } - /// Extract dependent type metadata for a value witness function of the given - /// type. - PolymorphicConvention(NominalTypeDecl *ntd, Module &M) - : M(M), FnType(getNotionalFunctionType(ntd)) - { - initGenerics(); - - auto paramType = FnType->getParameters()[0].getType(); - Sources.emplace_back(SourceKind::Metadata, 0, paramType); - - considerType(paramType, FulfillmentMap::IsInexact, 0, MetadataPath()); - } - ArrayRef getSources() const { return Sources; } GenericSignatureWitnessIterator getAllDependentTypes() const { @@ -2248,27 +2774,8 @@ namespace { Generics = FnType->getGenericSignature(); } - static CanSILFunctionType getNotionalFunctionType(NominalTypeDecl *D) { - ASTContext &ctx = D->getASTContext(); - SILFunctionType::ExtInfo extInfo(SILFunctionType::Representation::Method, - /*noreturn*/ false); - SILResultInfo result(TupleType::getEmpty(ctx), - ResultConvention::Unowned); - SILParameterInfo param(D->getDeclaredInterfaceType()->getCanonicalType(), - ParameterConvention::Direct_Owned); - - CanGenericSignature sig = D->getGenericSignatureOfContext() - ? D->getGenericSignatureOfContext()->getCanonicalSignature() - : nullptr; - - return SILFunctionType::get(sig, extInfo, - ParameterConvention::Direct_Unowned, - param, result, None, ctx); - } - void considerNewTypeSource(SourceKind kind, unsigned paramIndex, - CanType type, - FulfillmentMap::IsExact_t isExact) { + CanType type, IsExact_t isExact) { if (!Fulfillments.isInterestingTypeForFulfillments(type)) return; // Prospectively add a source. @@ -2281,23 +2788,28 @@ namespace { } } - bool considerType(CanType type, FulfillmentMap::IsExact_t isExact, + bool considerType(CanType type, IsExact_t isExact, unsigned sourceIndex, MetadataPath &&path) { struct Callback : FulfillmentMap::InterestingKeysCallback { PolymorphicConvention &Self; Callback(PolymorphicConvention &self) : Self(self) {} bool isInterestingType(CanType type) const override { - return FulfillmentMap::isInterestingTypeForFulfillments(type); + return type->isTypeParameter(); + } + bool hasInterestingType(CanType type) const override { + return type->hasTypeParameter(); + } + bool hasLimitedInterestingConformances(CanType type) const override { + return true; } - GenericSignature::ConformsToArray getInterestingConformances(CanType type) const override { return Self.getConformsTo(type); } } callbacks(*this); return Fulfillments.searchTypeMetadata(M, type, isExact, sourceIndex, - std::move(path), &callbacks); + std::move(path), callbacks); } /// Testify to generic parameters in the Self type. @@ -2310,8 +2822,7 @@ namespace { if (auto paramTy = dyn_cast(selfTy)) considerWitnessParamType(paramTy); else - considerType(selfTy, FulfillmentMap::IsInexact, - Sources.size() - 1, MetadataPath()); + considerType(selfTy, IsInexact, Sources.size() - 1, MetadataPath()); } void considerParameter(SILParameterInfo param, unsigned paramIndex, @@ -2332,8 +2843,7 @@ namespace { if (!isSelfParameter) return; if (type->getNominalOrBoundGenericNominal()) { considerNewTypeSource(SourceKind::GenericLValueMetadata, - paramIndex, type, - FulfillmentMap::IsExact); + paramIndex, type, IsExact); } return; @@ -2344,7 +2854,7 @@ namespace { // Classes are sources of metadata. if (type->getClassOrBoundGenericClass()) { considerNewTypeSource(SourceKind::ClassPointer, paramIndex, type, - FulfillmentMap::IsInexact); + IsInexact); return; } @@ -2355,7 +2865,7 @@ namespace { CanType objTy = metatypeTy.getInstanceType(); considerNewTypeSource(SourceKind::Metadata, paramIndex, objTy, - FulfillmentMap::IsInexact); + IsInexact); return; } @@ -2417,7 +2927,7 @@ namespace { /// A class for binding type parameters of a generic function. class EmitPolymorphicParameters : public PolymorphicConvention { IRGenFunction &IGF; - GenericParamList *ContextParams; + SILFunction &Fn; struct SourceValue { llvm::Value *Value = nullptr; @@ -2431,27 +2941,21 @@ namespace { SILFunction &Fn) : PolymorphicConvention(Fn.getLoweredFunctionType(), *IGF.IGM.SILMod->getSwiftModule()), - IGF(IGF), ContextParams(Fn.getContextGenericParams()) {} + IGF(IGF), Fn(Fn) {} void emit(Explosion &in, WitnessMetadata *witnessMetadata, const GetParameterFn &getParameter); - /// Emit polymorphic parameters for a generic value witness. - EmitPolymorphicParameters(IRGenFunction &IGF, NominalTypeDecl *ntd) - : PolymorphicConvention(ntd, *IGF.IGM.SILMod->getSwiftModule()), - IGF(IGF), ContextParams(ntd->getGenericParams()) {} - - void emitForGenericValueWitness(llvm::Value *selfMeta); - private: // Emit metadata bindings after the source, if any, has been bound. void emitWithSourcesBound(Explosion &in); + CanType getTypeInContext(CanType type) const { + return Fn.mapTypeIntoContext(type)->getCanonicalType(); + } + CanType getArgTypeInContext(unsigned paramIndex) const { - return ArchetypeBuilder::mapTypeIntoContext( - IGF.IGM.SILMod->getSwiftModule(), ContextParams, - FnType->getParameters()[paramIndex].getType()) - ->getCanonicalType(); + return getTypeInContext(FnType->getParameters()[paramIndex].getType()); } /// Emit the source value for parameters. @@ -2472,36 +2976,28 @@ namespace { } case SourceKind::GenericLValueMetadata: { + CanType argTy = getArgTypeInContext(source.getParamIndex()); + llvm::Value *metatype = in.claimNext(); - metatype->setName("Self"); + setTypeMetadataName(IGF.IGM, metatype, argTy); // Mark this as the cached metatype for the l-value's object type. - CanType argTy = getArgTypeInContext(source.getParamIndex()); - IGF.setUnscopedLocalTypeData(argTy, LocalTypeData::forMetatype(), + IGF.setUnscopedLocalTypeData(argTy, LocalTypeDataKind::forTypeMetadata(), metatype); return metatype; } case SourceKind::WitnessSelf: { assert(witnessMetadata && "no metadata for witness method"); - llvm::Value *metatype = witnessMetadata->SelfMetadata; - assert(metatype && "no Self metadata for witness method"); + llvm::Value *metadata = witnessMetadata->SelfMetadata; + assert(metadata && "no Self metadata for witness method"); // Mark this as the cached metatype for Self. CanType argTy = getArgTypeInContext(FnType->getParameters().size() - 1); + setTypeMetadataName(IGF.IGM, metadata, argTy); IGF.setUnscopedLocalTypeData(argTy, - LocalTypeData::forMetatype(), metatype); - return metatype; - } - - case SourceKind::WitnessExtraData: { - // The 'Self' parameter is provided last. - // TODO: For default implementations, the witness table pointer for - // the 'Self : P' conformance must be provided last along with the - // metatype. - llvm::Value *metatype = in.takeLast(); - metatype->setName("Self"); - return metatype; + LocalTypeDataKind::forTypeMetadata(), metadata); + return metadata; } } llvm_unreachable("bad source kind!"); @@ -2514,7 +3010,8 @@ namespace { auto &source = getSources()[sourceIndex]; auto &sourceValue = SourceValues[sourceIndex]; - return fulfillment.Path.followFromTypeMetadata(IGF, source.Type, + CanType sourceType = getTypeInContext(source.Type); + return fulfillment.Path.followFromTypeMetadata(IGF, sourceType, sourceValue.Value, &sourceValue.Cache); } @@ -2536,30 +3033,13 @@ void EmitPolymorphicParameters::emit(Explosion &in, emitWithSourcesBound(in); } -/// Emit a polymorphic parameters clause for a generic value witness, binding -/// all the metadata necessary. -void -EmitPolymorphicParameters::emitForGenericValueWitness(llvm::Value *selfMeta) { - // We get the source metadata verbatim from the value witness signature. - assert(getSources().size() == 1); - SourceValues.emplace_back(); - SourceValues.back().Value = selfMeta; - - // All our archetypes should be satisfiable from the source. - Explosion empty; - emitWithSourcesBound(empty); -} - void EmitPolymorphicParameters::emitWithSourcesBound(Explosion &in) { for (auto ncDepTy : getAllDependentTypes()) { CanType depTy = ncDepTy->getCanonicalType(); // Get the corresponding context archetype. - auto contextTy - = ArchetypeBuilder::mapTypeIntoContext(IGF.IGM.SILMod->getSwiftModule(), - ContextParams, depTy) - ->getAs(); + auto contextTy = getTypeInContext(depTy)->getAs(); assert(contextTy); // Derive the appropriate metadata reference. @@ -2602,44 +3082,87 @@ MetadataPath::followFromTypeMetadata(IRGenFunction &IGF, CanType sourceType, llvm::Value *source, Map *cache) const { - return follow(IGF, sourceType, nullptr, source, - Path.begin(), Path.end(), cache); + LocalTypeDataKey key = { + sourceType, + LocalTypeDataKind::forTypeMetadata() + }; + return follow(IGF, key, source, Path.begin(), Path.end(), cache); } llvm::Value * MetadataPath::followFromWitnessTable(IRGenFunction &IGF, - ProtocolDecl *sourceDecl, + CanType conformingType, + ProtocolConformanceRef conformance, llvm::Value *source, Map *cache) const { - return follow(IGF, CanType(), sourceDecl, source, - Path.begin(), Path.end(), cache); + LocalTypeDataKey key = { + conformingType, + LocalTypeDataKind::forProtocolWitnessTable(conformance) + }; + return follow(IGF, key, source, Path.begin(), Path.end(), cache); } +/// Follow this metadata path. +/// +/// \param sourceKey - A description of the source value. Not necessarily +/// an appropriate caching key. +/// \param cache - If given, this cache will be used to short-circuit +/// the lookup; otherwise, the global (but dominance-sensitive) cache +/// in the IRGenFunction will be used. This caching system is somewhat +/// more efficient than what IGF provides, but it's less general, and it +/// should probably be removed. llvm::Value *MetadataPath::follow(IRGenFunction &IGF, - CanType sourceType, Decl *sourceDecl, + LocalTypeDataKey sourceKey, llvm::Value *source, iterator begin, iterator end, Map *cache) { assert(source && "no source metadata value!"); + + // The invariant is that this iterator starts a path from source and + // that sourceKey is correctly describes it. iterator i = begin; - // If there's a cache, look for the entry matching the longest prefix - // of this path. + // Before we begin emitting code to generate the actual path, try to find + // the latest point in the path that we've cached a value for. + + // If the caller gave us a cache to use, check that. This lookup is very + // efficient and doesn't even require us to parse the prefix. if (cache) { auto result = cache->findPrefix(begin, end); if (result.first) { source = *result.first; // If that was the end, there's no more work to do; don't bother - // adjusting the source decl/type. + // adjusting the source key. if (result.second == end) return source; - // Advance sourceDecl/sourceType past the cached prefix. + // Advance the source key past the cached prefix. while (i != result.second) { Component component = *i++; - (void)followComponent(IGF, sourceType, sourceDecl, - /*source*/ nullptr, component); + (void) followComponent(IGF, sourceKey, /*source*/ nullptr, component); + } + } + + // Otherwise, make a pass over the path looking for available concrete + // entries in the IGF's local type data cache. + } else { + auto skipI = i; + LocalTypeDataKey skipKey = sourceKey; + while (skipI != end) { + Component component = *skipI++; + (void) followComponent(IGF, skipKey, /*source*/ nullptr, component); + + // Check the cache for a concrete value. We don't want an abstract + // entry because, if one exists, we'll just end up here again + // recursively. + if (auto skipSource = + IGF.tryGetConcreteLocalTypeData(skipKey.getCachingKey())) { + // If we found one, advance the info for the source to the current + // point in the path, then continue the search. + sourceKey = skipKey; + source = skipSource; + i = skipI; } } } @@ -2647,11 +3170,15 @@ llvm::Value *MetadataPath::follow(IRGenFunction &IGF, // Drill in on the actual source value. while (i != end) { auto component = *i++; - source = followComponent(IGF, sourceType, sourceDecl, source, component); + source = followComponent(IGF, sourceKey, source, component); - // Remember this in the cache at the next position. + // If we have a cache, remember this in the cache at the next position. if (cache) { cache->insertNew(begin, i, source); + + // Otherwise, insert it into the global cache. + } else { + IGF.setScopedLocalTypeData(sourceKey, source); } } @@ -2664,57 +3191,93 @@ llvm::Value *MetadataPath::follow(IRGenFunction &IGF, /// component. Source can be null, in which case this will be the only /// thing done. llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF, - CanType &sourceType, - Decl *&sourceDecl, + LocalTypeDataKey &sourceKey, llvm::Value *source, Component component) { switch (component.getKind()) { case Component::Kind::NominalTypeArgument: { - auto generic = cast(sourceType); + assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata()); + auto generic = cast(sourceKey.Type); auto index = component.getPrimaryIndex(); - if (source) { - source = emitArgumentMetadataRef(IGF, generic->getDecl(), index, source); - } auto subs = generic->getSubstitutions(IGF.IGM.SILMod->getSwiftModule(), nullptr); - sourceType = subs[index].getReplacement()->getCanonicalType(); + sourceKey.Type = subs[index].getReplacement()->getCanonicalType(); + + if (source) { + source = emitArgumentMetadataRef(IGF, generic->getDecl(), index, source); + setTypeMetadataName(IGF.IGM, source, sourceKey.Type); + } return source; } /// Generic type argument protocol conformance. case Component::Kind::NominalTypeArgumentConformance: { - auto generic = cast(sourceType); + assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata()); + auto generic = cast(sourceKey.Type); auto argIndex = component.getPrimaryIndex(); auto confIndex = component.getSecondaryIndex(); - ProtocolDecl *protocol = - generic->getDecl()->getGenericParams()->getAllArchetypes()[argIndex] - ->getConformsTo()[confIndex]; + auto subs = generic->getSubstitutions(IGF.IGM.SILMod->getSwiftModule(), + nullptr); + auto conformance = subs[argIndex].getConformances()[confIndex]; + sourceKey.Type = subs[argIndex].getReplacement()->getCanonicalType(); + sourceKey.Kind = LocalTypeDataKind::forProtocolWitnessTable(conformance); if (source) { + auto protocol = conformance.getRequirement(); source = emitArgumentWitnessTableRef(IGF, generic->getDecl(), argIndex, protocol, source); + setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, protocol); } - - sourceType = CanType(); - sourceDecl = protocol; return source; } case Component::Kind::NominalParent: { + assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata()); NominalTypeDecl *nominalDecl; - if (auto nominal = dyn_cast(sourceType)) { + if (auto nominal = dyn_cast(sourceKey.Type)) { nominalDecl = nominal->getDecl(); - sourceType = nominal.getParent(); + sourceKey.Type = nominal.getParent(); } else { - auto generic = cast(sourceType); + auto generic = cast(sourceKey.Type); nominalDecl = generic->getDecl(); - sourceType = generic.getParent(); + sourceKey.Type = generic.getParent(); } if (source) { source = emitParentMetadataRef(IGF, nominalDecl, source); + setTypeMetadataName(IGF.IGM, source, sourceKey.Type); + } + return source; + } + + case Component::Kind::InheritedProtocol: { + auto conformance = sourceKey.Kind.getProtocolConformance(); + auto protocol = conformance.getRequirement(); + auto inheritedProtocol = + protocol->getInheritedProtocols(nullptr)[component.getPrimaryIndex()]; + + sourceKey.Kind = + LocalTypeDataKind::forAbstractProtocolWitnessTable(inheritedProtocol); + if (conformance.isConcrete()) { + auto inheritedConformance = + conformance.getConcrete()->getInheritedConformance(inheritedProtocol); + if (inheritedConformance) { + sourceKey.Kind = LocalTypeDataKind::forConcreteProtocolWitnessTable( + inheritedConformance); + } + } + + if (source) { + auto &pi = IGF.IGM.getProtocolInfo(protocol); + auto &entry = pi.getWitnessEntry(inheritedProtocol); + assert(entry.isOutOfLineBase()); + source = emitInvariantLoadOfOpaqueWitness(IGF, source, + entry.getOutOfLineBaseIndex()); + source = IGF.Builder.CreateBitCast(source, IGF.IGM.WitnessTablePtrTy); + setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, + inheritedProtocol); } return source; } @@ -2723,7 +3286,7 @@ llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF, llvm_unreachable("following an impossible path!"); } - llvm_unreachable("bad metata path component"); + llvm_unreachable("bad metadata path component"); } /// Collect any required metadata for a witness method from the end of @@ -2752,30 +3315,16 @@ void irgen::emitPolymorphicParameters(IRGenFunction &IGF, EmitPolymorphicParameters(IGF, Fn).emit(in, witnessMetadata, getParameter); } -/// Perform the metadata bindings necessary to emit a generic value witness. -void irgen::emitPolymorphicParametersForGenericValueWitness(IRGenFunction &IGF, - NominalTypeDecl *ntd, - llvm::Value *selfMeta) { - // Nothing to do if the type isn't generic. - if (!ntd->getGenericParamsOfContext()) - return; - - EmitPolymorphicParameters(IGF, ntd).emitForGenericValueWitness(selfMeta); - // Register the 'Self' argument as generic metadata for the type. - IGF.setUnscopedLocalTypeData(ntd->getDeclaredTypeInContext()->getCanonicalType(), - LocalTypeData::forMetatype(), selfMeta); -} - /// Get the next argument and use it as the 'self' type metadata. static void getArgAsLocalSelfTypeMetadata(IRGenFunction &IGF, llvm::Function::arg_iterator &it, CanType abstractType) { - llvm::Value *arg = getArg(it, "Self"); + llvm::Value *arg = &*it++; assert(arg->getType() == IGF.IGM.TypeMetadataPtrTy && "Self argument is not a type?!"); - if (auto ugt = dyn_cast(abstractType)) { - emitPolymorphicParametersForGenericValueWitness(IGF, ugt->getDecl(), arg); - } + + auto formalType = getFormalTypeInContext(abstractType); + IGF.bindLocalTypeDataFromTypeMetadata(formalType, IsExact, arg); } namespace { @@ -2945,14 +3494,13 @@ void NecessaryBindings::save(IRGenFunction &IGF, Address buffer) const { // Find the metatype for the appropriate archetype and store it in // the slot. - llvm::Value *metatype = - IGF.getLocalTypeData(CanType(archetype), LocalTypeData::forMetatype()); + llvm::Value *metatype = IGF.getLocalTypeData(CanType(archetype), + LocalTypeDataKind::forTypeMetadata()); IGF.Builder.CreateStore(metatype, slot); // Find the witness tables for the archetype's protocol constraints and // store them in the slot. - for (unsigned protocolI : indices(archetype->getConformsTo())) { - auto protocol = archetype->getConformsTo()[protocolI]; + for (auto protocol : archetype->getConformsTo()) { if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) continue; Address witnessSlot = IGF.Builder.CreateConstArrayGEP(buffer, metadataI, @@ -2962,7 +3510,7 @@ void NecessaryBindings::save(IRGenFunction &IGF, Address buffer) const { ++metadataI; llvm::Value *witness = IGF.getLocalTypeData(CanType(archetype), - LocalTypeData::forArchetypeProtocolWitness(protocolI)); + LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol)); IGF.Builder.CreateStore(witness, witnessSlot); } } @@ -2989,52 +3537,55 @@ llvm::Value *irgen::emitImpliedWitnessTableRef(IRGenFunction &IGF, /// Emit a protocol witness table for a conformance. llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, CanType srcType, - const TypeInfo &srcTI, + llvm::Value **srcMetadataCache, ProtocolDecl *proto, const ProtocolInfo &protoI, - ProtocolConformance *conformance) { + ProtocolConformanceRef conformance) { assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto) && "protocol does not have witness tables?!"); - // If the source type is an archetype and we don't have concrete conformance - // info, the conformance must be via one of the protocol requirements of the - // archetype. Look at what's locally bound. - if (!conformance) { + // If we don't have concrete conformance information, the type must be + // an archetype and the conformance must be via one of the protocol + // requirements of the archetype. Look at what's locally bound. + if (conformance.isAbstract()) { auto archetype = cast(srcType); - return emitWitnessTableRef(IGF, archetype, proto); + return emitArchetypeWitnessTableRef(IGF, archetype, proto); } - // All other source types should be concrete enough that we have conformance - // info for them. - auto &conformanceI = protoI.getConformance(IGF.IGM, proto, conformance); - return conformanceI.getTable(IGF, srcType); + // All other source types should be concrete enough that we have + // conformance info for them. However, that conformance info might be + // more concrete than we're expecting. + // TODO: make a best effort to devirtualize, maybe? + auto concreteConformance = conformance.getConcrete(); + if (concreteConformance->getProtocol() != proto) { + concreteConformance = concreteConformance->getInheritedConformance(proto); + } + auto &conformanceI = + protoI.getConformance(IGF.IGM, proto, concreteConformance); + return conformanceI.getTable(IGF, srcType, srcMetadataCache); } /// Emit the witness table references required for the given type /// substitution. void irgen::emitWitnessTableRefs(IRGenFunction &IGF, const Substitution &sub, + llvm::Value **metadataCache, SmallVectorImpl &out) { auto conformances = sub.getConformances(); // We don't need to do anything if we have no protocols to conform to. - auto archetypeProtos = sub.getArchetype()->getConformsTo(); - assert(!conformances.size() || archetypeProtos.size() == conformances.size()); - - if (archetypeProtos.empty()) return; + if (conformances.empty()) return; // Look at the replacement type. CanType replType = sub.getReplacement()->getCanonicalType(); - auto &replTI = IGF.getTypeInfoForUnlowered(replType); - for (unsigned j = 0, je = archetypeProtos.size(); j != je; ++j) { - auto proto = archetypeProtos[j]; + for (auto &conformance : conformances) { + auto *proto = conformance.getRequirement(); if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto)) continue; - auto conformance = conformances.size() ? conformances[j] : nullptr; - auto wtable = emitWitnessTableRef(IGF, replType, replTI, proto, - IGF.IGM.getProtocolInfo(proto), + auto wtable = emitWitnessTableRef(IGF, replType, metadataCache, + proto, IGF.IGM.getProtocolInfo(proto), conformance); out.push_back(wtable); @@ -3072,11 +3623,6 @@ namespace { // EmitPolymorphicArguments::emit. case SourceKind::WitnessSelf: continue; - - // The 'Self' argument(s) are added implicitly from ExtraData - // of the function value. - case SourceKind::WitnessExtraData: - continue; } llvm_unreachable("bad source kind!"); } @@ -3146,9 +3692,12 @@ void EmitPolymorphicArguments::emit(CanType substInputType, if (Generics->isConcreteType(depTy, M)) continue; + llvm::Value *argMetadata = nullptr; + // Add the metadata reference unless it's fulfilled. if (!Fulfillments.getTypeMetadata(depTy)) { - out.add(IGF.emitTypeMetadataRef(argType)); + argMetadata = IGF.emitTypeMetadataRef(argType); + out.add(argMetadata); } // Nothing else to do if there aren't any protocols to witness. @@ -3158,8 +3707,6 @@ void EmitPolymorphicArguments::emit(CanType substInputType, if (protocols.empty()) continue; - auto &argTI = IGF.getTypeInfoForUnlowered(argType); - // Add witness tables for each of the required protocols. for (unsigned i = 0, e = protocols.size(); i != e; ++i) { auto protocol = protocols[i]; @@ -3172,12 +3719,10 @@ void EmitPolymorphicArguments::emit(CanType substInputType, if (Fulfillments.getWitnessTable(depTy, protocol)) continue; - auto conformance = conformances.size() ? conformances[i] : nullptr; - auto wtable = emitWitnessTableRef(IGF, - argType, argTI, + auto wtable = emitWitnessTableRef(IGF, argType, &argMetadata, protocol, IGF.IGM.getProtocolInfo(protocol), - conformance); + conformances[i]); out.add(wtable); } } @@ -3202,11 +3747,6 @@ void EmitPolymorphicArguments::emit(CanType substInputType, witnessMetadata->SelfMetadata = self; continue; } - - case SourceKind::WitnessExtraData: - // The 'Self' argument(s) are added implicitly from ExtraData of the - // function value. - continue; } llvm_unreachable("bad source kind"); } @@ -3261,8 +3801,6 @@ namespace { return out.push_back(IGM.TypeMetadataPtrTy); case SourceKind::WitnessSelf: return; // handled as a special case in expand() - case SourceKind::WitnessExtraData: - return; // added implicitly as ExtraData } llvm_unreachable("bad source kind"); } @@ -3294,8 +3832,9 @@ void irgen::expandTrailingWitnessSignature(IRGenModule &IGM, void irgen::emitWitnessMethodValue(IRGenFunction &IGF, CanType baseTy, + llvm::Value **baseMetadataCache, SILDeclRef member, - ProtocolConformance *conformance, + ProtocolConformanceRef conformance, Explosion &out) { auto fn = cast(member.getDecl()); @@ -3304,9 +3843,8 @@ irgen::emitWitnessMethodValue(IRGenFunction &IGF, // Find the witness table. // FIXME conformance for concrete type - auto &baseTI = IGF.getTypeInfoForUnlowered(baseTy); auto &fnProtoInfo = IGF.IGM.getProtocolInfo(fnProto); - llvm::Value *wtable = emitWitnessTableRef(IGF, baseTy, baseTI, + llvm::Value *wtable = emitWitnessTableRef(IGF, baseTy, baseMetadataCache, fnProto, fnProtoInfo, conformance); @@ -3321,3 +3859,76 @@ irgen::emitWitnessMethodValue(IRGenFunction &IGF, // Build the value. out.add(witness); } + +llvm::FunctionType *IRGenModule::getAssociatedTypeMetadataAccessFunctionTy() { + if (AssociatedTypeMetadataAccessFunctionTy) + return AssociatedTypeMetadataAccessFunctionTy; + + auto accessorTy = llvm::FunctionType::get(TypeMetadataPtrTy, + { TypeMetadataPtrTy, + WitnessTablePtrTy }, + /*varargs*/ false); + AssociatedTypeMetadataAccessFunctionTy = accessorTy; + return accessorTy; +} + +llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, + llvm::Value *parentMetadata, + llvm::Value *wtable, + AssociatedTypeDecl *associatedType) { + auto &pi = IGF.IGM.getProtocolInfo(associatedType->getProtocol()); + auto index = pi.getWitnessEntry(associatedType).getAssociatedTypeIndex(); + llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index); + + // Cast the witness to the appropriate function type. + auto witnessTy = IGF.IGM.getAssociatedTypeMetadataAccessFunctionTy(); + witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo()); + + // Call the accessor. + auto call = IGF.Builder.CreateCall(witness, { parentMetadata, wtable }); + call->setDoesNotThrow(); + call->setCallingConv(IGF.IGM.RuntimeCC); + + return call; +} + +llvm::FunctionType * +IRGenModule::getAssociatedTypeWitnessTableAccessFunctionTy() { + if (AssociatedTypeWitnessTableAccessFunctionTy) + return AssociatedTypeWitnessTableAccessFunctionTy; + + // The associated type metadata is passed first so that this function is + // CC-compatible with a conformance's witness table access function. + auto accessorTy = llvm::FunctionType::get(WitnessTablePtrTy, + { TypeMetadataPtrTy, + TypeMetadataPtrTy, + WitnessTablePtrTy }, + /*varargs*/ false); + AssociatedTypeWitnessTableAccessFunctionTy = accessorTy; + return accessorTy; +} + +llvm::Value * +irgen::emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF, + llvm::Value *parentMetadata, + llvm::Value *wtable, + AssociatedTypeDecl *associatedType, + llvm::Value *associatedTypeMetadata, + ProtocolDecl *associatedProtocol) { + auto &pi = IGF.IGM.getProtocolInfo(associatedType->getProtocol()); + auto index = pi.getWitnessEntry(associatedType) + .getAssociatedTypeWitnessTableIndex(associatedProtocol); + llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index); + + // Cast the witness to the appropriate function type. + auto witnessTy = IGF.IGM.getAssociatedTypeWitnessTableAccessFunctionTy(); + witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo()); + + // Call the accessor. + auto call = IGF.Builder.CreateCall(witness, + { associatedTypeMetadata, parentMetadata, wtable }); + call->setDoesNotThrow(); + call->setCallingConv(IGF.IGM.RuntimeCC); + + return call; +} diff --git a/lib/IRGen/GenProto.h b/lib/IRGen/GenProto.h index 44a7eac3562f6..8ea0db32c9fe9 100644 --- a/lib/IRGen/GenProto.h +++ b/lib/IRGen/GenProto.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -24,7 +24,7 @@ namespace llvm { namespace swift { class CanType; class FuncDecl; - class ProtocolConformance; + class ProtocolConformanceRef; struct SILDeclRef; class SILType; class SILFunction; @@ -38,15 +38,52 @@ namespace irgen { class IRGenModule; class ProtocolInfo; class TypeInfo; + + /// Set an LLVM value name for the given type metadata. + void setTypeMetadataName(IRGenModule &IGM, llvm::Value *value, CanType type); + + /// Set an LLVM value name for the given protocol witness table. + void setProtocolWitnessTableName(IRGenModule &IGM, llvm::Value *value, + CanType type, ProtocolDecl *protocol); /// Extract the method pointer from an archetype's witness table /// as a function value. void emitWitnessMethodValue(IRGenFunction &IGF, CanType baseTy, + llvm::Value **baseMetadataCache, SILDeclRef member, - ProtocolConformance *conformance, + ProtocolConformanceRef conformance, Explosion &out); + /// Given a type T and an associated type X of some protocol P to + /// which T conforms, return the type metadata for T.X. + /// + /// \param parentMetadata - the type metadata for T + /// \param wtable - the witness table witnessing the conformance of T to P + /// \param associatedType - the declaration of X; a member of P + llvm::Value *emitAssociatedTypeMetadataRef(IRGenFunction &IGF, + llvm::Value *parentMetadata, + llvm::Value *wtable, + AssociatedTypeDecl *associatedType); + + /// Given a type T and an associated type X of a protocol PT to which + /// T conforms, where X is required to implement some protocol PX, return + /// the witness table witnessing the conformance of T.X to PX. + /// + /// PX must be a direct requirement of X. + /// + /// \param parentMetadata - the type metadata for T + /// \param wtable - the witness table witnessing the conformance of T to PT + /// \param associatedType - the declaration of X; a member of PT + /// \param associatedTypeMetadata - the type metadata for T.X + /// \param associatedProtocol - the declaration of PX + llvm::Value *emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF, + llvm::Value *parentMetadata, + llvm::Value *wtable, + AssociatedTypeDecl *associatedType, + llvm::Value *associatedTypeMetadata, + ProtocolDecl *associatedProtocol); + /// Add the witness parameters necessary for calling a function with /// the given generics clause. void expandPolymorphicSignature(IRGenModule &IGM, @@ -88,11 +125,6 @@ namespace irgen { WitnessMetadata *witnessMetadata, const GetParameterFn &getParameter); - /// Perform the metadata bindings necessary to emit a generic value witness. - void emitPolymorphicParametersForGenericValueWitness(IRGenFunction &IGF, - NominalTypeDecl *ntd, - llvm::Value *selfMeta); - /// Add the trailing arguments necessary for calling a witness method. void emitTrailingWitnessArguments(IRGenFunction &IGF, WitnessMetadata &witnessMetadata, @@ -124,16 +156,18 @@ namespace irgen { /// Emit references to the witness tables for the substituted type /// in the given substitution. - void emitWitnessTableRefs(IRGenFunction &IGF, const Substitution &sub, + void emitWitnessTableRefs(IRGenFunction &IGF, + const Substitution &sub, + llvm::Value **metadataCache, SmallVectorImpl &out); /// Emit a witness table reference. llvm::Value *emitWitnessTableRef(IRGenFunction &IGF, CanType srcType, - const TypeInfo &srcTI, + llvm::Value **srcMetadataCache, ProtocolDecl *proto, const ProtocolInfo &protoI, - ProtocolConformance *conformance); + ProtocolConformanceRef conformance); /// An entry in a list of known protocols. class ProtocolEntry { @@ -155,18 +189,6 @@ namespace irgen { ProtocolDecl *target, const GetWitnessTableFn &getWitnessTable); - /// Allocate space for a value in a value buffer. - Address emitAllocateBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer); - - /// Project to the address of a value in a value buffer. - Address emitProjectBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer); - - /// Deallocate space for a value in a value buffer. - void emitDeallocateBuffer(IRGenFunction &IGF, SILType valueType, - Address buffer); - } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenSequential.h b/lib/IRGen/GenRecord.h similarity index 60% rename from lib/IRGen/GenSequential.h rename to lib/IRGen/GenRecord.h index 49ae9c7648c8a..2cbf60ed8b23c 100644 --- a/lib/IRGen/GenSequential.h +++ b/lib/IRGen/GenRecord.h @@ -1,8 +1,8 @@ -//===--- GenSequential.h - IR generation for sequential types ---*- C++ -*-===// +//===--- GenRecord.h - IR generation for record types -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,13 +10,13 @@ // //===----------------------------------------------------------------------===// // -// This file provides some common code for emitting sequential types. -// A sequential type is something like a tuple or a struct. +// This file provides some common code for emitting record types. +// A record type is something like a tuple or a struct. // //===----------------------------------------------------------------------===// -#ifndef SWIFT_IRGEN_GENSEQUENTIAL_H -#define SWIFT_IRGEN_GENSEQUENTIAL_H +#ifndef SWIFT_IRGEN_GENRECORD_H +#define SWIFT_IRGEN_GENRECORD_H #include "IRGenFunction.h" #include "IRGenModule.h" @@ -29,24 +29,24 @@ namespace swift { namespace irgen { -template class SequentialTypeBuilder; +template class RecordTypeBuilder; -/// A field of a sequential type. -template class SequentialField { +/// A field of a record type. +template class RecordField { ElementLayout Layout; - template friend class SequentialTypeBuilder; + template friend class RecordTypeBuilder; /// Begin/End - the range of explosion indexes for this element unsigned Begin : 16; unsigned End : 16; protected: - explicit SequentialField(const TypeInfo &elementTI) + explicit RecordField(const TypeInfo &elementTI) : Layout(ElementLayout::getIncomplete(elementTI)) {} - explicit SequentialField(const ElementLayout &layout, - unsigned begin, unsigned end) + explicit RecordField(const ElementLayout &layout, + unsigned begin, unsigned end) : Layout(layout), Begin(begin), End(end) {} const FieldImpl *asImpl() const { @@ -85,10 +85,10 @@ template class SequentialField { } }; -/// A metaprogrammed TypeInfo implementation for sequential types. +/// A metaprogrammed TypeInfo implementation for record types. template ::value> -class SequentialTypeInfoImpl : public Base { +class RecordTypeInfoImpl : public Base { public: typedef FieldImpl_ FieldImpl; @@ -106,7 +106,7 @@ class SequentialTypeInfoImpl : public Base { const Impl &asImpl() const { return *static_cast(this); } template - SequentialTypeInfoImpl(ArrayRef fields, As&&...args) + RecordTypeInfoImpl(ArrayRef fields, As&&...args) : Base(std::forward(args)...), NumFields(fields.size()) { std::uninitialized_copy(fields.begin(), fields.end(), getFieldsBuffer()); @@ -162,7 +162,7 @@ class SequentialTypeInfoImpl : public Base { Address dest, Address src, SILType T) const override { // If we're POD, use the generic routine. - if (this->isPOD(ResilienceScope::Component) && + if (this->isPOD(ResilienceExpansion::Maximal) && isa(this)) { return cast(this)-> LoadableTypeInfo::initializeWithCopy(IGF, dest, src, T); @@ -183,7 +183,7 @@ class SequentialTypeInfoImpl : public Base { Address dest, Address src, SILType T) const override { // If we're bitwise-takable, use memcpy. - if (this->isBitwiseTakable(ResilienceScope::Component)) { + if (this->isBitwiseTakable(ResilienceExpansion::Maximal)) { IGF.Builder.CreateMemCpy(dest.getAddress(), src.getAddress(), asImpl().Impl::getSize(IGF, T), std::min(dest.getAlignment(), src.getAlignment()).getValue()); @@ -213,24 +213,189 @@ class SequentialTypeInfoImpl : public Base { }; template ::value, bool IsLoadable = std::is_base_of::value> -class SequentialTypeInfo; +class RecordTypeInfo; -/// An implementation of SequentialTypeInfo for non-loadable types. +/// An implementation of RecordTypeInfo for non-fixed-size types +/// (but not resilient ones where we don't know the complete set of +/// stored properties). +/// +/// Override the buffer operations to just delegate to the unique +/// non-empty field, if there is one. +template +class RecordTypeInfo + : public RecordTypeInfoImpl { + typedef RecordTypeInfoImpl super; + + /// The index+1 of the unique non-empty field, or zero if there is none. + unsigned UniqueNonEmptyFieldIndexPlusOne; +protected: + template + RecordTypeInfo(ArrayRef fields, As&&...args) + : super(fields, std::forward(args)...) { + + // Look for a unique non-empty field. + UniqueNonEmptyFieldIndexPlusOne = findUniqueNonEmptyField(fields); + } + +public: + using super::getStorageType; + Address allocateBuffer(IRGenFunction &IGF, Address buffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + Address address = + field->getTypeInfo().allocateBuffer(IGF, buffer, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(address, getStorageType()); + } else { + return super::allocateBuffer(IGF, buffer, type); + } + } + + Address projectBuffer(IRGenFunction &IGF, Address buffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + Address address = + field->getTypeInfo().projectBuffer(IGF, buffer, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(address, getStorageType()); + } else { + return super::projectBuffer(IGF, buffer, type); + } + } + + void destroyBuffer(IRGenFunction &IGF, Address buffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + field->getTypeInfo().destroyBuffer(IGF, buffer, + field->getType(IGF.IGM, type)); + } else { + super::destroyBuffer(IGF, buffer, type); + } + } + + void deallocateBuffer(IRGenFunction &IGF, Address buffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + field->getTypeInfo().deallocateBuffer(IGF, buffer, + field->getType(IGF.IGM, type)); + } else { + super::deallocateBuffer(IGF, buffer, type); + } + } + + Address initializeBufferWithTake(IRGenFunction &IGF, + Address destBuffer, + Address srcAddr, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + auto &fieldTI = field->getTypeInfo(); + Address srcFieldAddr = + IGF.Builder.CreateElementBitCast(srcAddr, fieldTI.getStorageType()); + Address fieldResult = + fieldTI.initializeBufferWithTake(IGF, destBuffer, srcFieldAddr, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType()); + } else { + return super::initializeBufferWithTake(IGF, destBuffer, srcAddr, type); + } + } + + Address initializeBufferWithCopy(IRGenFunction &IGF, + Address destBuffer, + Address srcAddr, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + auto &fieldTI = field->getTypeInfo(); + Address srcFieldAddr = + IGF.Builder.CreateElementBitCast(srcAddr, fieldTI.getStorageType()); + Address fieldResult = + fieldTI.initializeBufferWithCopy(IGF, destBuffer, srcFieldAddr, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType()); + } else { + return super::initializeBufferWithCopy(IGF, destBuffer, srcAddr, type); + } + } + + Address initializeBufferWithTakeOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + auto &fieldTI = field->getTypeInfo(); + Address fieldResult = + fieldTI.initializeBufferWithTakeOfBuffer(IGF, destBuffer, srcBuffer, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType()); + } else { + return super::initializeBufferWithTakeOfBuffer(IGF, destBuffer, + srcBuffer, type); + } + } + + Address initializeBufferWithCopyOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType type) const override { + if (auto field = getUniqueNonEmptyField()) { + auto &fieldTI = field->getTypeInfo(); + Address fieldResult = + fieldTI.initializeBufferWithCopyOfBuffer(IGF, destBuffer, srcBuffer, + field->getType(IGF.IGM, type)); + return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType()); + } else { + return super::initializeBufferWithCopyOfBuffer(IGF, destBuffer, + srcBuffer, type); + } + } + +private: + /// Scan the given field info + static unsigned findUniqueNonEmptyField(ArrayRef fields) { + unsigned result = 0; + for (auto &field : fields) { + // Ignore empty fields. + if (field.isEmpty()) continue; + + // If we've already found an index, then there isn't a + // unique non-empty field. + if (result) return 0; + + result = (&field - fields.data()) + 1; + } + + return result; + } + + const FieldImpl *getUniqueNonEmptyField() const { + if (UniqueNonEmptyFieldIndexPlusOne) { + return &this->getFields()[UniqueNonEmptyFieldIndexPlusOne - 1]; + } else { + return nullptr; + } + } +}; + +/// An implementation of RecordTypeInfo for non-loadable types. template -class SequentialTypeInfo - : public SequentialTypeInfoImpl { - typedef SequentialTypeInfoImpl super; +class RecordTypeInfo + : public RecordTypeInfoImpl { + typedef RecordTypeInfoImpl super; protected: template - SequentialTypeInfo(As&&...args) : super(std::forward(args)...) {} + RecordTypeInfo(As&&...args) : super(std::forward(args)...) {} }; -/// An implementation of SequentialTypeInfo for loadable types. +/// An implementation of RecordTypeInfo for loadable types. template -class SequentialTypeInfo - : public SequentialTypeInfoImpl { - typedef SequentialTypeInfoImpl super; +class RecordTypeInfo + : public RecordTypeInfoImpl { + typedef RecordTypeInfoImpl super; unsigned ExplosionSize : 16; @@ -238,8 +403,8 @@ class SequentialTypeInfo using super::asImpl; template - SequentialTypeInfo(ArrayRef fields, unsigned explosionSize, - As &&...args) + RecordTypeInfo(ArrayRef fields, unsigned explosionSize, + As &&...args) : super(fields, std::forward(args)...), ExplosionSize(explosionSize) {} @@ -346,7 +511,7 @@ class SequentialTypeInfo } }; -/// A builder of sequential types. +/// A builder of record types. /// /// Required for a full implementation: /// TypeInfoImpl *construct(void *buffer, ArrayRef fields); @@ -355,10 +520,10 @@ class SequentialTypeInfo /// void performLayout(ArrayRef fieldTypes); /// - should call recordLayout with the layout template -class SequentialTypeBuilder { +class RecordTypeBuilder { protected: IRGenModule &IGM; - SequentialTypeBuilder(IRGenModule &IGM) : IGM(IGM) {} + RecordTypeBuilder(IRGenModule &IGM) : IGM(IGM) {} BuilderImpl *asImpl() { return static_cast(this); } diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index e53a7c35acce9..ededb83349b97 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,7 +28,7 @@ #include "clang/AST/RecordLayout.h" #include "GenMeta.h" -#include "GenSequential.h" +#include "GenRecord.h" #include "GenType.h" #include "IRGenFunction.h" #include "IRGenModule.h" @@ -57,10 +57,10 @@ static StructTypeInfoKind getStructTypeInfoKind(const TypeInfo &type) { } namespace { - class StructFieldInfo : public SequentialField { + class StructFieldInfo : public RecordField { public: StructFieldInfo(VarDecl *field, const TypeInfo &type) - : SequentialField(type), Field(field) {} + : RecordField(type), Field(field) {} /// The field. VarDecl * const Field; @@ -75,11 +75,11 @@ namespace { }; /// A field-info implementation for fields of Clang types. - class ClangFieldInfo : public SequentialField { + class ClangFieldInfo : public RecordField { public: ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout, unsigned explosionBegin, unsigned explosionEnd) - : SequentialField(layout, explosionBegin, explosionEnd), + : RecordField(layout, explosionBegin, explosionEnd), Field(swiftField) {} VarDecl * const Field; @@ -102,8 +102,8 @@ namespace { /// A common base class for structs. template class StructTypeInfoBase : - public SequentialTypeInfo { - typedef SequentialTypeInfo super; + public RecordTypeInfo { + typedef RecordTypeInfo super; protected: template @@ -200,7 +200,7 @@ namespace { = cast(asImpl().getFields()[0].getTypeInfo()); auto targetSize = asImpl().getFixedSize().getValueInBits(); - if (fieldTI.isKnownEmpty()) + if (fieldTI.isKnownEmpty(ResilienceExpansion::Maximal)) return APInt(targetSize, 0); APInt fieldMask = fieldTI.getFixedExtraInhabitantMask(IGM); @@ -415,6 +415,8 @@ namespace { llvm::ArrayType::get(IGF.IGM.Int8PtrPtrTy, storedProperties.size()), IGF.IGM.getPointerAlignment(), "structFields"); + IGF.Builder.CreateLifetimeStart(fields, + IGF.IGM.getPointerSize() * storedProperties.size()); fields = IGF.Builder.CreateStructGEP(fields, 0, Size(0)); unsigned index = 0; @@ -433,18 +435,20 @@ namespace { IGF.Builder.CreateCall(IGF.IGM.getInitStructMetadataUniversalFn(), {numFields, fields.getAddress(), fieldVector, vwtable}); + IGF.Builder.CreateLifetimeEnd(fields, + IGF.IGM.getPointerSize() * storedProperties.size()); } }; class StructTypeBuilder : - public SequentialTypeBuilder { + public RecordTypeBuilder { llvm::StructType *StructTy; CanType TheStruct; public: StructTypeBuilder(IRGenModule &IGM, llvm::StructType *structTy, CanType type) : - SequentialTypeBuilder(IGM), StructTy(structTy), TheStruct(type) { + RecordTypeBuilder(IGM), StructTy(structTy), TheStruct(type) { } LoadableStructTypeInfo *createLoadable(ArrayRef fields, @@ -683,7 +687,7 @@ class ClangRecordLowering { unsigned explosionEnd = NextExplosionIndex; ElementLayout layout = ElementLayout::getIncomplete(fieldType); - layout.completeFixed(fieldType.isPOD(ResilienceScope::Component), + layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal), NextOffset, LLVMFields.size()); FieldInfos.push_back( @@ -775,7 +779,7 @@ const TypeInfo *TypeConverter::convertStructType(TypeBase *key, CanType type, StructDecl *D) { // All resilient structs have the same opaque lowering, since they are // indistinguishable as values. - if (IGM.isResilient(D, ResilienceScope::Component)) + if (IGM.isResilient(D, ResilienceExpansion::Maximal)) return &getResilientStructTypeInfo(); // Create the struct type. diff --git a/lib/IRGen/GenStruct.h b/lib/IRGen/GenStruct.h index 720e64dc8580e..70ea121333c3f 100644 --- a/lib/IRGen/GenStruct.h +++ b/lib/IRGen/GenStruct.h @@ -1,8 +1,8 @@ -//===--- GenStruct.h - Swift IR generation for structs ------------*- C++ -*-===// +//===--- GenStruct.h - Swift IR generation for structs ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp index 90ae84dcaca66..2d66368388460 100644 --- a/lib/IRGen/GenTuple.cpp +++ b/lib/IRGen/GenTuple.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// // // This file implements IR generation for tuple types in Swift. This -// includes creating the IR type as well as emitting the primitive access +// includes creating the IR type as well as emitting the primitive access // operations. // // It is assumed in several places in IR-generation that the @@ -27,7 +27,7 @@ #include "llvm/IR/DerivedTypes.h" #include "GenHeap.h" -#include "GenSequential.h" +#include "GenRecord.h" #include "GenType.h" #include "IRGenFunction.h" #include "IRGenModule.h" @@ -43,10 +43,10 @@ using namespace swift; using namespace irgen; namespace { - class TupleFieldInfo : public SequentialField { + class TupleFieldInfo : public RecordField { public: TupleFieldInfo(unsigned index, StringRef name, const TypeInfo &type) - : SequentialField(type), Index(index), Name(name) + : RecordField(type), Index(index), Name(name) {} /// The field index. @@ -71,8 +71,8 @@ namespace { /// Adapter for tuple types. template class TupleTypeInfoBase - : public SequentialTypeInfo { - typedef SequentialTypeInfo super; + : public RecordTypeInfo { + typedef RecordTypeInfo super; protected: template @@ -149,7 +149,7 @@ namespace { = cast(asImpl().getFields()[0].getTypeInfo()); auto size = asImpl().getFixedSize().getValueInBits(); - if (fieldTI.isKnownEmpty()) + if (fieldTI.isKnownEmpty(ResilienceExpansion::Maximal)) return APInt(size, 0); APInt firstMask = fieldTI.getFixedExtraInhabitantMask(IGM); @@ -283,13 +283,13 @@ namespace { }; class TupleTypeBuilder : - public SequentialTypeBuilder { + public RecordTypeBuilder { SILType TheTuple; public: TupleTypeBuilder(IRGenModule &IGM, SILType theTuple) - : SequentialTypeBuilder(IGM), TheTuple(theTuple) {} + : RecordTypeBuilder(IGM), TheTuple(theTuple) {} FixedTupleTypeInfo *createFixed(ArrayRef fields, StructLayout &&layout) { diff --git a/lib/IRGen/GenTuple.h b/lib/IRGen/GenTuple.h index a2a5dad7f655b..9627cb767e236 100644 --- a/lib/IRGen/GenTuple.h +++ b/lib/IRGen/GenTuple.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 35fb3cca2b923..ca4a22d55b992 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1,8 +1,8 @@ -//===--- GenTypes.cpp - Swift IR Generation For Types ---------------------===// +//===--- GenType.cpp - Swift IR Generation For Types ----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,26 +50,25 @@ TypeConverter::Types_t::getCacheFor(TypeBase *t) { return t->hasTypeParameter() ? DependentCache : IndependentCache; } -Address TypeInfo::initializeBufferWithTake(IRGenFunction &IGF, - Address destBuffer, - Address srcAddr, - SILType T) const { - Address destAddr = emitAllocateBuffer(IGF, T, destBuffer); - initializeWithTake(IGF, destAddr, srcAddr, T); - return destAddr; +void TypeInfo:: assign(IRGenFunction &IGF, Address dest, Address src, + IsTake_t isTake, SILType T) const { + if (isTake) { + assignWithTake(IGF, dest, src, T); + } else { + assignWithCopy(IGF, dest, src, T); + } } -Address TypeInfo::initializeBufferWithCopy(IRGenFunction &IGF, - Address destBuffer, - Address srcAddr, - SILType T) const { - Address destAddr = emitAllocateBuffer(IGF, T, destBuffer); - initializeWithCopy(IGF, destAddr, srcAddr, T); - return destAddr; +void TypeInfo::initialize(IRGenFunction &IGF, Address dest, Address src, + IsTake_t isTake, SILType T) const { + if (isTake) { + initializeWithTake(IGF, dest, src, T); + } else { + initializeWithCopy(IGF, dest, src, T); + } } - -bool TypeInfo::isSingleRetainablePointer(ResilienceScope scope, +bool TypeInfo::isSingleRetainablePointer(ResilienceExpansion expansion, ReferenceCounting *refcounting) const { return false; } @@ -137,7 +136,7 @@ Address TypeInfo::indexArray(IRGenFunction &IGF, Address base, void TypeInfo::destroyArray(IRGenFunction &IGF, Address array, llvm::Value *count, SILType T) const { - if (isPOD(ResilienceScope::Component)) + if (isPOD(ResilienceExpansion::Maximal)) return; auto entry = IGF.Builder.GetInsertBlock(); @@ -152,12 +151,14 @@ void TypeInfo::destroyArray(IRGenFunction &IGF, Address array, auto elementVal = IGF.Builder.CreatePHI(array.getType(), 2); elementVal->addIncoming(array.getAddress(), entry); Address element(elementVal, array.getAlignment()); - + auto done = IGF.Builder.CreateICmpEQ(counter, llvm::ConstantInt::get(IGF.IGM.SizeTy, 0)); IGF.Builder.CreateCondBr(done, exit, loop); IGF.Builder.emitBlock(loop); + ConditionalDominanceScope condition(IGF); + destroy(IGF, element, T); auto nextCounter = IGF.Builder.CreateSub(counter, llvm::ConstantInt::get(IGF.IGM.SizeTy, 1)); @@ -196,16 +197,14 @@ void irgen::emitInitializeArrayFrontToBack(IRGenFunction &IGF, srcVal->addIncoming(srcArray.getAddress(), entry); Address dest(destVal, destArray.getAlignment()); Address src(srcVal, srcArray.getAlignment()); - + auto done = IGF.Builder.CreateICmpEQ(counter, llvm::ConstantInt::get(IGM.SizeTy, 0)); IGF.Builder.CreateCondBr(done, exit, loop); IGF.Builder.emitBlock(loop); - if (take) - type.initializeWithTake(IGF, dest, src, T); - else - type.initializeWithCopy(IGF, dest, src, T); + ConditionalDominanceScope condition(IGF); + type.initialize(IGF, dest, src, take, T); auto nextCounter = IGF.Builder.CreateSub(counter, llvm::ConstantInt::get(IGM.SizeTy, 1)); @@ -250,21 +249,19 @@ void irgen::emitInitializeArrayBackToFront(IRGenFunction &IGF, srcVal->addIncoming(srcEnd.getAddress(), entry); Address dest(destVal, destArray.getAlignment()); Address src(srcVal, srcArray.getAlignment()); - + auto done = IGF.Builder.CreateICmpEQ(counter, llvm::ConstantInt::get(IGM.SizeTy, 0)); IGF.Builder.CreateCondBr(done, exit, loop); IGF.Builder.emitBlock(loop); + ConditionalDominanceScope condition(IGF); auto prevDest = type.indexArray(IGF, dest, llvm::ConstantInt::getSigned(IGM.SizeTy, -1), T); auto prevSrc = type.indexArray(IGF, src, llvm::ConstantInt::getSigned(IGM.SizeTy, -1), T); - if (take) - type.initializeWithTake(IGF, prevDest, prevSrc, T); - else - type.initializeWithCopy(IGF, prevDest, prevSrc, T); + type.initialize(IGF, prevDest, prevSrc, take, T); auto nextCounter = IGF.Builder.CreateSub(counter, llvm::ConstantInt::get(IGM.SizeTy, 1)); @@ -280,7 +277,7 @@ void irgen::emitInitializeArrayBackToFront(IRGenFunction &IGF, void TypeInfo::initializeArrayWithCopy(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const { - if (isPOD(ResilienceScope::Component)) { + if (isPOD(ResilienceExpansion::Maximal)) { llvm::Value *stride = getStride(IGF, T); llvm::Value *byteCount = IGF.Builder.CreateNUWMul(stride, count); IGF.Builder.CreateMemCpy(dest.getAddress(), src.getAddress(), @@ -295,7 +292,7 @@ void TypeInfo::initializeArrayWithTakeFrontToBack(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const { - if (isBitwiseTakable(ResilienceScope::Component)) { + if (isBitwiseTakable(ResilienceExpansion::Maximal)) { llvm::Value *stride = getStride(IGF, T); llvm::Value *byteCount = IGF.Builder.CreateNUWMul(stride, count); IGF.Builder.CreateMemMove(dest.getAddress(), src.getAddress(), @@ -310,7 +307,7 @@ void TypeInfo::initializeArrayWithTakeBackToFront(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const { - if (isBitwiseTakable(ResilienceScope::Component)) { + if (isBitwiseTakable(ResilienceExpansion::Maximal)) { llvm::Value *stride = getStride(IGF, T); llvm::Value *byteCount = IGF.Builder.CreateNUWMul(stride, count); IGF.Builder.CreateMemMove(dest.getAddress(), src.getAddress(), @@ -338,9 +335,9 @@ Address TypeInfo::getUndefAddress() const { } /// Whether this type is known to be empty. -bool TypeInfo::isKnownEmpty() const { +bool TypeInfo::isKnownEmpty(ResilienceExpansion expansion) const { if (auto fixed = dyn_cast(this)) - return fixed->isKnownEmpty(); + return fixed->isKnownEmpty(expansion); return false; } @@ -351,7 +348,7 @@ void FixedTypeInfo::initializeWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr, SILType T) const { - assert(isBitwiseTakable(ResilienceScope::Component) + assert(isBitwiseTakable(ResilienceExpansion::Maximal) && "non-bitwise-takable type must override default initializeWithTake"); // Prefer loads and stores if we won't make a million of them. @@ -376,7 +373,7 @@ void LoadableTypeInfo::initializeWithCopy(IRGenFunction &IGF, Address srcAddr, SILType T) const { // Use memcpy if that's legal. - if (isPOD(ResilienceScope::Component)) { + if (isPOD(ResilienceExpansion::Maximal)) { return initializeWithTake(IGF, destAddr, srcAddr, T); } @@ -433,7 +430,7 @@ llvm::Value *FixedTypeInfo::getStride(IRGenFunction &IGF, SILType T) const { } llvm::Value *FixedTypeInfo::getIsPOD(IRGenFunction &IGF, SILType T) const { return llvm::ConstantInt::get(IGF.IGM.Int1Ty, - isPOD(ResilienceScope::Component) == IsPOD); + isPOD(ResilienceExpansion::Maximal) == IsPOD); } llvm::Constant *FixedTypeInfo::getStaticStride(IRGenModule &IGM) const { return asSizeConstant(IGM, getFixedStride()); @@ -536,6 +533,7 @@ FixedTypeInfo::getSpareBitExtraInhabitantIndex(IRGenFunction &IGF, IGF.Builder.CreateCondBr(isValid, endBB, spareBB); IGF.Builder.emitBlock(spareBB); + ConditionalDominanceScope condition(IGF); // Gather the occupied bits. auto OccupiedBits = SpareBits; @@ -862,7 +860,10 @@ void TypeConverter::popGenericContext(CanGenericSignature signature) { } ArchetypeBuilder &TypeConverter::getArchetypes() { - return IGM.SILMod->Types.getArchetypes(); + auto moduleDecl = IGM.SILMod->getSwiftModule(); + auto genericSig = IGM.SILMod->Types.getCurGenericContext(); + return *moduleDecl->getASTContext() + .getOrCreateArchetypeBuilder(genericSig, moduleDecl); } ArchetypeBuilder &IRGenModule::getContextArchetypes() { @@ -1626,7 +1627,8 @@ namespace { // If the type isn't actually dependent, we're okay. bool visit(CanType type) { - if (!type->hasArchetype()) return false; + if (!type->hasArchetype() && !type->hasTypeParameter()) + return false; return CanTypeVisitor::visit(type); } @@ -1639,11 +1641,11 @@ namespace { return visitStructDecl(type->getDecl()); } bool visitStructDecl(StructDecl *decl) { - if (IGM.isResilient(decl, ResilienceScope::Component)) + if (IGM.isResilient(decl, ResilienceExpansion::Maximal)) return true; for (auto field : decl->getStoredProperties()) { - if (visit(field->getType()->getCanonicalType())) + if (visit(field->getInterfaceType()->getCanonicalType())) return true; } return false; @@ -1658,7 +1660,7 @@ namespace { return visitEnumDecl(type->getDecl()); } bool visitEnumDecl(EnumDecl *decl) { - if (IGM.isResilient(decl, ResilienceScope::Component)) + if (IGM.isResilient(decl, ResilienceExpansion::Maximal)) return true; if (decl->isIndirect()) return false; @@ -1666,7 +1668,7 @@ namespace { for (auto elt : decl->getAllElements()) { if (elt->hasArgumentType() && !elt->isIndirect() && - visit(elt->getArgumentType()->getCanonicalType())) + visit(elt->getArgumentInterfaceType()->getCanonicalType())) return true; } return false; @@ -1685,7 +1687,9 @@ namespace { // The IR-generation for function types is specifically not // type-dependent. - bool visitAnyFunctionType(CanAnyFunctionType type) { return false; } + bool visitAnyFunctionType(CanAnyFunctionType type) { + return false; + } // The safe default for a dependent type is to assume that it // needs its own implementation. @@ -1699,11 +1703,11 @@ static bool isIRTypeDependent(IRGenModule &IGM, NominalTypeDecl *decl) { assert(!isa(decl)); if (isa(decl)) { return false; - } else if (auto sd = dyn_cast(decl)) { - return IsIRTypeDependent(IGM).visitStructDecl(sd); + } else if (auto structDecl = dyn_cast(decl)) { + return IsIRTypeDependent(IGM).visitStructDecl(structDecl); } else { - auto ed = cast(decl); - return IsIRTypeDependent(IGM).visitEnumDecl(ed); + auto enumDecl = cast(decl); + return IsIRTypeDependent(IGM).visitEnumDecl(enumDecl); } } @@ -1911,17 +1915,17 @@ llvm::PointerType *IRGenModule::requiresIndirectResult(SILType type) { } /// Determine whether this type is known to be POD. -bool IRGenModule::isPOD(SILType type, ResilienceScope scope) { +bool IRGenModule::isPOD(SILType type, ResilienceExpansion expansion) { if (type.is()) return false; if (type.is()) return false; if (type.is()) return false; if (auto tuple = type.getAs()) { for (auto index : indices(tuple.getElementTypes())) - if (!isPOD(type.getTupleElementType(index), scope)) + if (!isPOD(type.getTupleElementType(index), expansion)) return false; return true; } - return getTypeInfo(type).isPOD(scope); + return getTypeInfo(type).isPOD(expansion); } @@ -2014,14 +2018,18 @@ bool TypeConverter::isExemplarArchetype(ArchetypeType *arch) const { } #endif -SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, - SILType t, ResilienceScope scope){ +SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, SILType t, + ResilienceExpansion expansion) { if (auto tuple = t.getAs()) if (tuple->getNumElements() == 1) return t.getTupleElementType(0); - // TODO: Consider resilience for structs and enums. if (auto structDecl = t.getStructOrBoundGenericStruct()) { + // If the struct has to be accessed resiliently from this resilience domain, + // we can't assume anything about its layout. + if (IGM.isResilient(structDecl, expansion)) + return SILType(); + // C ABI wackiness may cause a single-field struct to have different layout // from its field. if (structDecl->hasUnreferenceableStorage() @@ -2039,6 +2047,11 @@ SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, } if (auto enumDecl = t.getEnumOrBoundGenericEnum()) { + // If the enum has to be accessed resiliently from this resilience domain, + // we can't assume anything about its layout. + if (IGM.isResilient(enumDecl, expansion)) + return SILType(); + auto allCases = enumDecl->getAllElements(); auto theCase = allCases.begin(); diff --git a/lib/IRGen/GenType.h b/lib/IRGen/GenType.h index ef698a734f544..25a4478595595 100644 --- a/lib/IRGen/GenType.h +++ b/lib/IRGen/GenType.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -204,8 +204,8 @@ class TypeConverter { friend void TypeConverter::popGenericContext(CanGenericSignature signature); #ifndef NDEBUG - friend CanType TypeConverter::getTypeThatLoweredTo(llvm::Type *) const; - friend bool TypeConverter::isExemplarArchetype(ArchetypeType *) const; + friend CanType TypeConverter::getTypeThatLoweredTo(llvm::Type *t) const; + friend bool TypeConverter::isExemplarArchetype(ArchetypeType *arch) const; #endif }; Types_t Types; @@ -259,7 +259,7 @@ void emitInitializeArrayBackToFront(IRGenFunction &IGF, /// type of its field, which it is guaranteed to have identical layout to. SILType getSingletonAggregateFieldType(IRGenModule &IGM, SILType t, - ResilienceScope scope); + ResilienceExpansion expansion); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/HeapTypeInfo.h b/lib/IRGen/HeapTypeInfo.h index a257be578def5..8937bca076e82 100644 --- a/lib/IRGen/HeapTypeInfo.h +++ b/lib/IRGen/HeapTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -61,14 +61,14 @@ class HeapTypeInfo : public SingleScalarTypeInfo { Alignment align) : super(storage, size, spareBits, align) {} - bool isSingleRetainablePointer(ResilienceScope scope, + bool isSingleRetainablePointer(ResilienceExpansion expansion, ReferenceCounting *refcounting) const override { if(refcounting) *refcounting = asDerived().getReferenceCounting(); return true; } - IsaEncoding getIsaEncoding(ResilienceScope scope) const { + IsaEncoding getIsaEncoding(ResilienceExpansion expansion) const { switch (asDerived().getReferenceCounting()) { // We can access the isa of pure Swift heap objects directly. case ReferenceCounting::Native: diff --git a/lib/IRGen/IRBuilder.h b/lib/IRGen/IRBuilder.h index 46cfd9a3f3abe..93c12513359aa 100644 --- a/lib/IRGen/IRBuilder.h +++ b/lib/IRGen/IRBuilder.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -200,6 +200,19 @@ class IRBuilder : public IRBuilderBase { return Address(addr, address.getAlignment()); } + /// Cast the given address to be a pointer to the given element type, + /// preserving the original address space. + Address CreateElementBitCast(Address address, llvm::Type *type, + const llvm::Twine &name = "") { + // Do nothing if the type doesn't change. + auto origPtrType = address.getType(); + if (origPtrType->getElementType() == type) return address; + + // Otherwise, cast to a pointer to the correct type. + auto ptrType = type->getPointerTo(origPtrType->getAddressSpace()); + return CreateBitCast(address, ptrType, name); + } + /// Insert the given basic block after the IP block and move the /// insertion point to it. Only valid if the IP is valid. void emitBlock(llvm::BasicBlock *BB); @@ -211,6 +224,18 @@ class IRBuilder : public IRBuilderBase { std::min(dest.getAlignment(), src.getAlignment()).getValue()); } + + using IRBuilderBase::CreateLifetimeStart; + llvm::CallInst *CreateLifetimeStart(Address buf, Size size) { + return CreateLifetimeStart(buf.getAddress(), + llvm::ConstantInt::get(Context, APInt(64, size.getValue()))); + } + + using IRBuilderBase::CreateLifetimeEnd; + llvm::CallInst *CreateLifetimeEnd(Address buf, Size size) { + return CreateLifetimeEnd(buf.getAddress(), + llvm::ConstantInt::get(Context, APInt(64, size.getValue()))); + } }; } // end namespace irgen diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 50744f9ea156a..4cb561692e718 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,6 +23,7 @@ #include "swift/SIL/SILModule.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/Platform.h" +#include "swift/Basic/Timer.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/LLVMPasses/PassesFwd.h" #include "swift/LLVMPasses/Passes.h" @@ -116,6 +117,8 @@ void setModuleFlags(IRGenModule &IGM) { void swift::performLLVMOptimizations(IRGenOptions &Opts, llvm::Module *Module, llvm::TargetMachine *TargetMachine) { + SharedTimer timer("LLVM optimization"); + // Set up a pipeline. PassManagerBuilder PMBuilder; @@ -124,6 +127,7 @@ void swift::performLLVMOptimizations(IRGenOptions &Opts, llvm::Module *Module, PMBuilder.Inliner = llvm::createFunctionInliningPass(200); PMBuilder.SLPVectorize = true; PMBuilder.LoopVectorize = true; + PMBuilder.MergeFunctions = true; } else { PMBuilder.OptLevel = 0; if (!Opts.DisableLLVMOptzns) @@ -277,7 +281,10 @@ static bool performLLVM(IRGenOptions &Opts, DiagnosticEngine &Diags, } } - EmitPasses.run(*Module); + { + SharedTimer timer("LLVM output"); + EmitPasses.run(*Module); + } return false; } @@ -408,68 +415,72 @@ static std::unique_ptr performIRGeneration(IRGenOptions &Opts, initLLVMModule(IGM); - // Emit the module contents. - dispatcher.emitGlobalTopLevel(); + { + SharedTimer timer("IRGen"); + // Emit the module contents. + dispatcher.emitGlobalTopLevel(); - if (SF) { - IGM.emitSourceFile(*SF, StartElem); - } else { - assert(StartElem == 0 && "no explicit source file provided"); - for (auto *File : M->getFiles()) { - if (auto *nextSF = dyn_cast(File)) { - if (nextSF->ASTStage >= SourceFile::TypeChecked) - IGM.emitSourceFile(*nextSF, 0); - } else { - File->collectLinkLibraries([&IGM](LinkLibrary LinkLib) { - IGM.addLinkLibrary(LinkLib); - }); + if (SF) { + IGM.emitSourceFile(*SF, StartElem); + } else { + assert(StartElem == 0 && "no explicit source file provided"); + for (auto *File : M->getFiles()) { + if (auto *nextSF = dyn_cast(File)) { + if (nextSF->ASTStage >= SourceFile::TypeChecked) + IGM.emitSourceFile(*nextSF, 0); + } else { + File->collectLinkLibraries([&IGM](LinkLibrary LinkLib) { + IGM.addLinkLibrary(LinkLib); + }); + } } } - } - // Register our info with the runtime if needed. - if (Opts.UseJIT) { - IGM.emitRuntimeRegistration(); - } else { - // Emit protocol conformances into a section we can recognize at runtime. - // In JIT mode these are manually registered above. - IGM.emitProtocolConformances(); - } + // Register our info with the runtime if needed. + if (Opts.UseJIT) { + IGM.emitRuntimeRegistration(); + } else { + // Emit protocol conformances into a section we can recognize at runtime. + // In JIT mode these are manually registered above. + IGM.emitProtocolConformances(); + IGM.emitTypeMetadataRecords(); + } - // Okay, emit any definitions that we suddenly need. - dispatcher.emitLazyDefinitions(); + // Okay, emit any definitions that we suddenly need. + dispatcher.emitLazyDefinitions(); - // Emit symbols for eliminated dead methods. - IGM.emitVTableStubs(); + // Emit symbols for eliminated dead methods. + IGM.emitVTableStubs(); - // Verify type layout if we were asked to. - if (!Opts.VerifyTypeLayoutNames.empty()) - IGM.emitTypeVerifier(); + // Verify type layout if we were asked to. + if (!Opts.VerifyTypeLayoutNames.empty()) + IGM.emitTypeVerifier(); - std::for_each(Opts.LinkLibraries.begin(), Opts.LinkLibraries.end(), - [&](LinkLibrary linkLib) { - IGM.addLinkLibrary(linkLib); - }); + std::for_each(Opts.LinkLibraries.begin(), Opts.LinkLibraries.end(), + [&](LinkLibrary linkLib) { + IGM.addLinkLibrary(linkLib); + }); - // Hack to handle thunks eagerly synthesized by the Clang importer. - swift::Module *prev = nullptr; - for (auto external : Ctx.ExternalDefinitions) { - swift::Module *next = external->getModuleContext(); - if (next == prev) - continue; - prev = next; + // Hack to handle thunks eagerly synthesized by the Clang importer. + swift::Module *prev = nullptr; + for (auto external : Ctx.ExternalDefinitions) { + swift::Module *next = external->getModuleContext(); + if (next == prev) + continue; + prev = next; - if (next->getName() == M->getName()) - continue; + if (next->getName() == M->getName()) + continue; - next->collectLinkLibraries([&](LinkLibrary linkLib) { - IGM.addLinkLibrary(linkLib); - }); - } + next->collectLinkLibraries([&](LinkLibrary linkLib) { + IGM.addLinkLibrary(linkLib); + }); + } - IGM.finalize(); + IGM.finalize(); - setModuleFlags(IGM); + setModuleFlags(IGM); + } // Bail out if there are any errors. if (Ctx.hadError()) return nullptr; @@ -655,7 +666,7 @@ static void performParallelIRGeneration(IRGenOptions &Opts, std::vector Threads; llvm::sys::Mutex DiagMutex; - // Start all the threads an do the LLVM compilation. + // Start all the threads and do the LLVM compilation. for (int ThreadIdx = 1; ThreadIdx < numThreads; ++ThreadIdx) { Threads.push_back(std::thread(ThreadEntryPoint, &dispatcher, &DiagMutex, ThreadIdx)); diff --git a/lib/IRGen/IRGen.h b/lib/IRGen/IRGen.h index 50fd9d926a9d9..46b23173c6a3b 100644 --- a/lib/IRGen/IRGen.h +++ b/lib/IRGen/IRGen.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -136,27 +136,11 @@ enum class ExtraData : unsigned char { Last_ExtraData = Block }; -/// ResilienceScope - The compiler is often able to pursue -/// optimizations based on its knowledge of the implementation of some -/// language structure. However, optimizations which affect -/// cross-component interfaces are not necessarily sound in the face -/// of differing compiler versions and API changes that make types -/// fragile. The "resilience scope" is the breadth of the code -/// affected by the answer to a question being asked. -/// -/// TODO: maybe deployment versions should factor in here. If a -/// question is being asked vis-a-vis the implementation of a subject -/// structure that is unavailable in any revision for which the object -/// structure is resilient, is there any reason not to answer as if -/// the subject structure were universally fragile? -enum class ResilienceScope { - /// Component scope means the decision has to be consistent within - /// the current component only. - Component, - - /// Universal scope means that the decision has to be consistent - /// across all possible clients who could see this declaration. - Universal +/// Given that we have metadata for a type, is it for exactly the +/// specified type, or might it be a subtype? +enum IsExact_t : bool { + IsInexact = false, + IsExact = true }; /// Destructor variants. diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index acd608f66c528..4228c80632211 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1,8 +1,8 @@ -//===--- IRGenDebugInfo.h - Debug Info Support-----------------------------===// +//===--- IRGenDebugInfo.cpp - Debug Info Support --------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -128,7 +128,7 @@ IRGenDebugInfo::IRGenDebugInfo(const IRGenOptions &Opts, StringRef Flags = Opts.DWARFDebugFlags; unsigned Major, Minor; std::tie(Major, Minor) = version::getSwiftNumericVersion(); - unsigned RuntimeVersion = Major*100 + Minor; + unsigned MajorRuntimeVersion = Major; // No split DWARF on Darwin. StringRef SplitName = StringRef(); @@ -136,7 +136,7 @@ IRGenDebugInfo::IRGenDebugInfo(const IRGenOptions &Opts, // Clang is doing the same thing here. TheCU = DBuilder.createCompileUnit( Lang, AbsMainFile, Opts.DebugCompilationDir, Producer, IsOptimized, - Flags, RuntimeVersion, SplitName, + Flags, MajorRuntimeVersion, SplitName, Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables ? llvm::DIBuilder::LineTablesOnly : llvm::DIBuilder::FullDebug); @@ -553,15 +553,21 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateContext(DeclContext *DC) { if (!DC) return TheCU; + if (isa(DC)) + if (auto *Decl = IGM.SILMod->lookUpFunction( + SILDeclRef(cast(DC), SILDeclRef::Kind::Func))) + return getOrCreateScope(Decl->getDebugScope()); + switch (DC->getContextKind()) { - // TODO: Create a cache for functions. - case DeclContextKind::AbstractClosureExpr: + // The interesting cases are already handled above. case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::AbstractClosureExpr: // We don't model these in DWARF. case DeclContextKind::SerializedLocal: case DeclContextKind::Initializer: case DeclContextKind::ExtensionDecl: + case DeclContextKind::SubscriptDecl: return getOrCreateContext(DC->getParent()); case DeclContextKind::TopLevelCodeDecl: @@ -619,7 +625,7 @@ IRGenDebugInfo::createParameterTypes(CanSILFunctionType FnTy, DeclContext *DeclCtx) { SmallVector Parameters; - GenericsRAII scope(*this, FnTy->getGenericSignature()); + GenericContextScope scope(IGM, FnTy->getGenericSignature()); // The function return type is the first element in the list. createParameterType(Parameters, FnTy->getSemanticResultSILType(), @@ -644,7 +650,6 @@ static bool isAllocatingConstructor(SILFunctionTypeRepresentation Rep, llvm::DISubprogram *IRGenDebugInfo::emitFunction( SILModule &SILMod, const SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType SILTy, DeclContext *DeclCtx) { - // Returned a previously cached entry for an abstract (inlined) function. auto cached = ScopeCache.find(DS); if (cached != ScopeCache.end()) return cast(cached->second); @@ -677,9 +682,11 @@ llvm::DISubprogram *IRGenDebugInfo::emitFunction( ScopeLine = FL.LocForLinetable.Line; } - auto File = getOrCreateFile(L.Filename); - auto Scope = MainModule; auto Line = L.Line; + auto File = getOrCreateFile(L.Filename); + llvm::DIScope *Scope = MainModule; + if (DS->SILFn && DS->SILFn->getDeclContext()) + Scope = getOrCreateContext(DS->SILFn->getDeclContext()->getParent()); // We know that main always comes from MainFile. if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { @@ -857,7 +864,7 @@ void IRGenDebugInfo::emitTypeMetadata(IRGenFunction &IGF, (Alignment)CI.getTargetInfo().getPointerAlign(0)); emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), TName, 0, - // swift.type is a already pointer type, + // swift.type is already a pointer type, // having a shadow copy doesn't add another // layer of indirection. DirectValue, ArtificialValue); @@ -870,12 +877,9 @@ llvm::DIFile *IRGenDebugInfo::getFile(llvm::DIScope *Scope) { case llvm::dwarf::DW_TAG_lexical_block: Scope = cast(Scope)->getScope(); break; - case llvm::dwarf::DW_TAG_subprogram: { - // Scopes are not indexed by UID. - llvm::DITypeIdentifierMap EmptyMap; - Scope = cast(Scope)->getScope().resolve(EmptyMap); + case llvm::dwarf::DW_TAG_subprogram: + Scope = cast(Scope)->getFile(); break; - } default: return MainFile; } @@ -961,24 +965,6 @@ getStorageSize(const llvm::DataLayout &DL, ArrayRef Storage) { return Size(size); } -/// LValues, inout args, and Archetypes are implicitly indirect by -/// virtue of their DWARF type. -static bool isImplicitlyIndirect(TypeBase *Ty) { - switch (Ty->getKind()) { - case TypeKind::Paren: - return isImplicitlyIndirect( - cast(Ty)->getUnderlyingType().getPointer()); - case TypeKind::NameAlias: - return isImplicitlyIndirect( - cast(Ty)->getSinglyDesugaredType()); - case TypeKind::InOut: - case TypeKind::Archetype: - return true; - default: - return false; - } -} - void IRGenDebugInfo::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo DbgTy, const SILDebugScope *DS, StringRef Name, unsigned ArgNo, @@ -1018,9 +1004,6 @@ void IRGenDebugInfo::emitVariableDeclaration( if (Artificial || DITy->isArtificial() || DITy == InternalType) Flags |= llvm::DINode::FlagArtificial; - if (isImplicitlyIndirect(DbgTy.getType())) - Indirection = DirectValue; - // Create the descriptor for the variable. llvm::DILocalVariable *Var = nullptr; @@ -1154,14 +1137,9 @@ StringRef IRGenDebugInfo::getMangledName(DebugTypeInfo DbgTy) { if (MetadataTypeDecl && DbgTy.getDecl() == MetadataTypeDecl) return BumpAllocatedString(DbgTy.getDecl()->getName().str()); - llvm::SmallString<160> Buffer; - { - llvm::raw_svector_ostream S(Buffer); - Mangle::Mangler M(S, /* DWARF */ true); - M.mangleTypeForDebugger(DbgTy.getType(), DbgTy.getDeclContext()); - } - assert(!Buffer.empty() && "mangled name came back empty"); - return BumpAllocatedString(Buffer); + Mangle::Mangler M(/* DWARF */ true); + M.mangleTypeForDebugger(DbgTy.getType(), DbgTy.getDeclContext()); + return BumpAllocatedString(M.finalize()); } /// Create a member of a struct, class, tuple, or enum. @@ -1186,9 +1164,10 @@ llvm::DINodeArray IRGenDebugInfo::getTupleElements( unsigned Flags, DeclContext *DeclContext, unsigned &SizeInBits) { SmallVector Elements; unsigned OffsetInBits = 0; + auto genericSig = IGM.SILMod->Types.getCurGenericContext(); for (auto ElemTy : TupleTy->getElementTypes()) { auto &elemTI = - IGM.getTypeInfoForUnlowered(AbstractionPattern(CurGenerics, + IGM.getTypeInfoForUnlowered(AbstractionPattern(genericSig, ElemTy->getCanonicalType()), ElemTy); DebugTypeInfo DbgTy(ElemTy, elemTI, DeclContext); @@ -1826,7 +1805,7 @@ static bool canMangle(TypeBase *Ty) { switch (Ty->getKind()) { case TypeKind::PolymorphicFunction: // Mangler crashes. case TypeKind::GenericFunction: // Not yet supported. - case TypeKind::SILBlockStorage: // Not suported at all. + case TypeKind::SILBlockStorage: // Not supported at all. case TypeKind::SILBox: return false; case TypeKind::InOut: { diff --git a/lib/IRGen/IRGenDebugInfo.h b/lib/IRGen/IRGenDebugInfo.h index 906efbe92aed9..51b052c486432 100644 --- a/lib/IRGen/IRGenDebugInfo.h +++ b/lib/IRGen/IRGenDebugInfo.h @@ -1,8 +1,8 @@ -//===--- IRGenDebugInfo.h - Debug Info Support-------------------*- C++ -*-===// +//===--- IRGenDebugInfo.h - Debug Info Support ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -110,23 +110,6 @@ class IRGenDebugInfo { /// Used by pushLoc. SmallVector, 8> LocationStack; - // FIXME: move this to something more local in type generation. - CanGenericSignature CurGenerics; - class GenericsRAII { - IRGenDebugInfo &Self; - GenericContextScope Scope; - CanGenericSignature OldGenerics; - public: - GenericsRAII(IRGenDebugInfo &self, CanGenericSignature generics) - : Self(self), Scope(self.IGM, generics), OldGenerics(self.CurGenerics) { - if (generics) self.CurGenerics = generics; - } - - ~GenericsRAII() { - Self.CurGenerics = OldGenerics; - } - }; - public: IRGenDebugInfo(const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, llvm::Module &M, SourceFile *SF); @@ -310,7 +293,7 @@ class AutoRestoreLocation { /// instructions (e.g., ARC-inserted calls to release()) that have no /// source location associated with them. The DWARF specification /// allows the compiler to use the special line number 0 to indicate -/// code that can not be attributed to any source location. +/// code that cannot be attributed to any source location. class ArtificialLocation : public AutoRestoreLocation { public: /// \brief Set the current location to line 0, but within scope DS. diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index e3a2b4dafaae2..d919764e3ef02 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -52,8 +52,12 @@ IRGenFunction::IRGenFunction(IRGenModule &IGM, IRGenFunction::~IRGenFunction() { emitEpilogue(); + // Restore the debug location. if (IGM.DebugInfo) IGM.DebugInfo->popLoc(); + + // Tear down any side-table data structures. + if (LocalTypeData) destroyLocalTypeData(); } /// Call the llvm.memcpy intrinsic. The arguments need not already @@ -187,7 +191,7 @@ static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn, void IRGenFunction::emitDeallocRawCall(llvm::Value *pointer, llvm::Value *size, llvm::Value *alignMask) { - // For now, all we have is swift_slowDelloc. + // For now, all we have is swift_slowDealloc. return emitDeallocatingCall(*this, IGM.getSlowDeallocFn(), {pointer, size, alignMask}); } @@ -212,40 +216,6 @@ void IRGenFunction::emitFakeExplosion(const TypeInfo &type, } } -llvm::Value *IRGenFunction::lookupTypeDataMap(CanType type, LocalTypeData index, - const TypeDataMap &scopedMap) { - - // First try to lookup in the unscoped cache (= definitions in the entry block - // of the function). - auto key = getLocalTypeDataKey(type, index); - auto it = LocalTypeDataMap.find(key); - if (it != LocalTypeDataMap.end()) - return it->second; - - // Now try to lookup in the scoped cache. - auto it2 = scopedMap.find(key); - if (it2 == scopedMap.end()) - return nullptr; - - if (auto *I = dyn_cast(it2->second)) { - // This is a very very simple dominance check: either the definition is in the - // entry block or in the current block. - // TODO: do a better dominance check. - if (I->getParent() == &CurFn->getEntryBlock() || - I->getParent() == Builder.GetInsertBlock()) { - return I; - } - return nullptr; - } - - if (isa(it2->second)) { - return it2->second; - } - - // TODO: other kinds of value? - return nullptr; -} - void IRGenFunction::unimplemented(SourceLoc Loc, StringRef Message) { return IGM.unimplemented(Loc, Message); } diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 3ba294855d3dc..6e0e2a3262460 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -1,8 +1,8 @@ -//===--- IRGenFunction.h - IR Generation for Swift Functions ---*- C++ -*-===// +//===--- IRGenFunction.h - IR Generation for Swift Functions ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,7 +25,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/IR/CallingConv.h" #include "IRBuilder.h" - +#include "LocalTypeDataKind.h" +#include "DominancePoint.h" namespace llvm { class AllocaInst; @@ -60,53 +61,12 @@ namespace irgen { class HeapNonFixedOffsets; class IRGenModule; class LinkEntity; + class LocalTypeDataCache; class Scope; class TypeInfo; enum class ValueWitness : unsigned; enum class ReferenceCounting : unsigned char; -/// A nonce value for storing some sort of locally-known information about a type. -class LocalTypeData { - unsigned Value; - - explicit LocalTypeData(unsigned Value) : Value(Value) {} - - /// Magic values for special kinds of index. - enum : unsigned { - Metatype = ~0U, - ValueWitnessTable = ~1U, - - ValueWitnessBase = 0xFFFFFF00U, - }; - -public: - LocalTypeData() = default; - - // The magic values are all in the "negative" range and so do - // not collide with reasonable index values. - - /// A reference to the type metadata. - static LocalTypeData forMetatype() { return LocalTypeData(Metatype); } - /// A reference to the value witness table. - static LocalTypeData forValueWitnessTable() { - return LocalTypeData(ValueWitnessTable); - } - - /// A reference to a specific value witness. - static LocalTypeData forValueWitness(ValueWitness witness) { - return LocalTypeData((unsigned)witness + ValueWitnessBase); - } - - /// A reference to a protocol witness table for an archetype. - static LocalTypeData forArchetypeProtocolWitness(unsigned index) { - return LocalTypeData(index); - } - - unsigned getValue() const { - return Value; - } -}; - /// IRGenFunction - Primary class for emitting LLVM instructions for a /// specific function. class IRGenFunction { @@ -401,57 +361,145 @@ class IRGenFunction { //--- Type emission ------------------------------------------------------------ public: - /// Look for a mapping for a local type-metadata reference. - /// The lookup is done for the current block which is the Builder's - /// insert-block. - llvm::Value *tryGetLocalTypeData(CanType type, LocalTypeData index) { - return lookupTypeDataMap(type, index, ScopedTypeDataMap); + /// Look up a local type data reference, returning null if no entry was + /// found. This will emit code to materialize the reference if an + /// "abstract" entry is present. + llvm::Value *tryGetLocalTypeData(CanType type, LocalTypeDataKind kind) { + return tryGetLocalTypeData(LocalTypeDataKey{type, kind}); } + llvm::Value *tryGetLocalTypeData(LocalTypeDataKey key); - /// The same as tryGetLocalTypeData, just for the Layout metadata. - llvm::Value *tryGetLocalTypeDataForLayout(SILType type, LocalTypeData index) { - return lookupTypeDataMap(type.getSwiftRValueType(), index, - ScopedTypeDataMapForLayout); - } + /// Look up a local type data reference, returning null if no entry was + /// found or if the only viable entries are abstract. This will never + /// emit code. + llvm::Value *tryGetConcreteLocalTypeData(LocalTypeDataKey key); - /// Retrieve a local type-metadata reference which is known to exist. - llvm::Value *getLocalTypeData(CanType type, LocalTypeData index) { - auto key = getLocalTypeDataKey(type, index); - assert(LocalTypeDataMap.count(key) && "no mapping for local type data"); - return LocalTypeDataMap.find(key)->second; - } + /// Retrieve a local type data reference which is known to exist. + llvm::Value *getLocalTypeData(CanType type, LocalTypeDataKind kind); - /// Add a local type-metadata reference at a point which dominates - /// the entire function. - void setUnscopedLocalTypeData(CanType type, LocalTypeData index, + /// Add a local type-metadata reference at a point which definitely + /// dominates all of its uses. + void setUnscopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data) { - assert(data && "setting a null value for type data!"); - - auto key = getLocalTypeDataKey(type, index); - assert(!LocalTypeDataMap.count(key) && - "existing mapping for local type data"); - LocalTypeDataMap.insert({key, data}); + setUnscopedLocalTypeData(LocalTypeDataKey{type, kind}, data); } + void setUnscopedLocalTypeData(LocalTypeDataKey key, llvm::Value *data); - /// Add a local type-metadata reference, which is valid for the containing - /// block. - void setScopedLocalTypeData(CanType type, LocalTypeData index, + /// Add a local type-metadata reference, valid at the current insertion + /// point. + void setScopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data) { - assert(_isValidScopedLocalTypeData(data) && - "metadata instruction not inserted into the Builder's insert-block"); - ScopedTypeDataMap[getLocalTypeDataKey(type, index)] = data; + setScopedLocalTypeData(LocalTypeDataKey{type, kind}, data); + } + void setScopedLocalTypeData(LocalTypeDataKey key, llvm::Value *data); + + /// The same as tryGetLocalTypeData, just for the Layout metadata. + /// + /// We use a separate function name for this to clarify that you should + /// only ever be looking type metadata for a lowered SILType for the + /// purposes of local layout (e.g. of a tuple). + llvm::Value *tryGetLocalTypeDataForLayout(SILType type, + LocalTypeDataKind kind) { + return tryGetLocalTypeData(type.getSwiftRValueType(), kind); } /// Add a local type-metadata reference, which is valid for the containing /// block. - void setScopedLocalTypeDataForLayout(SILType type, LocalTypeData index, + void setScopedLocalTypeDataForLayout(SILType type, LocalTypeDataKind kind, llvm::Value *data) { - assert(_isValidScopedLocalTypeData(data) && - "metadata instruction not inserted into the Builder's insert-block"); - ScopedTypeDataMapForLayout[ - getLocalTypeDataKey(type.getSwiftRValueType(), index)] = data; + setScopedLocalTypeData(type.getSwiftRValueType(), kind, data); } + /// Given a concrete type metadata node, add all the local type data + /// that we can reach from it. + void bindLocalTypeDataFromTypeMetadata(CanType type, IsExact_t isExact, + llvm::Value *metadata); + + void setDominanceResolver(DominanceResolverFunction resolver) { + assert(DominanceResolver == nullptr); + DominanceResolver = resolver; + } + + bool isActiveDominancePointDominatedBy(DominancePoint point) { + // If the point is universal, it dominates. + if (point.isUniversal()) return true; + + assert(!ActiveDominancePoint.isUniversal() && + "active dominance point is universal but there exists a" + "non-universal point?"); + + // If we don't have a resolver, we're emitting a simple helper + // function; just assume dominance. + if (!DominanceResolver) return true; + + // Otherwise, ask the resolver. + return DominanceResolver(*this, ActiveDominancePoint, point); + } + + /// Is the current dominance point conditional in some way not + /// tracked by the active dominance point? + /// + /// This should only be used by the local type data cache code. + bool isConditionalDominancePoint() const { + return ConditionalDominance != nullptr; + } + + void registerConditionalLocalTypeDataKey(LocalTypeDataKey key) { + assert(ConditionalDominance != nullptr && + "not in a conditional dominance scope"); + ConditionalDominance->registerConditionalLocalTypeDataKey(key); + } + + /// Return the currently-active dominance point. + DominancePoint getActiveDominancePoint() const { + return ActiveDominancePoint; + } + + /// A RAII object for temporarily changing the dominance of the active + /// definition point. + class DominanceScope { + IRGenFunction &IGF; + DominancePoint OldDominancePoint; + public: + explicit DominanceScope(IRGenFunction &IGF, DominancePoint newPoint) + : IGF(IGF), OldDominancePoint(IGF.ActiveDominancePoint) { + IGF.ActiveDominancePoint = newPoint; + assert(!newPoint.isOrdinary() || IGF.DominanceResolver); + } + + DominanceScope(const DominanceScope &other) = delete; + DominanceScope &operator=(const DominanceScope &other) = delete; + + ~DominanceScope() { + IGF.ActiveDominancePoint = OldDominancePoint; + } + }; + + /// A RAII object for temporarily suppressing type-data caching at the + /// active definition point. Do this if you're adding local control flow + /// that isn't modeled by the dominance system. + class ConditionalDominanceScope { + IRGenFunction &IGF; + ConditionalDominanceScope *OldScope; + SmallVector RegisteredKeys; + + public: + explicit ConditionalDominanceScope(IRGenFunction &IGF) + : IGF(IGF), OldScope(IGF.ConditionalDominance) { + IGF.ConditionalDominance = this; + } + + ConditionalDominanceScope(const ConditionalDominanceScope &other) = delete; + ConditionalDominanceScope &operator=(const ConditionalDominanceScope &other) + = delete; + + void registerConditionalLocalTypeDataKey(LocalTypeDataKey key) { + RegisteredKeys.push_back(key); + } + + ~ConditionalDominanceScope(); + }; + /// The kind of value LocalSelf is. enum LocalSelfKind { /// An object reference. @@ -466,35 +514,16 @@ class IRGenFunction { void setLocalSelfMetadata(llvm::Value *value, LocalSelfKind kind); private: -#ifndef NDEBUG - bool _isValidScopedLocalTypeData(llvm::Value *v) { - // Constants are valid anywhere. - if (isa(v)) - return true; - // Instructions are valid only in the current insert block. - if (auto inst = dyn_cast(v)) - return inst->getParent() == Builder.GetInsertBlock(); - // TODO: Other kinds of value? - return false; - } -#endif + LocalTypeDataCache &getOrCreateLocalTypeData(); + void destroyLocalTypeData(); - typedef unsigned LocalTypeDataDepth; - typedef std::pair LocalTypeDataPair; - LocalTypeDataPair getLocalTypeDataKey(CanType type, LocalTypeData index) { - return LocalTypeDataPair(type.getPointer(), index.getValue()); - } - - typedef llvm::DenseMap TypeDataMap; - - llvm::Value *lookupTypeDataMap(CanType type, LocalTypeData index, - const TypeDataMap &scopedMap); + LocalTypeDataCache *LocalTypeData = nullptr; - TypeDataMap LocalTypeDataMap; - - TypeDataMap ScopedTypeDataMap; - - TypeDataMap ScopedTypeDataMapForLayout; + /// The dominance resolver. This can be set at most once; when it's not + /// set, this emission must never have a non-null active definition point. + DominanceResolverFunction DominanceResolver = nullptr; + DominancePoint ActiveDominancePoint = DominancePoint::universal(); + ConditionalDominanceScope *ConditionalDominance = nullptr; /// The value that satisfies metadata lookups for dynamic Self. llvm::Value *LocalSelf = nullptr; @@ -502,6 +531,8 @@ class IRGenFunction { LocalSelfKind SelfKind; }; +using ConditionalDominanceScope = IRGenFunction::ConditionalDominanceScope; + } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 78472403414f5..f7fe4416810cb 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -131,6 +131,15 @@ IRGenModule::IRGenModule(IRGenModuleDispatcher &dispatcher, SourceFile *SF, Types(*new TypeConverter(*this)) { dispatcher.addGenModule(SF, this); + + // If the command line contains an explicit request about whether to add + // LLVM value names, honor it. Otherwise, add value names only if the + // final result is textual LLVM assembly. + if (Opts.HasValueNamesSetting) { + EnableValueNames = Opts.ValueNames; + } else { + EnableValueNames = (Opts.OutputKind == IRGenOutputKind::LLVMAssembly); + } VoidTy = llvm::Type::getVoidTy(getLLVMContext()); Int1Ty = llvm::Type::getInt1Ty(getLLVMContext()); @@ -269,6 +278,32 @@ IRGenModule::IRGenModule(IRGenModuleDispatcher &dispatcher, SourceFile *SF, ProtocolConformanceRecordPtrTy = ProtocolConformanceRecordTy->getPointerTo(DefaultAS); + NominalTypeDescriptorTy + = llvm::StructType::create(LLVMContext, "swift.type_descriptor"); + NominalTypeDescriptorPtrTy + = NominalTypeDescriptorTy->getPointerTo(DefaultAS); + + TypeMetadataRecordTy + = createStructType(*this, "swift.type_metadata_record", { + RelativeAddressTy, + Int32Ty + }); + TypeMetadataRecordPtrTy + = TypeMetadataRecordTy->getPointerTo(DefaultAS); + + FieldDescriptorTy = createStructType(*this, "swift.field_descriptor", { + Int32Ty, // Number of fields that follow + Int32Ty, // Size of fields that follow + // Tail-allocated FieldRecordTy elements + }); + + FieldRecordTy = createStructType(*this, "swift.field_record", { + Int32Ty, // Flags + RelativeAddressTy, // Offset to metadata or mangled name for external type + RelativeAddressTy, // Offset to field name + }); + FieldRecordPtrTy = FieldRecordTy->getPointerTo(DefaultAS); + FixedBufferTy = nullptr; for (unsigned i = 0; i != MaxNumValueWitnesses; ++i) ValueWitnessTys[i] = nullptr; @@ -625,19 +660,6 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { } } -// FIXME: This should just be the implementation of -// llvm::array_pod_sort_comparator. The only difference is that it uses -// std::less instead of operator<. -template -static int pointerPODSortComparator(T * const *lhs, T * const *rhs) { - std::less lt; - if (lt(*lhs, *rhs)) - return -1; - if (lt(*rhs, *lhs)) - return -1; - return 0; -} - static bool replaceModuleFlagsEntry(llvm::LLVMContext &Ctx, llvm::Module &Module, StringRef EntryName, llvm::Module::ModFlagBehavior Behavior, @@ -846,3 +868,31 @@ IRGenModule *IRGenModuleDispatcher::getGenModule(SILFunction *f) { return getPrimaryIGM(); } + +StringRef IRGenModule::getFieldMetadataSectionName() { + switch (TargetInfo.OutputObjectFormat) { + case llvm::Triple::MachO: + return "__DATA, __swift2_field_names, regular, no_dead_strip"; + break; + case llvm::Triple::ELF: + return ".swift2_field_names"; + break; + default: + llvm_unreachable("Don't know how to emit field name table for " + "the selected object format."); + } +} + +StringRef IRGenModule::getFieldNamesSectionName() { + switch (TargetInfo.OutputObjectFormat) { + case llvm::Triple::MachO: + return "__DATA, __swift2_field_metadata, regular, no_dead_strip"; + break; + case llvm::Triple::ELF: + return ".swift2_field_metadata"; + break; + default: + llvm_unreachable("Don't know how to emit field metadata table for " + "the selected object format."); + } +} diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index fdae76a59ba86..ad0010a899e94 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -85,6 +85,7 @@ namespace swift { class IRGenOptions; class NormalProtocolConformance; class ProtocolConformance; + class TypeMetadataRecord; class ProtocolCompositionType; class ProtocolDecl; struct SILDeclRef; @@ -204,6 +205,9 @@ class IRGenModuleDispatcher { /// Emit the protocol conformance records needed by each IR module. void emitProtocolConformances(); + /// Emit type metadata records for types without explicit protocol conformance. + void emitTypeMetadataRecords(); + /// Emit everything which is reachable from already emitted IR. void emitLazyDefinitions(); @@ -322,6 +326,9 @@ class IRGenModule { /// Does the current target require Objective-C interoperation? bool ObjCInterop = true; + /// Should we add value names to local IR values? + bool EnableValueNames = false; + llvm::Type *VoidTy; /// void (usually {}) llvm::IntegerType *Int1Ty; /// i1 llvm::IntegerType *Int8Ty; /// i8 @@ -382,16 +389,28 @@ class IRGenModule { llvm::PointerType *ObjCBlockPtrTy; /// %objc_block* llvm::StructType *ProtocolConformanceRecordTy; llvm::PointerType *ProtocolConformanceRecordPtrTy; + llvm::StructType *NominalTypeDescriptorTy; + llvm::PointerType *NominalTypeDescriptorPtrTy; + llvm::StructType *TypeMetadataRecordTy; + llvm::PointerType *TypeMetadataRecordPtrTy; + llvm::StructType *FieldDescriptorTy; + llvm::PointerType *FieldDescriptorPtrTy; + llvm::StructType *FieldRecordTy; + llvm::PointerType *FieldRecordPtrTy; llvm::PointerType *ErrorPtrTy; /// %swift.error* llvm::StructType *OpenedErrorTripleTy; /// { %swift.opaque*, %swift.type*, i8** } llvm::PointerType *OpenedErrorTriplePtrTy; /// { %swift.opaque*, %swift.type*, i8** }* - + unsigned InvariantMetadataID; /// !invariant.load unsigned DereferenceableID; /// !dereferenceable llvm::MDNode *InvariantNode; llvm::CallingConv::ID RuntimeCC; /// lightweight calling convention + llvm::FunctionType *getAssociatedTypeMetadataAccessFunctionTy(); + llvm::FunctionType *getAssociatedTypeWitnessTableAccessFunctionTy(); + llvm::StructType *getGenericWitnessTableCacheTy(); + /// Get the bit width of an integer type for the target platform. unsigned getBuiltinIntegerWidth(BuiltinIntegerType *t); unsigned getBuiltinIntegerWidth(BuiltinIntegerWidth w); @@ -446,6 +465,10 @@ class IRGenModule { llvm::Type *getFixedBufferTy(); llvm::Type *getValueWitnessTy(ValueWitness index); + llvm::Constant *emitDirectRelativeReference(llvm::Constant *target, + llvm::Constant *base, + ArrayRef baseIndices); + void unimplemented(SourceLoc, StringRef Message); LLVM_ATTRIBUTE_NORETURN void fatal_unimplemented(SourceLoc, StringRef Message); @@ -456,6 +479,9 @@ class IRGenModule { llvm::Type *FixedBufferTy; /// [N x i8], where N == 3 * sizeof(void*) llvm::Type *ValueWitnessTys[MaxNumValueWitnesses]; + llvm::FunctionType *AssociatedTypeMetadataAccessFunctionTy = nullptr; + llvm::FunctionType *AssociatedTypeWitnessTableAccessFunctionTy = nullptr; + llvm::StructType *GenericWitnessTableCacheTy = nullptr; llvm::DenseMap SpareBitsForTypes; @@ -492,7 +518,7 @@ class IRGenModule { unsigned getExplosionSize(SILType T); llvm::PointerType *isSingleIndirectValue(SILType T); llvm::PointerType *requiresIndirectResult(SILType T); - bool isPOD(SILType type, ResilienceScope scope); + bool isPOD(SILType type, ResilienceExpansion expansion); clang::CanQual getClangType(CanType type); clang::CanQual getClangType(SILType type); clang::CanQual getClangType(SILParameterInfo param); @@ -503,7 +529,10 @@ class IRGenModule { return *ClangASTContext; } - bool isResilient(Decl *decl, ResilienceScope scope); + bool isResilient(NominalTypeDecl *decl, ResilienceExpansion expansion); + ResilienceExpansion getResilienceExpansionForAccess(NominalTypeDecl *decl); + ResilienceExpansion getResilienceExpansionForLayout(NominalTypeDecl *decl); + ResilienceExpansion getResilienceExpansionForLayout(SILGlobalVariable *var); SpareBitVector getSpareBitsForType(llvm::Type *scalarTy, Size size); @@ -520,7 +549,8 @@ class IRGenModule { //--- Globals --------------------------------------------------------------- public: - llvm::Constant *getAddrOfGlobalString(StringRef utf8); + llvm::Constant *getAddrOfGlobalString(StringRef utf8, + bool willBeRelativelyAddressed = false); llvm::Constant *getAddrOfGlobalUTF16String(StringRef utf8); llvm::Constant *getAddrOfObjCSelectorRef(StringRef selector); llvm::Constant *getAddrOfObjCMethodName(StringRef methodName); @@ -529,6 +559,7 @@ class IRGenModule { llvm::Constant *getAddrOfObjCProtocolRef(ProtocolDecl *proto, ForDefinition_t forDefinition); void addUsedGlobal(llvm::GlobalValue *global); + void addCompilerUsedGlobal(llvm::GlobalValue *global); void addObjCClass(llvm::Constant *addr, bool nonlazy); void addProtocolConformanceRecord(NormalProtocolConformance *conformance); @@ -536,6 +567,10 @@ class IRGenModule { ArrayRef fieldTypes, llvm::Function *fn); llvm::Constant *emitProtocolConformances(); + llvm::Constant *emitTypeMetadataRecords(); + llvm::Constant *getAddrOfFieldName(StringRef Name); + StringRef getFieldMetadataSectionName(); + StringRef getFieldNamesSectionName(); llvm::Constant *getOrCreateHelperFunction(StringRef name, llvm::Type *resultType, @@ -547,8 +582,10 @@ class IRGenModule { llvm::DenseMap GlobalGOTEquivalents; llvm::DenseMap GlobalFuncs; llvm::DenseSet GlobalClangDecls; - llvm::StringMap GlobalStrings; + llvm::StringMap> + GlobalStrings; llvm::StringMap GlobalUTF16Strings; + llvm::StringMap> FieldNames; llvm::StringMap ObjCSelectorRefs; llvm::StringMap ObjCMethodNames; @@ -558,6 +595,14 @@ class IRGenModule { /// out. SmallVector LLVMUsed; + /// LLVMCompilerUsed - List of global values which are required to be + /// present in the object file; bitcast to i8*. This is used for + /// forcing visibility of symbols which may otherwise be optimized + /// out. + /// + /// Similar to LLVMUsed, but emitted as llvm.compiler.used. + SmallVector LLVMCompilerUsed; + /// Metadata nodes for autolinking info. /// /// This is typed using llvm::Value instead of llvm::MDNode because it @@ -573,6 +618,8 @@ class IRGenModule { SmallVector ObjCCategories; /// List of protocol conformances to generate records for. SmallVector ProtocolConformances; + /// List of nominal types to generate type metadata records for. + SmallVector RuntimeResolvableTypes; /// List of ExtensionDecls corresponding to the generated /// categories. SmallVector ObjCCategoryDecls; @@ -620,7 +667,7 @@ class IRGenModule { llvm::Constant *getObjCEmptyVTablePtr(); llvm::Value *getObjCRetainAutoreleasedReturnValueMarker(); ClassDecl *getObjCRuntimeBaseForSwiftRootClass(ClassDecl *theClass); - ClassDecl *getObjCRuntimeBaseClass(Identifier name); + ClassDecl *getObjCRuntimeBaseClass(Identifier name, Identifier objcName); llvm::Module *getModule() const; llvm::Module *releaseModule(); llvm::AttributeSet getAllocAttrs(); @@ -640,11 +687,14 @@ public: \ private: \ llvm::Constant *Id##Fn = nullptr; #include "RuntimeFunctions.def" + + llvm::Constant *FixLifetimeFn = nullptr; mutable Optional HeapPointerSpareBits; //--- Generic --------------------------------------------------------------- public: + llvm::Constant *getFixLifetimeFn(); /// The constructor. /// @@ -716,6 +766,10 @@ private: \ llvm::Constant *getAddrOfTypeMetadata(CanType concreteType, bool isPattern); llvm::Function *getAddrOfTypeMetadataAccessFunction(CanType type, ForDefinition_t forDefinition); + llvm::Function *getAddrOfGenericTypeMetadataAccessFunction( + NominalTypeDecl *nominal, + ArrayRef genericArgs, + ForDefinition_t forDefinition); llvm::Constant *getAddrOfTypeMetadataLazyCacheVariable(CanType type, ForDefinition_t forDefinition); llvm::Constant *getAddrOfForeignTypeMetadataCandidate(CanType concreteType); @@ -734,6 +788,7 @@ private: \ llvm::Function *getAddrOfSILFunction(SILFunction *f, ForDefinition_t forDefinition); Address getAddrOfSILGlobalVariable(SILGlobalVariable *var, + const TypeInfo &ti, ForDefinition_t forDefinition); llvm::Function *getAddrOfWitnessTableAccessFunction( const NormalProtocolConformance *C, @@ -748,10 +803,26 @@ private: \ ForDefinition_t forDefinition); llvm::Constant *getAddrOfWitnessTable(const NormalProtocolConformance *C, llvm::Type *definitionTy = nullptr); + llvm::Constant * + getAddrOfGenericWitnessTableCache(const NormalProtocolConformance *C, + ForDefinition_t forDefinition); + llvm::Function * + getAddrOfGenericWitnessTableInstantiationFunction( + const NormalProtocolConformance *C); + llvm::Function *getAddrOfAssociatedTypeMetadataAccessFunction( + const NormalProtocolConformance *C, + AssociatedTypeDecl *associatedType); + llvm::Function *getAddrOfAssociatedTypeWitnessTableAccessFunction( + const NormalProtocolConformance *C, + AssociatedTypeDecl *associatedType, + ProtocolDecl *requiredProtocol); + Address getAddrOfObjCISAMask(); StringRef mangleType(CanType type, SmallVectorImpl &buffer); - + + bool hasMetadataPattern(NominalTypeDecl *theDecl); + // Get the ArchetypeBuilder for the currently active generic context. Crashes // if there is no generic context. ArchetypeBuilder &getContextArchetypes(); @@ -760,6 +831,10 @@ private: \ Direct, GOT, }; + /// Mark a global variable as true-const by putting it in the text section of + /// the binary. + void setTrueConstGlobal(llvm::GlobalVariable *var); + private: llvm::Constant *getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment, @@ -777,6 +852,7 @@ private: \ llvm::Type *defaultType); void emitLazyPrivateDefinitions(); + void addRuntimeResolvableType(CanType type); //--- Global context emission -------------------------------------------------- public: diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 201d108989263..2c5f9dd3cdf9e 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,7 +31,9 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Pattern.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" +#include "swift/SIL/Dominance.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILDeclRef.h" @@ -122,17 +124,23 @@ class LoweredValue { public: enum class Kind { /// This LoweredValue corresponds to a SIL address value. + /// The LoweredValue of an alloc_stack keeps an owning container in + /// addition to the address of the allocated buffer. + /// Depending on the allocated type, the container may be equal to the + /// buffer itself (for types with known sizes) or it may be the address + /// of a fixed-size container which points to the heap-allocated buffer. + /// In this case the address-part may be null, which means that the buffer + /// is not allocated yet. Address, - /// This LoweredValue corresponds to a SIL address value owned by an - /// uninitialized fixed-size buffer. - UnallocatedAddressInBuffer, - /// The following kinds correspond to SIL non-address values. Value_First, /// A normal value, represented as an exploded array of llvm Values. Explosion = Value_First, - + + /// A @box together with the address of the box value. + BoxWithAddress, + /// A value that represents a statically-known function symbol that /// can be called directly, represented as a StaticFunction. StaticFunction, @@ -149,7 +157,8 @@ class LoweredValue { using ExplosionVector = SmallVector; union { - Address address; + ContainedAddress address; + OwnedAddress boxWithAddress; struct { ExplosionVector values; } explosion; @@ -158,14 +167,24 @@ class LoweredValue { }; public: + + /// Create an address value without a container (the usual case). LoweredValue(const Address &address) - : kind(Kind::Address), address(address) + : kind(Kind::Address), address(Address(), address) {} - enum UnallocatedAddressInBuffer_t { UnallocatedAddressInBuffer }; + enum ContainerForUnallocatedAddress_t { ContainerForUnallocatedAddress }; + + /// Create an address value for an alloc_stack, consisting of a container and + /// a not yet allocated buffer. + LoweredValue(const Address &container, ContainerForUnallocatedAddress_t) + : kind(Kind::Address), address(container, Address()) + {} - LoweredValue(const Address &address, UnallocatedAddressInBuffer_t) - : kind(Kind::UnallocatedAddressInBuffer), address(address) + /// Create an address value for an alloc_stack, consisting of a container and + /// the address of the allocated buffer. + LoweredValue(const ContainedAddress &address) + : kind(Kind::Address), address(address) {} LoweredValue(StaticFunction &&staticFunction) @@ -181,18 +200,24 @@ class LoweredValue { auto Elts = e.claimAll(); explosion.values.append(Elts.begin(), Elts.end()); } - + + LoweredValue(const OwnedAddress &boxWithAddress) + : kind(Kind::BoxWithAddress), boxWithAddress(boxWithAddress) + {} + LoweredValue(LoweredValue &&lv) : kind(lv.kind) { switch (kind) { case Kind::Address: - case Kind::UnallocatedAddressInBuffer: - ::new (&address) Address(std::move(lv.address)); + ::new (&address) ContainedAddress(std::move(lv.address)); break; case Kind::Explosion: ::new (&explosion.values) ExplosionVector(std::move(lv.explosion.values)); break; + case Kind::BoxWithAddress: + ::new (&boxWithAddress) OwnedAddress(std::move(lv.boxWithAddress)); + break; case Kind::StaticFunction: ::new (&staticFunction) StaticFunction(std::move(lv.staticFunction)); break; @@ -210,23 +235,27 @@ class LoweredValue { } bool isAddress() const { - return kind == Kind::Address; + return kind == Kind::Address && address.getAddress().isValid(); } bool isUnallocatedAddressInBuffer() const { - return kind == Kind::UnallocatedAddressInBuffer; + return kind == Kind::Address && !address.getAddress().isValid(); } bool isValue() const { return kind >= Kind::Value_First && kind <= Kind::Value_Last; } + bool isBoxWithAddress() const { + return kind == Kind::BoxWithAddress; + } Address getAddress() const { - assert(kind == Kind::Address && "not an allocated address"); - return address; + assert(isAddress() && "not an allocated address"); + return address.getAddress(); } - Address getAddressOfUnallocatedBuffer() const { - assert(kind == Kind::UnallocatedAddressInBuffer); - return address; + Address getContainerOfAddress() const { + assert(kind == Kind::Address); + assert(address.getContainer().isValid() && "address has no container"); + return address.getContainer(); } void getExplosion(IRGenFunction &IGF, Explosion &ex) const; @@ -237,6 +266,11 @@ class LoweredValue { return e; } + Address getAddressOfBox() const { + assert(kind == Kind::BoxWithAddress); + return boxWithAddress.getAddress(); + } + llvm::Value *getSingletonExplosion(IRGenFunction &IGF) const; const StaticFunction &getStaticFunction() const { @@ -252,12 +286,14 @@ class LoweredValue { ~LoweredValue() { switch (kind) { case Kind::Address: - case Kind::UnallocatedAddressInBuffer: - address.~Address(); + address.~ContainedAddress(); break; case Kind::Explosion: explosion.values.~ExplosionVector(); break; + case Kind::BoxWithAddress: + boxWithAddress.~OwnedAddress(); + break; case Kind::StaticFunction: staticFunction.~StaticFunction(); break; @@ -292,6 +328,37 @@ class IRGenSILFunction : /// All alloc_ref instructions which allocate the object on the stack. llvm::SmallPtrSet StackAllocs; + /// With closure captures it is actually possible to have two function + /// arguments that both have the same name. Until this is fixed, we need to + /// also hash the ArgNo here. + typedef std::pair> + StackSlotKey; + /// Keeps track of the mapping of source variables to -O0 shadow copy allocas. + llvm::SmallDenseMap ShadowStackSlots; + llvm::SmallDenseMap, 8> AnonymousVariables; + unsigned NumAnonVars = 0; + + /// Notes about instructions for which we're supposed to perform some + /// sort of non-standard emission. This enables some really simply local + /// peepholing in cases where you can't just do that with the lowered value. + /// + /// Since emission notes generally change semantics, we enforce that all + /// notes must be claimed. + /// + /// This uses a set because the current peepholes don't need to record any + /// extra structure; if you need extra structure, feel free to make it a + /// map. This set is generally very small because claiming a note removes + /// it. + llvm::SmallPtrSet EmissionNotes; + + void addEmissionNote(SILInstruction *inst) { + assert(inst); + EmissionNotes.insert(inst); + } + + bool claimEmissionNote(SILInstruction *inst) { + return EmissionNotes.erase(inst); + } /// Accumulative amount of allocated bytes on the stack. Used to limit the /// size for stack promoted objects. @@ -306,6 +373,9 @@ class IRGenSILFunction : SILFunction *CurSILFn; Address IndirectReturn; + + // A cached dominance analysis. + std::unique_ptr Dominance; IRGenSILFunction(IRGenModule &IGM, SILFunction *f); ~IRGenSILFunction(); @@ -322,66 +392,60 @@ class IRGenSILFunction : (void)inserted; } - void overwriteLoweredValue(SILValue v, LoweredValue &&lv) { - auto it = LoweredValues.find(v); - assert(it != LoweredValues.end() && "no existing entry for overwrite?"); - it->second = std::move(lv); - } - /// Create a new Address corresponding to the given SIL address value. void setLoweredAddress(SILValue v, const Address &address) { - assert((v.getType().isAddress() || v.getType().isLocalStorage()) && - "address for non-address value?!"); + assert(v->getType().isAddress() && "address for non-address value?!"); setLoweredValue(v, address); } - void setLoweredUnallocatedAddressInBuffer(SILValue v, - const Address &buffer) { - assert((v.getType().isAddress() || v.getType().isLocalStorage()) && - "address for non-address value?!"); + void setLoweredContainedAddress(SILValue v, const ContainedAddress &address) { + assert(v->getType().isAddress() && "address for non-address value?!"); + setLoweredValue(v, address); + } + + void setContainerOfUnallocatedAddress(SILValue v, + const Address &buffer) { + assert(v->getType().isAddress() && "address for non-address value?!"); setLoweredValue(v, - LoweredValue(buffer, LoweredValue::UnallocatedAddressInBuffer)); + LoweredValue(buffer, LoweredValue::ContainerForUnallocatedAddress)); } - void overwriteLoweredAddress(SILValue v, const Address &address) { - assert((v.getType().isAddress() || v.getType().isLocalStorage()) && - "address for non-address value?!"); - overwriteLoweredValue(v, address); + void overwriteAllocatedAddress(SILValue v, const Address &address) { + assert(v->getType().isAddress() && "address for non-address value?!"); + auto it = LoweredValues.find(v); + assert(it != LoweredValues.end() && "no existing entry for overwrite?"); + assert(it->second.isUnallocatedAddressInBuffer() && + "not an unallocated address"); + it->second = ContainedAddress(it->second.getContainerOfAddress(), address); } void setAllocatedAddressForBuffer(SILValue v, const Address &allocedAddress); /// Create a new Explosion corresponding to the given SIL value. void setLoweredExplosion(SILValue v, Explosion &e) { - assert(v.getType().isObject() && "explosion for address value?!"); + assert(v->getType().isObject() && "explosion for address value?!"); setLoweredValue(v, LoweredValue(e)); } - void overwriteLoweredExplosion(SILValue v, Explosion &e) { - assert(v.getType().isObject() && "explosion for address value?!"); - overwriteLoweredValue(v, LoweredValue(e)); + void setLoweredBox(SILValue v, const OwnedAddress &box) { + assert(v->getType().isObject() && "box for address value?!"); + setLoweredValue(v, LoweredValue(box)); } - void setLoweredSingleValue(SILValue v, llvm::Value *scalar) { - Explosion e; - e.add(scalar); - setLoweredExplosion(v, e); - } - /// Create a new StaticFunction corresponding to the given SIL value. void setLoweredStaticFunction(SILValue v, llvm::Function *f, SILFunctionTypeRepresentation rep) { - assert(v.getType().isObject() && "function for address value?!"); - assert(v.getType().is() && + assert(v->getType().isObject() && "function for address value?!"); + assert(v->getType().is() && "function for non-function value?!"); setLoweredValue(v, StaticFunction{f, rep}); } /// Create a new Objective-C method corresponding to the given SIL value. void setLoweredObjCMethod(SILValue v, SILDeclRef method) { - assert(v.getType().isObject() && "function for address value?!"); - assert(v.getType().is() && + assert(v->getType().isObject() && "function for address value?!"); + assert(v->getType().is() && "function for non-function value?!"); setLoweredValue(v, ObjCMethod{method, SILType(), false}); } @@ -400,8 +464,8 @@ class IRGenSILFunction : /// static type (vs. the static type itself). void setLoweredObjCMethodBounded(SILValue v, SILDeclRef method, SILType searchType, bool startAtSuper) { - assert(v.getType().isObject() && "function for address value?!"); - assert(v.getType().is() && + assert(v->getType().isObject() && "function for address value?!"); + assert(v->getType().is() && "function for non-function value?!"); setLoweredValue(v, ObjCMethod{method, searchType, startAtSuper}); } @@ -413,8 +477,7 @@ class IRGenSILFunction : auto &ti = getTypeInfo(t); switch (t.getCategory()) { - case SILValueCategory::Address: - case SILValueCategory::LocalStorage: { + case SILValueCategory::Address: { Address undefAddr = ti.getAddressForPointer( llvm::UndefValue::get(ti.getStorageType()->getPointerTo())); LoweredUndefs.insert({t, LoweredValue(undefAddr)}); @@ -443,7 +506,7 @@ class IRGenSILFunction : /// have been lowered. LoweredValue &getLoweredValue(SILValue v) { if (isa(v)) - return getUndefLoweredValue(v.getType()); + return getUndefLoweredValue(v->getType()); auto foundValue = LoweredValues.find(v); assert(foundValue != LoweredValues.end() && @@ -456,6 +519,9 @@ class IRGenSILFunction : Address getLoweredAddress(SILValue v) { return getLoweredValue(v).getAddress(); } + Address getLoweredContainerOfAddress(SILValue v) { + return getLoweredValue(v).getContainerOfAddress(); + } /// Add the unmanaged LLVM values lowered from a SIL value to an explosion. void getLoweredExplosion(SILValue v, Explosion &e) { getLoweredValue(v).getExplosion(*this, e); @@ -478,12 +544,36 @@ class IRGenSILFunction : return foundBB->second; } + StringRef getOrCreateAnonymousVarName(VarDecl *Decl) { + llvm::SmallString<4> &Name = AnonymousVariables[Decl]; + if (Name.empty()) { + { + llvm::raw_svector_ostream S(Name); + S << '_' << NumAnonVars++; + } + AnonymousVariables.insert({Decl, Name}); + } + return Name; + } + + template + StringRef getVarName(DebugVarCarryingInst *i) { + StringRef Name = i->getVarInfo().Name; + // The $match variables generated by the type checker are not + // guaranteed to be unique within their scope, but they have + // unique VarDecls. + if ((Name.empty() || Name == "$match") && i->getDecl()) + return getOrCreateAnonymousVarName(i->getDecl()); + return Name; + } + /// At -O0, emit a shadow copy of an Address in an alloca, so the /// register allocator doesn't elide the dbg.value intrinsic when /// register pressure is high. There is a trade-off to this: With /// shadow copies, we lose the precise lifetime. llvm::Value *emitShadowCopy(llvm::Value *Storage, - StringRef Name, + const SILDebugScope *Scope, + StringRef Name, unsigned ArgNo, Alignment Align = Alignment(0)) { auto Ty = Storage->getType(); if (IGM.Opts.Optimize || @@ -495,16 +585,21 @@ class IRGenSILFunction : if (Align.isZero()) Align = IGM.getPointerAlignment(); - auto Alloca = createAlloca(Ty, Align, Name+".addr"); + auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}]; + if (!Alloca.isValid()) + Alloca = createAlloca(Ty, Align, Name+".addr"); Builder.CreateStore(Storage, Alloca.getAddress(), Align); return Alloca.getAddress(); } - llvm::Value *emitShadowCopy(Address storage, StringRef name) { - return emitShadowCopy(storage.getAddress(), name, storage.getAlignment()); + llvm::Value *emitShadowCopy(Address Storage, const SILDebugScope *Scope, + StringRef Name, unsigned ArgNo) { + return emitShadowCopy(Storage.getAddress(), Scope, Name, ArgNo, + Storage.getAlignment()); } - void emitShadowCopy(ArrayRef vals, StringRef name, + void emitShadowCopy(ArrayRef vals, const SILDebugScope *Scope, + StringRef Name, unsigned ArgNo, llvm::SmallVectorImpl ©) { // Only do this at -O0. if (IGM.Opts.Optimize) { @@ -515,7 +610,7 @@ class IRGenSILFunction : // Single or empty values. if (vals.size() <= 1) { for (auto val : vals) - copy.push_back(emitShadowCopy(val, name)); + copy.push_back(emitShadowCopy(val, Scope, Name, ArgNo)); return; } @@ -531,7 +626,7 @@ class IRGenSILFunction : auto layout = IGM.DataLayout.getStructLayout(aggregateType); Alignment align(layout->getAlignment()); - auto alloca = createAlloca(aggregateType, align, name + ".debug"); + auto alloca = createAlloca(aggregateType, align, Name + ".debug"); size_t i = 0; for (auto val : vals) { auto addr = Builder.CreateStructGEP(alloca, i, @@ -578,6 +673,8 @@ class IRGenSILFunction : void emitFunctionArgDebugInfo(SILBasicBlock *BB); + void emitDebugInfoForAllocStack(AllocStackInst *i, const TypeInfo &type, + llvm::Value *addr); void visitAllocStackInst(AllocStackInst *i); void visitAllocRefInst(AllocRefInst *i); void visitAllocRefDynamicInst(AllocRefDynamicInst *i); @@ -592,6 +689,7 @@ class IRGenSILFunction : void visitBuiltinInst(BuiltinInst *i); void visitFunctionRefInst(FunctionRefInst *i); + void visitAllocGlobalInst(AllocGlobalInst *i); void visitGlobalAddrInst(GlobalAddrInst *i); void visitIntegerLiteralInst(IntegerLiteralInst *i); @@ -655,6 +753,7 @@ class IRGenSILFunction : void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i); void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i); + void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i); void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *i); void visitProjectBlockStorageInst(ProjectBlockStorageInst *i); @@ -740,7 +839,6 @@ llvm::Value *StaticFunction::getExplosionValue(IRGenFunction &IGF) const { void LoweredValue::getExplosion(IRGenFunction &IGF, Explosion &ex) const { switch (kind) { case Kind::Address: - case Kind::UnallocatedAddressInBuffer: llvm_unreachable("not a value"); case Kind::Explosion: @@ -748,6 +846,10 @@ void LoweredValue::getExplosion(IRGenFunction &IGF, Explosion &ex) const { ex.add(value); break; + case Kind::BoxWithAddress: + ex.add(boxWithAddress.getOwner()); + break; + case Kind::StaticFunction: ex.add(staticFunction.getExplosionValue(IGF)); break; @@ -761,13 +863,15 @@ void LoweredValue::getExplosion(IRGenFunction &IGF, Explosion &ex) const { llvm::Value *LoweredValue::getSingletonExplosion(IRGenFunction &IGF) const { switch (kind) { case Kind::Address: - case Kind::UnallocatedAddressInBuffer: llvm_unreachable("not a value"); case Kind::Explosion: assert(explosion.values.size() == 1); return explosion.values[0]; + case Kind::BoxWithAddress: + return boxWithAddress.getOwner(); + case Kind::StaticFunction: return staticFunction.getExplosionValue(IGF); @@ -840,14 +944,14 @@ emitPHINodesForBBArgs(IRGenSILFunction &IGF, emitPHINodesForType(IGF, arg->getType(), ti, predecessors, phis); if (arg->getType().isAddress()) { - IGF.setLoweredAddress(SILValue(arg,0), + IGF.setLoweredAddress(arg, ti.getAddressForPointer(phis.back())); } else { Explosion argValue; for (llvm::PHINode *phi : swift::make_range(phis.begin()+first, phis.end())) argValue.add(phi); - IGF.setLoweredExplosion(SILValue(arg,0), argValue); + IGF.setLoweredExplosion(arg, argValue); } } @@ -872,10 +976,9 @@ static ArrayRef emitEntryPointIndirectReturn( // Map the indirect return if present. if (funcTy->hasIndirectResult()) { SILArgument *ret = entry->bbarg_begin()[0]; - SILValue retv(ret, 0); auto &retTI = IGF.IGM.getTypeInfo(ret->getType()); - IGF.setLoweredAddress(retv, retTI.getAddressForPointer(params.claimNext())); + IGF.setLoweredAddress(ret, retTI.getAddressForPointer(params.claimNext())); return entry->getBBArgs().slice(1); } else { // Map an indirect return for a type SIL considers loadable but still @@ -908,7 +1011,7 @@ static void emitDirectExternalParameter(IRGenSILFunction &IGF, // Fast-path a really common case. This check assumes that either // the storage type of a type is an llvm::StructType or it has a // single-element explosion. - } else if (coercionTy == paramTI.StorageType) { + } else if (coercionTy == paramTI.getStorageType()) { out.add(in.claimNext()); return; } else { @@ -932,10 +1035,12 @@ static void emitDirectExternalParameter(IRGenSILFunction &IGF, // Otherwise, we need to traffic through memory. // Create a temporary. - Address temporary = allocateForCoercion(IGF, + Address temporary; Size tempSize; + std::tie(temporary, tempSize) = allocateForCoercion(IGF, coercionTy, paramTI.getStorageType(), ""); + IGF.Builder.CreateLifetimeStart(temporary, tempSize); // Write the input parameters into the temporary: Address coercedAddr = @@ -961,6 +1066,7 @@ static void emitDirectExternalParameter(IRGenSILFunction &IGF, paramTI.loadAsTake(IGF, temporary, out); // Deallocate the temporary. + // `deallocateStack` emits the lifetime.end marker for us. paramTI.deallocateStack(IGF, temporary, paramType); } @@ -987,7 +1093,7 @@ static void bindParameter(IRGenSILFunction &IGF, // explosion schema. loadableTI.reexplode(IGF, allParamValues, paramValues); } - IGF.setLoweredExplosion(SILValue(param, 0), paramValues); + IGF.setLoweredExplosion(param, paramValues); return; } @@ -998,7 +1104,7 @@ static void bindParameter(IRGenSILFunction &IGF, // could be passed by value in the right resilience domain. Address paramAddr = paramTI.getAddressForPointer(allParamValues.claimNext()); - IGF.setLoweredAddress(SILValue(param, 0), paramAddr); + IGF.setLoweredAddress(param, paramAddr); } /// Emit entry point arguments for a SILFunction with the Swift calling @@ -1197,7 +1303,7 @@ static void emitEntryPointArgumentsCOrObjC(IRGenSILFunction &IGF, // all the value parameters. if (hasPolymorphicParameters(funcTy)) { emitPolymorphicParameters(IGF, *IGF.CurSILFn, params, - NULL, + nullptr, [&](unsigned paramIndex) -> llvm::Value* { SILValue parameter = entry->getBBArgs()[paramIndex]; return IGF.getLoweredSingletonExplosion(parameter); @@ -1246,6 +1352,20 @@ void IRGenSILFunction::emitSILFunction() { CurSILFn->print(llvm::dbgs())); assert(!CurSILFn->empty() && "function has no basic blocks?!"); + + // Configure the dominance resolver. + // TODO: consider re-using a dom analysis from the PassManager + // TODO: consider using a cheaper analysis at -O0 + setDominanceResolver([](IRGenFunction &IGF_, + DominancePoint activePoint, + DominancePoint dominatingPoint) -> bool { + IRGenSILFunction &IGF = static_cast(IGF_); + if (!IGF.Dominance) { + IGF.Dominance.reset(new DominanceInfo(IGF.CurSILFn)); + } + return IGF.Dominance->dominates(dominatingPoint.as(), + activePoint.as()); + }); // FIXME: Or if this is a witness. DebugInfo doesn't have an interface to // correctly handle the generic parameters of a witness, which can come from @@ -1259,13 +1379,13 @@ void IRGenSILFunction::emitSILFunction() { // Map the entry bb. LoweredBBs[&*CurSILFn->begin()] = LoweredBB(&*CurFn->begin(), {}); // Create LLVM basic blocks for the other bbs. - for (SILBasicBlock *bb = CurSILFn->begin()->getNextNode(); - bb != CurSILFn->end(); bb = bb->getNextNode()) { + for (auto bi = std::next(CurSILFn->begin()), be = CurSILFn->end(); bi != be; + ++bi) { // FIXME: Use the SIL basic block's name. llvm::BasicBlock *llBB = llvm::BasicBlock::Create(IGM.getLLVMContext()); - auto phis = emitPHINodesForBBArgs(*this, bb, llBB); + auto phis = emitPHINodesForBBArgs(*this, &*bi, llBB); CurFn->getBasicBlockList().push_back(llBB); - LoweredBBs[bb] = LoweredBB(llBB, std::move(phis)); + LoweredBBs[&*bi] = LoweredBB(llBB, std::move(phis)); } auto entry = LoweredBBs.begin(); @@ -1284,7 +1404,7 @@ void IRGenSILFunction::emitSILFunction() { break; } emitLocalSelfMetadata(*this); - + assert(params.empty() && "did not map all llvm params to SIL params?!"); // It's really nice to be able to assume that we've already emitted @@ -1346,6 +1466,9 @@ void IRGenSILFunction::emitSILFunction() { for (SILBasicBlock &bb : *CurSILFn) if (!visitedBlocks.count(&bb)) LoweredBBs[&bb].bb->eraseFromParent(); + + assert(EmissionNotes.empty() && + "didn't claim emission notes for all instructions!"); } void IRGenSILFunction::estimateStackSize() { @@ -1371,15 +1494,12 @@ void IRGenSILFunction::estimateStackSize() { /// Determine the number of source-level Swift of a function or closure. static unsigned countArgs(DeclContext *DC) { unsigned N = 0; - auto count = [&](ArrayRef Patterns) { - for (auto p : Patterns) - p->forEachVariable([&](VarDecl *VD) { ++N; }); - }; - - if (auto *Fn = dyn_cast(DC)) - count(Fn->getBodyParamPatterns()); - else if (auto *Closure = dyn_cast(DC)) - count(Closure->getParamPatterns()); + if (auto *Fn = dyn_cast(DC)) { + for (auto *PL : Fn->getParameterLists()) + N += PL->size(); + + } else if (auto *Closure = dyn_cast(DC)) + N += Closure->getParameters()->size(); else llvm_unreachable("unhandled declcontext type"); return N; @@ -1401,9 +1521,11 @@ void IRGenSILFunction::emitFunctionArgDebugInfo(SILBasicBlock *BB) { // other argument. It is only used for sorting. unsigned ArgNo = countArgs(CurSILFn->getDeclContext()) + 1 + BB->getBBArgs().size(); - IGM.DebugInfo->emitVariableDeclaration( - Builder, emitShadowCopy(ErrorResultSlot.getAddress(), Name), DTI, - getDebugScope(), Name, ArgNo, IndirectValue, ArtificialValue); + auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(), + Name, ArgNo); + IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, DTI, + getDebugScope(), Name, ArgNo, + IndirectValue, ArtificialValue); } } @@ -1416,6 +1538,11 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) { bool InEntryBlock = BB->pred_empty(); bool ArgsEmitted = false; + // Set this block as the dominance point. This implicitly communicates + // with the dominance resolver configured in emitSILFunction. + DominanceScope dominance(*this, InEntryBlock ? DominancePoint::universal() + : DominancePoint(BB)); + // The basic blocks are visited in a random order. Reset the debug location. std::unique_ptr ScopedLoc; if (InEntryBlock) @@ -1472,8 +1599,7 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) { if (!DS) { if (CurSILFn->isBare()) DS = CurSILFn->getDebugScope(); - // FIXME: Enable this assertion. - //assert(maybeScopeless(I) && "instruction has location, but no scope"); + assert(maybeScopeless(I) && "instruction has location, but no scope"); } // Ignore scope-less instructions and have IRBuilder reuse the @@ -1507,6 +1633,9 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) { } } visit(&I); + + assert(!EmissionNotes.count(&I) && + "didn't claim emission note for instruction!"); } assert(Builder.hasPostTerminatorIP() && "SIL bb did not terminate block?!"); @@ -1519,35 +1648,71 @@ void IRGenSILFunction::visitFunctionRefInst(FunctionRefInst *i) { // Store the function constant and calling // convention as a StaticFunction so we can avoid bitcasting or thunking if // we don't need to. - setLoweredStaticFunction(SILValue(i, 0), fnptr, + setLoweredStaticFunction(i, fnptr, i->getReferencedFunction()->getRepresentation()); } +void IRGenSILFunction::visitAllocGlobalInst(AllocGlobalInst *i) { + SILGlobalVariable *var = i->getReferencedGlobal(); + SILType loweredTy = var->getLoweredType(); + auto &ti = getTypeInfo(loweredTy); + + auto expansion = IGM.getResilienceExpansionForLayout(var); + + // If the global is fixed-size in all resilience domains that can see it, + // we allocated storage for it statically, and there's nothing to do. + if (ti.isFixedSize(expansion)) + return; + + // Otherwise, the static storage for the global consists of a fixed-size + // buffer. + Address addr = IGM.getAddrOfSILGlobalVariable(var, ti, + NotForDefinition); + (void) ti.allocateBuffer(*this, addr, loweredTy); +} + void IRGenSILFunction::visitGlobalAddrInst(GlobalAddrInst *i) { - auto &ti = getTypeInfo(i->getType()); + SILGlobalVariable *var = i->getReferencedGlobal(); + SILType loweredTy = var->getLoweredType(); + assert(loweredTy == i->getType().getObjectType()); + auto &ti = getTypeInfo(loweredTy); - Address addr; - // If the variable is empty, don't actually emit it; just return undef. - if (ti.isKnownEmpty()) { - addr = ti.getUndefAddress(); - } else { - addr = IGM.getAddrOfSILGlobalVariable(i->getReferencedGlobal(), - NotForDefinition); + auto expansion = IGM.getResilienceExpansionForLayout(var); + + // If the variable is empty in all resilience domains that can see it, + // don't actually emit a symbol for the global at all, just return undef. + if (ti.isKnownEmpty(expansion)) { + setLoweredAddress(i, ti.getUndefAddress()); + return; } + + Address addr = IGM.getAddrOfSILGlobalVariable(var, ti, + NotForDefinition); + + // If the global is fixed-size in all resilience domains that can see it, + // we allocated storage for it statically, and there's nothing to do. + if (ti.isFixedSize(expansion)) { + setLoweredAddress(i, addr); + return; + } + + // Otherwise, the static storage for the global consists of a fixed-size + // buffer; project it. + addr = ti.projectBuffer(*this, addr, loweredTy); - setLoweredAddress(SILValue(i, 0), addr); + setLoweredAddress(i, addr); } void IRGenSILFunction::visitMetatypeInst(swift::MetatypeInst *i) { auto metaTy = i->getType().castTo(); Explosion e; emitMetatypeRef(*this, metaTy, e); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } static llvm::Value *getClassBaseValue(IRGenSILFunction &IGF, SILValue v) { - if (v.getType().isAddress()) { + if (v->getType().isAddress()) { auto addr = IGF.getLoweredAddress(v); return IGF.Builder.CreateLoad(addr); } @@ -1573,12 +1738,12 @@ static llvm::Value *getClassMetatype(IRGenFunction &IGF, } void IRGenSILFunction::visitValueMetatypeInst(swift::ValueMetatypeInst *i) { - SILType instanceTy = i->getOperand().getType(); + SILType instanceTy = i->getOperand()->getType(); auto metaTy = i->getType().castTo(); if (metaTy->getRepresentation() == MetatypeRepresentation::Thin) { Explosion empty; - setLoweredExplosion(SILValue(i, 0), empty); + setLoweredExplosion(i, empty); return; } @@ -1596,7 +1761,7 @@ void IRGenSILFunction::visitValueMetatypeInst(swift::ValueMetatypeInst *i) { } else { Address base = getLoweredAddress(i->getOperand()); e.add(emitDynamicTypeOfOpaqueArchetype(*this, base, - i->getOperand().getType())); + i->getOperand()->getType())); // FIXME: We need to convert this back to an ObjC class for an // ObjC metatype representation. if (metaTy->getRepresentation() == MetatypeRepresentation::ObjC) @@ -1607,14 +1772,14 @@ void IRGenSILFunction::visitValueMetatypeInst(swift::ValueMetatypeInst *i) { emitMetatypeRef(*this, metaTy, e); } - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitExistentialMetatypeInst( swift::ExistentialMetatypeInst *i) { Explosion result; SILValue op = i->getOperand(); - SILType opType = op.getType(); + SILType opType = op->getType(); switch (opType.getPreferredExistentialRepresentation(*IGM.SILMod)) { case ExistentialRepresentation::Metatype: { @@ -1642,14 +1807,14 @@ void IRGenSILFunction::visitExistentialMetatypeInst( llvm_unreachable("Bad existential representation"); } - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } static void emitApplyArgument(IRGenSILFunction &IGF, SILValue arg, SILParameterInfo param, Explosion &out) { - bool isSubstituted = (arg.getType() != param.getSILType()); + bool isSubstituted = (arg->getType() != param.getSILType()); // For indirect arguments, we just need to pass a pointer. if (param.isIndirect()) { @@ -1668,7 +1833,7 @@ static void emitApplyArgument(IRGenSILFunction &IGF, // Otherwise, it's an explosion, which we may need to translate, // both in terms of explosion level and substitution levels. - assert(arg.getType().isObject()); + assert(arg->getType().isObject()); // Fast path: avoid an unnecessary temporary explosion. if (!isSubstituted) { @@ -1677,7 +1842,7 @@ static void emitApplyArgument(IRGenSILFunction &IGF, } Explosion temp = IGF.getLoweredExplosion(arg); - reemitAsUnsubstituted(IGF, param.getSILType(), arg.getType(), + reemitAsUnsubstituted(IGF, param.getSILType(), arg->getType(), temp, out); } @@ -1788,8 +1953,9 @@ static CallEmission getCallEmissionForLoweredValue(IRGenSILFunction &IGF, break; } + case LoweredValue::Kind::BoxWithAddress: + llvm_unreachable("@box isn't a valid callee"); case LoweredValue::Kind::Address: - case LoweredValue::Kind::UnallocatedAddressInBuffer: llvm_unreachable("sil address isn't a valid callee"); } @@ -1809,7 +1975,7 @@ void IRGenSILFunction::visitBuiltinInst(swift::BuiltinInst *i) { // Builtin arguments should never be substituted, so use the value's type // as the parameter type. emitApplyArgument(*this, argValue, - SILParameterInfo(argValue.getType().getSwiftRValueType(), + SILParameterInfo(argValue->getType().getSwiftRValueType(), ParameterConvention::Direct_Unowned), args); } @@ -1818,7 +1984,7 @@ void IRGenSILFunction::visitBuiltinInst(swift::BuiltinInst *i) { emitBuiltinCall(*this, i->getName(), i->getType(), args, result, i->getSubstitutions()); - setLoweredExplosion(SILValue(i,0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitApplyInst(swift::ApplyInst *i) { @@ -1847,7 +2013,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) { args = args.drop_back(); params = params.drop_back(); - if (selfArg.getType().isObject()) { + if (selfArg->getType().isObject()) { selfValue = getLoweredSingletonExplosion(selfArg); } else { selfValue = getLoweredAddress(selfArg).getAddress(); @@ -1892,7 +2058,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) { Explosion result; if (indirectResult) { Address a = getLoweredAddress(indirectResult); - auto &retTI = getTypeInfo(indirectResult.getType()); + auto &retTI = getTypeInfo(indirectResult->getType()); emission.emitToMemory(a, retTI); // Leave an empty explosion in 'result'. @@ -1903,7 +2069,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) { } if (isa(i)) { - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } else { auto tryApplyInst = cast(i); @@ -1955,8 +2121,9 @@ getPartialApplicationFunction(IRGenSILFunction &IGF, switch (lv.kind) { case LoweredValue::Kind::Address: - case LoweredValue::Kind::UnallocatedAddressInBuffer: llvm_unreachable("can't partially apply an address"); + case LoweredValue::Kind::BoxWithAddress: + llvm_unreachable("can't partially apply a @box"); case LoweredValue::Kind::ObjCMethod: llvm_unreachable("objc method partial application shouldn't get here"); @@ -1975,12 +2142,12 @@ getPartialApplicationFunction(IRGenSILFunction &IGF, break; } return std::make_tuple(lv.getStaticFunction().getFunction(), - nullptr, v.getType().castTo()); + nullptr, v->getType().castTo()); case LoweredValue::Kind::Explosion: { Explosion ex = lv.getExplosion(IGF); llvm::Value *fn = ex.claimNext(); llvm::Value *context = nullptr; - auto fnType = v.getType().castTo(); + auto fnType = v->getType().castTo(); switch (fnType->getRepresentation()) { case SILFunctionType::Representation::Thin: @@ -2002,7 +2169,7 @@ getPartialApplicationFunction(IRGenSILFunction &IGF, } void IRGenSILFunction::visitPartialApplyInst(swift::PartialApplyInst *i) { - SILValue v(i, 0); + SILValue v(i); // NB: We collect the arguments under the substituted type. auto args = i->getArguments(); @@ -2015,7 +2182,7 @@ void IRGenSILFunction::visitPartialApplyInst(swift::PartialApplyInst *i) { // Lower the parameters in the callee's generic context. GenericContextScope scope(IGM, i->getOrigCalleeType()->getGenericSignature()); for (auto index : indices(args)) { - assert(args[index].getType() == params[index].getSILType()); + assert(args[index]->getType() == params[index].getSILType()); emitApplyArgument(*this, args[index], params[index], llArgs); } } @@ -2039,9 +2206,9 @@ void IRGenSILFunction::visitPartialApplyInst(swift::PartialApplyInst *i) { i->getOrigCalleeType(), i->getType().castTo(), selfVal, - i->getArguments()[0].getType(), + i->getArguments()[0]->getType(), function); - setLoweredExplosion(SILValue(i, 0), function); + setLoweredExplosion(i, function); return; } @@ -2091,7 +2258,7 @@ void IRGenSILFunction::visitIntegerLiteralInst(swift::IntegerLiteralInst *i) { Explosion e; e.add(constant); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } /// Construct a ConstantFP from a FloatLiteralInst. @@ -2104,7 +2271,7 @@ void IRGenSILFunction::visitFloatLiteralInst(swift::FloatLiteralInst *i) { llvm::Value *constant = getConstantFP(IGM, i); Explosion e; e.add(constant); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } static llvm::Constant *getAddrOfString(IRGenModule &IGM, StringRef string, @@ -2113,22 +2280,32 @@ static llvm::Constant *getAddrOfString(IRGenModule &IGM, StringRef string, case swift::StringLiteralInst::Encoding::UTF8: return IGM.getAddrOfGlobalString(string); - case swift::StringLiteralInst::Encoding::UTF16: + case swift::StringLiteralInst::Encoding::UTF16: { // This is always a GEP of a GlobalVariable with a nul terminator. auto addr = IGM.getAddrOfGlobalUTF16String(string); // Cast to Builtin.RawPointer. return llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy); } + + case swift::StringLiteralInst::Encoding::ObjCSelector: + llvm_unreachable("cannot get the address of an Objective-C selector"); + } llvm_unreachable("bad string encoding"); } void IRGenSILFunction::visitStringLiteralInst(swift::StringLiteralInst *i) { - auto addr = getAddrOfString(IGM, i->getValue(), i->getEncoding()); + llvm::Value *addr; + + // Emit a load of a selector. + if (i->getEncoding() == swift::StringLiteralInst::Encoding::ObjCSelector) + addr = emitObjCSelectorRefLoad(i->getValue()); + else + addr = getAddrOfString(IGM, i->getValue(), i->getEncoding()); Explosion e; e.add(addr); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitUnreachableInst(swift::UnreachableInst *i) { @@ -2164,7 +2341,7 @@ void IRGenSILFunction::visitReturnInst(swift::ReturnInst *i) { result = std::move(temp); } - emitReturnInst(*this, i->getOperand().getType(), result); + emitReturnInst(*this, i->getOperand()->getType(), result); } void IRGenSILFunction::visitThrowInst(swift::ThrowInst *i) { @@ -2243,7 +2420,7 @@ emitSwitchValueDispatch(IRGenSILFunction &IGF, auto casePair = dests[i]; llvm::Value *caseval; auto casevalue = IGF.getLoweredExplosion(casePair.first); - if (casePair.first.getType().getSwiftType()->is()) { + if (casePair.first->getType().getSwiftType()->is()) { caseval = casevalue.claimNext(); // Function pointer. //values.claimNext(); // Ignore the data pointer. } else { @@ -2283,7 +2460,7 @@ void IRGenSILFunction::visitSwitchValueInst(SwitchValueInst *inst) { SmallVector, 4> dests; auto *defaultDest = emitBBMapForSwitchValue(*this, dests, inst); - emitSwitchValueDispatch(*this, inst->getOperand().getType(), + emitSwitchValueDispatch(*this, inst->getOperand()->getType(), value, dests, defaultDest); } @@ -2379,7 +2556,7 @@ void IRGenSILFunction::visitSwitchEnumInst(SwitchEnumInst *inst) { = emitBBMapForSwitchEnum(*this, dests, inst); // Emit the dispatch. - auto &EIS = getEnumImplStrategy(IGM, inst->getOperand().getType()); + auto &EIS = getEnumImplStrategy(IGM, inst->getOperand()->getType()); EIS.emitValueSwitch(*this, value, dests, defaultDest); // Bind arguments for cases that want them. @@ -2394,7 +2571,7 @@ void IRGenSILFunction::visitSwitchEnumInst(SwitchEnumInst *inst) { Explosion inValue = getLoweredExplosion(inst->getOperand()); Explosion projected; - emitProjectLoadableEnum(*this, inst->getOperand().getType(), + emitProjectLoadableEnum(*this, inst->getOperand()->getType(), inValue, casePair.first, projected); unsigned phiIndex = 0; @@ -2415,7 +2592,7 @@ IRGenSILFunction::visitSwitchEnumAddrInst(SwitchEnumAddrInst *inst) { = emitBBMapForSwitchEnum(*this, dests, inst); // Emit the dispatch. - emitSwitchAddressOnlyEnumDispatch(*this, inst->getOperand().getType(), + emitSwitchAddressOnlyEnumDispatch(*this, inst->getOperand()->getType(), value, dests, defaultDest); } @@ -2446,7 +2623,7 @@ emitBBMapForSelect(IRGenSILFunction &IGF, IGF.Builder.SetInsertPoint(origBB); auto addIncoming = [&](SILValue value) { - if (value.getType().isAddress()) { + if (value->getType().isAddress()) { addIncomingAddressToPHINodes(IGF, resultPHI.getAll(), IGF.getLoweredAddress(value)); } else { @@ -2525,7 +2702,7 @@ mapTriviallyToInt(IRGenSILFunction &IGF, const EnumImplStrategy &EIS, SelectEnum if (index < 0) return nullptr; - IntegerLiteralInst *intLit = dyn_cast(casePair.second.getDef()); + IntegerLiteralInst *intLit = dyn_cast(casePair.second); if (!intLit) return nullptr; @@ -2580,7 +2757,7 @@ static void emitSingleEnumMemberSelectResult(IRGenSILFunction &IGF, // Extract the true values. auto trueValue = inst->getCase(0).second; SmallVector TrueValues; - if (trueValue.getType().isAddress()) { + if (trueValue->getType().isAddress()) { TrueValues.push_back(IGF.getLoweredAddress(trueValue).getAddress()); } else { Explosion ex = IGF.getLoweredExplosion(trueValue); @@ -2592,7 +2769,7 @@ static void emitSingleEnumMemberSelectResult(IRGenSILFunction &IGF, auto falseValue = inst->hasDefault() ? inst->getDefaultResult() : inst->getCase(1).second; SmallVector FalseValues; - if (falseValue.getType().isAddress()) { + if (falseValue->getType().isAddress()) { FalseValues.push_back(IGF.getLoweredAddress(falseValue).getAddress()); } else { Explosion ex = IGF.getLoweredExplosion(falseValue); @@ -2620,7 +2797,7 @@ static void emitSingleEnumMemberSelectResult(IRGenSILFunction &IGF, void IRGenSILFunction::visitSelectEnumInst(SelectEnumInst *inst) { - auto &EIS = getEnumImplStrategy(IGM, inst->getEnumOperand().getType()); + auto &EIS = getEnumImplStrategy(IGM, inst->getEnumOperand()->getType()); Explosion result; if (llvm::Value *R = mapTriviallyToInt(*this, EIS, inst)) { @@ -2648,7 +2825,7 @@ void IRGenSILFunction::visitSelectEnumInst(SelectEnumInst *inst) { // receive the result. Builder.SetInsertPoint(contBB); } - setLoweredValue(SILValue(inst, 0), + setLoweredValue(inst, getLoweredValueForSelect(*this, result, inst)); } @@ -2658,11 +2835,11 @@ void IRGenSILFunction::visitSelectEnumAddrInst(SelectEnumAddrInst *inst) { if ((inst->getNumCases() == 1 && inst->hasDefault()) || (inst->getNumCases() == 2 && !inst->hasDefault())) { - auto &EIS = getEnumImplStrategy(IGM, inst->getEnumOperand().getType()); + auto &EIS = getEnumImplStrategy(IGM, inst->getEnumOperand()->getType()); // If this is testing for one case, do simpler codegen. This is // particularly common when testing optionals. auto isTrue = EIS.emitIndirectCaseTest(*this, - inst->getEnumOperand().getType(), + inst->getEnumOperand()->getType(), value, inst->getCase(0).first); emitSingleEnumMemberSelectResult(*this, inst, isTrue, result); } else { @@ -2673,14 +2850,14 @@ void IRGenSILFunction::visitSelectEnumAddrInst(SelectEnumAddrInst *inst) { = emitBBMapForSelect(*this, result, dests, defaultDest, inst); // Emit the dispatch. - emitSwitchAddressOnlyEnumDispatch(*this, inst->getEnumOperand().getType(), + emitSwitchAddressOnlyEnumDispatch(*this, inst->getEnumOperand()->getType(), value, dests, defaultDest); // emitBBMapForSelectEnum set up a phi node to receive the result. Builder.SetInsertPoint(contBB); } - setLoweredValue(SILValue(inst, 0), + setLoweredValue(inst, getLoweredValueForSelect(*this, result, inst)); } @@ -2694,14 +2871,14 @@ void IRGenSILFunction::visitSelectValueInst(SelectValueInst *inst) { auto *contBB = emitBBMapForSelect(*this, result, dests, defaultDest, inst); // Emit the dispatch. - emitSwitchValueDispatch(*this, inst->getOperand().getType(), value, dests, + emitSwitchValueDispatch(*this, inst->getOperand()->getType(), value, dests, defaultDest); // emitBBMapForSelectEnum set up a continuation block and phi nodes to // receive the result. Builder.SetInsertPoint(contBB); - setLoweredValue(SILValue(inst, 0), + setLoweredValue(inst, getLoweredValueForSelect(*this, result, inst)); } @@ -2709,7 +2886,7 @@ void IRGenSILFunction::visitDynamicMethodBranchInst(DynamicMethodBranchInst *i){ LoweredBB &hasMethodBB = getLoweredBB(i->getHasMethodBB()); LoweredBB &noMethodBB = getLoweredBB(i->getNoMethodBB()); - // Emit the swift_objcRespondsToSelector() call. + // Emit the respondsToSelector: call. StringRef selector; llvm::SmallString<64> selectorBuffer; if (auto fnDecl = dyn_cast(i->getMember().getDecl())) @@ -2723,8 +2900,24 @@ void IRGenSILFunction::visitDynamicMethodBranchInst(DynamicMethodBranchInst *i){ if (object->getType() != IGM.ObjCPtrTy) object = Builder.CreateBitCast(object, IGM.ObjCPtrTy); llvm::Value *loadSel = emitObjCSelectorRefLoad(selector); - llvm::CallInst *call = Builder.CreateCall(IGM.getObjCRespondsToSelectorFn(), - {object, loadSel}); + + llvm::Value *respondsToSelector + = emitObjCSelectorRefLoad("respondsToSelector:"); + + llvm::Constant *messenger = IGM.getObjCMsgSendFn(); + llvm::Type *argTys[] = { + IGM.ObjCPtrTy, + IGM.Int8PtrTy, + IGM.Int8PtrTy, + }; + auto respondsToSelectorTy = llvm::FunctionType::get(IGM.Int1Ty, + argTys, + /*isVarArg*/ false) + ->getPointerTo(); + messenger = llvm::ConstantExpr::getBitCast(messenger, + respondsToSelectorTy); + llvm::CallInst *call = Builder.CreateCall(messenger, + {object, respondsToSelector, loadSel}); call->setDoesNotThrow(); // FIXME: Assume (probably safely) that the hasMethodBB has only us as a @@ -2775,7 +2968,7 @@ void IRGenSILFunction::visitCondBranchInst(swift::CondBranchInst *i) { void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { Explosion in = getLoweredExplosion(i->getOperand()); Explosion out; - cast(getTypeInfo(i->getOperand().getType())) + cast(getTypeInfo(i->getOperand()->getType())) .copy(*this, in, out); out.claimAll(); } @@ -2792,7 +2985,7 @@ void IRGenSILFunction::visitAutoreleaseValueInst(swift::AutoreleaseValueInst *i) void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) { Explosion in = getLoweredExplosion(i->getOperand()); - cast(getTypeInfo(i->getOperand().getType())) + cast(getTypeInfo(i->getOperand()->getType())) .consume(*this, in); } @@ -2800,14 +2993,14 @@ void IRGenSILFunction::visitStructInst(swift::StructInst *i) { Explosion out; for (SILValue elt : i->getElements()) out.add(getLoweredExplosion(elt).claimAll()); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction::visitTupleInst(swift::TupleInst *i) { Explosion out; for (SILValue elt : i->getElements()) out.add(getLoweredExplosion(elt).claimAll()); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction::visitEnumInst(swift::EnumInst *i) { @@ -2816,46 +3009,45 @@ void IRGenSILFunction::visitEnumInst(swift::EnumInst *i) { : Explosion(); Explosion out; emitInjectLoadableEnum(*this, i->getType(), i->getElement(), data, out); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction::visitInitEnumDataAddrInst(swift::InitEnumDataAddrInst *i) { Address enumAddr = getLoweredAddress(i->getOperand()); Address dataAddr = emitProjectEnumAddressForStore(*this, - i->getOperand().getType(), + i->getOperand()->getType(), enumAddr, i->getElement()); - setLoweredAddress(SILValue(i, 0), dataAddr); + setLoweredAddress(i, dataAddr); } void IRGenSILFunction::visitUncheckedEnumDataInst(swift::UncheckedEnumDataInst *i) { Explosion enumVal = getLoweredExplosion(i->getOperand()); Explosion data; - emitProjectLoadableEnum(*this, i->getOperand().getType(), + emitProjectLoadableEnum(*this, i->getOperand()->getType(), enumVal, i->getElement(), data); - setLoweredExplosion(SILValue(i, 0), data); + setLoweredExplosion(i, data); } void IRGenSILFunction::visitUncheckedTakeEnumDataAddrInst(swift::UncheckedTakeEnumDataAddrInst *i) { Address enumAddr = getLoweredAddress(i->getOperand()); Address dataAddr = emitDestructiveProjectEnumAddressForLoad(*this, - i->getOperand().getType(), + i->getOperand()->getType(), enumAddr, i->getElement()); - setLoweredAddress(SILValue(i, 0), dataAddr); + setLoweredAddress(i, dataAddr); } void IRGenSILFunction::visitInjectEnumAddrInst(swift::InjectEnumAddrInst *i) { Address enumAddr = getLoweredAddress(i->getOperand()); - emitStoreEnumTagToAddress(*this, i->getOperand().getType(), + emitStoreEnumTagToAddress(*this, i->getOperand()->getType(), enumAddr, i->getElement()); } void IRGenSILFunction::visitTupleExtractInst(swift::TupleExtractInst *i) { - SILValue v(i, 0); Explosion fullTuple = getLoweredExplosion(i->getOperand()); Explosion output; - SILType baseType = i->getOperand().getType(); + SILType baseType = i->getOperand()->getType(); projectTupleElementFromExplosion(*this, baseType, @@ -2863,24 +3055,23 @@ void IRGenSILFunction::visitTupleExtractInst(swift::TupleExtractInst *i) { i->getFieldNo(), output); fullTuple.claimAll(); - setLoweredExplosion(v, output); + setLoweredExplosion(i, output); } void IRGenSILFunction::visitTupleElementAddrInst(swift::TupleElementAddrInst *i) { Address base = getLoweredAddress(i->getOperand()); - SILType baseType = i->getOperand().getType(); + SILType baseType = i->getOperand()->getType(); Address field = projectTupleElementAddress(*this, base, baseType, i->getFieldNo()); - setLoweredAddress(SILValue(i, 0), field); + setLoweredAddress(i, field); } void IRGenSILFunction::visitStructExtractInst(swift::StructExtractInst *i) { - SILValue v(i, 0); Explosion operand = getLoweredExplosion(i->getOperand()); Explosion lowered; - SILType baseType = i->getOperand().getType(); + SILType baseType = i->getOperand()->getType(); projectPhysicalStructMemberFromExplosion(*this, baseType, @@ -2889,31 +3080,31 @@ void IRGenSILFunction::visitStructExtractInst(swift::StructExtractInst *i) { lowered); operand.claimAll(); - setLoweredExplosion(v, lowered); + setLoweredExplosion(i, lowered); } void IRGenSILFunction::visitStructElementAddrInst( swift::StructElementAddrInst *i) { Address base = getLoweredAddress(i->getOperand()); - SILType baseType = i->getOperand().getType(); + SILType baseType = i->getOperand()->getType(); Address field = projectPhysicalStructMemberAddress(*this, base, baseType, i->getField()); - setLoweredAddress(SILValue(i, 0), field); + setLoweredAddress(i, field); } void IRGenSILFunction::visitRefElementAddrInst(swift::RefElementAddrInst *i) { Explosion base = getLoweredExplosion(i->getOperand()); llvm::Value *value = base.claimNext(); - SILType baseTy = i->getOperand().getType(); + SILType baseTy = i->getOperand()->getType(); Address field = projectPhysicalClassMemberAddress(*this, value, baseTy, i->getType(), i->getField()) .getAddress(); - setLoweredAddress(SILValue(i, 0), field); + setLoweredAddress(i, field); } void IRGenSILFunction::visitLoadInst(swift::LoadInst *i) { @@ -2921,13 +3112,13 @@ void IRGenSILFunction::visitLoadInst(swift::LoadInst *i) { Address source = getLoweredAddress(i->getOperand()); const TypeInfo &type = getTypeInfo(i->getType().getObjectType()); cast(type).loadAsTake(*this, source, lowered); - setLoweredExplosion(SILValue(i, 0), lowered); + setLoweredExplosion(i, lowered); } void IRGenSILFunction::visitStoreInst(swift::StoreInst *i) { Explosion source = getLoweredExplosion(i->getSrc()); Address dest = getLoweredAddress(i->getDest()); - auto &type = getTypeInfo(i->getSrc().getType().getObjectType()); + auto &type = getTypeInfo(i->getSrc()->getType().getObjectType()); cast(type).initialize(*this, source, dest); } @@ -2935,26 +3126,31 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) { if (!IGM.DebugInfo) return; - VarDecl *Decl = i->getDecl(); - if (!Decl) - return; - auto SILVal = i->getOperand(); if (isa(SILVal)) return; - StringRef Name = i->getVarInfo().Name; - Explosion e = getLoweredExplosion(SILVal); - DebugTypeInfo DbgTy(Decl, Decl->getType(), getTypeInfo(SILVal.getType())); + StringRef Name = getVarName(i); + DebugTypeInfo DbgTy; + SILType SILTy = SILVal->getType(); + if (VarDecl *Decl = i->getDecl()) + DbgTy = DebugTypeInfo(Decl, Decl->getType(), getTypeInfo(SILTy)); + else if (i->getFunction()->isBare() && + !SILTy.getSwiftType()->hasArchetype() && !Name.empty()) + // Preliminary support for .sil debug information. + DbgTy = DebugTypeInfo(SILTy.getSwiftType(), getTypeInfo(SILTy), nullptr); + else + return; // An inout/lvalue type that is described by a debug value has been // promoted by an optimization pass. Unwrap the type. DbgTy.unwrapLValueOrInOutType(); // Put the value into a stack slot at -Onone. - llvm::SmallVector Copy; - emitShadowCopy(e.claimAll(), Name, Copy); - emitDebugVariableDeclaration(Copy, DbgTy, i->getDebugScope(), Name, - i->getVarInfo().ArgNo); + llvm::SmallVector Copy; + Explosion e = getLoweredExplosion(SILVal); + unsigned ArgNo = i->getVarInfo().ArgNo; + emitShadowCopy(e.claimAll(), i->getDebugScope(), Name, ArgNo, Copy); + emitDebugVariableDeclaration(Copy, DbgTy, i->getDebugScope(), Name, ArgNo); } void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { @@ -2968,18 +3164,26 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { if (isa(SILVal)) return; - StringRef Name = i->getVarInfo().Name; + StringRef Name = getVarName(i); auto Addr = getLoweredAddress(SILVal).getAddress(); - DebugTypeInfo DbgTy(Decl, Decl->getType(), getTypeInfo(SILVal.getType())); - // Put the value into a stack slot at -Onone and emit a debug intrinsic. - emitDebugVariableDeclaration(emitShadowCopy(Addr, Name), DbgTy, - i->getDebugScope(), Name, - i->getVarInfo().ArgNo, IndirectValue); + DebugTypeInfo DbgTy(Decl, SILVal->getType().getSwiftType(), + getTypeInfo(SILVal->getType())); + // Unwrap implicitly indirect types and types that are passed by + // reference only at the SIL level and below. + if (DbgTy.isArchetype() || i->getVarInfo().Constant) + DbgTy.unwrapLValueOrInOutType(); + // Put the value's address into a stack slot at -Onone and emit a debug + // intrinsic. + unsigned ArgNo = i->getVarInfo().ArgNo; + emitDebugVariableDeclaration( + emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo), DbgTy, + i->getDebugScope(), Name, ArgNo, + DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue); } void IRGenSILFunction::visitLoadWeakInst(swift::LoadWeakInst *i) { Address source = getLoweredAddress(i->getOperand()); - auto &weakTI = cast(getTypeInfo(i->getOperand().getType())); + auto &weakTI = cast(getTypeInfo(i->getOperand()->getType())); Explosion result; if (i->isTake()) { @@ -2988,14 +3192,14 @@ void IRGenSILFunction::visitLoadWeakInst(swift::LoadWeakInst *i) { weakTI.weakLoadStrong(*this, source, result); } - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitStoreWeakInst(swift::StoreWeakInst *i) { Explosion source = getLoweredExplosion(i->getSrc()); Address dest = getLoweredAddress(i->getDest()); - auto &weakTI = cast(getTypeInfo(i->getDest().getType())); + auto &weakTI = cast(getTypeInfo(i->getDest()->getType())); if (i->isInitializationOfDest()) { weakTI.weakInit(*this, source, dest); } else { @@ -3004,7 +3208,7 @@ void IRGenSILFunction::visitStoreWeakInst(swift::StoreWeakInst *i) { } void IRGenSILFunction::visitFixLifetimeInst(swift::FixLifetimeInst *i) { - if (i->getOperand().getType().isAddress()) { + if (i->getOperand()->getType().isAddress()) { // Just pass in the address to fix lifetime if we have one. We will not do // anything to it so nothing bad should happen. emitFixLifetime(getLoweredAddress(i->getOperand()).getAddress()); @@ -3013,7 +3217,7 @@ void IRGenSILFunction::visitFixLifetimeInst(swift::FixLifetimeInst *i) { // Handle objects. Explosion in = getLoweredExplosion(i->getOperand()); - cast(getTypeInfo(i->getOperand().getType())) + cast(getTypeInfo(i->getOperand()->getType())) .fixLifetime(*this, in); } @@ -3022,7 +3226,7 @@ void IRGenSILFunction::visitMarkDependenceInst(swift::MarkDependenceInst *i) { // the result. SILValue value = i->getValue(); - if (value.getType().isAddress()) { + if (value->getType().isAddress()) { setLoweredAddress(i, getLoweredAddress(value)); } else { Explosion temp = getLoweredExplosion(value); @@ -3035,7 +3239,7 @@ void IRGenSILFunction::visitCopyBlockInst(CopyBlockInst *i) { llvm::Value *copied = emitBlockCopyCall(lowered.claimNext()); Explosion result; result.add(copied); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitStrongPinInst(swift::StrongPinInst *i) { @@ -3056,13 +3260,13 @@ void IRGenSILFunction::visitStrongUnpinInst(swift::StrongUnpinInst *i) { void IRGenSILFunction::visitStrongRetainInst(swift::StrongRetainInst *i) { Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = cast(getTypeInfo(i->getOperand().getType())); + auto &ti = cast(getTypeInfo(i->getOperand()->getType())); ti.strongRetain(*this, lowered); } void IRGenSILFunction::visitStrongReleaseInst(swift::StrongReleaseInst *i) { Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = cast(getTypeInfo(i->getOperand().getType())); + auto &ti = cast(getTypeInfo(i->getOperand()->getType())); ti.strongRelease(*this, lowered); } @@ -3077,25 +3281,25 @@ static const ReferenceTypeInfo &getReferentTypeInfo(IRGenFunction &IGF, void IRGenSILFunction:: visitStrongRetainUnownedInst(swift::StrongRetainUnownedInst *i) { Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand().getType()); + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); ti.strongRetainUnowned(*this, lowered); } void IRGenSILFunction::visitUnownedRetainInst(swift::UnownedRetainInst *i) { Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand().getType()); + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); ti.unownedRetain(*this, lowered); } void IRGenSILFunction::visitUnownedReleaseInst(swift::UnownedReleaseInst *i) { Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand().getType()); + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); ti.unownedRelease(*this, lowered); } void IRGenSILFunction::visitLoadUnownedInst(swift::LoadUnownedInst *i) { Address source = getLoweredAddress(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand().getType()); + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); Explosion result; if (i->isTake()) { @@ -3104,14 +3308,14 @@ void IRGenSILFunction::visitLoadUnownedInst(swift::LoadUnownedInst *i) { ti.unownedLoadStrong(*this, source, result); } - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitStoreUnownedInst(swift::StoreUnownedInst *i) { Explosion source = getLoweredExplosion(i->getSrc()); Address dest = getLoweredAddress(i->getDest()); - auto &ti = getReferentTypeInfo(*this, i->getDest().getType()); + auto &ti = getReferentTypeInfo(*this, i->getDest()->getType()); if (i->isInitializationOfDest()) { ti.unownedInit(*this, source, dest); } else { @@ -3138,8 +3342,8 @@ static void requireRefCountedType(IRGenSILFunction &IGF, static llvm::Value *emitIsUnique(IRGenSILFunction &IGF, SILValue operand, SourceLoc loc, bool checkPinned) { - requireRefCountedType(IGF, loc, operand.getType()); - auto &operTI = cast(IGF.getTypeInfo(operand.getType())); + requireRefCountedType(IGF, loc, operand->getType()); + auto &operTI = cast(IGF.getTypeInfo(operand->getType())); LoadedRef ref = operTI.loadRefcountedPtr(IGF, loc, IGF.getLoweredAddress(operand)); @@ -3152,7 +3356,7 @@ void IRGenSILFunction::visitIsUniqueInst(swift::IsUniqueInst *i) { i->getLoc().getSourceLoc(), false); Explosion out; out.add(result); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction:: @@ -3161,13 +3365,12 @@ visitIsUniqueOrPinnedInst(swift::IsUniqueOrPinnedInst *i) { i->getLoc().getSourceLoc(), true); Explosion out; out.add(result); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF, const SILInstruction *allocInst, const TypeInfo &ti, - SILValue containerValue, SILValue addressValue, Address fixedSizeBuffer, const llvm::Twine &name) { @@ -3180,23 +3383,26 @@ static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF, // if the alloc_stack is dominated by copy_addrs into it on all paths. // For now, check only that the copy_addr is the first use within the same // block. - const SILInstruction *inst = allocInst; - while ((inst = inst->getNextNode()) && !isa(inst)) { - // Does this instruction use the allocation? - for (auto &operand : inst->getAllOperands()) - if (operand.get() == addressValue) - goto is_use; - - continue; - - is_use: + for (auto ii = std::next(allocInst->getIterator()), + ie = std::prev(allocInst->getParent()->end()); + ii != ie; ++ii) { + auto *inst = &*ii; + + // Does this instruction use the allocation? If not, continue. + auto Ops = inst->getAllOperands(); + if (std::none_of(Ops.begin(), Ops.end(), + [&addressValue](const Operand &Op) { + return Op.get() == addressValue; + })) + continue; + // Is this a copy? - auto copy = dyn_cast(inst); + auto *copy = dyn_cast(inst); if (!copy) return false; // Destination must be the allocation. - if (copy->getDest().getDef() != allocInst) + if (copy->getDest() != SILValue(allocInst)) return false; // Copy must be an initialization. @@ -3205,23 +3411,23 @@ static bool tryDeferFixedSizeBufferInitialization(IRGenSILFunction &IGF, // We can defer to this initialization. Allocate the fixed-size buffer // now, but don't allocate the value inside it. - if (!fixedSizeBuffer.getAddress()) + if (!fixedSizeBuffer.getAddress()) { fixedSizeBuffer = IGF.createFixedSizeBufferAlloca(name); - if (containerValue) - IGF.setLoweredAddress(containerValue, fixedSizeBuffer); - IGF.setLoweredUnallocatedAddressInBuffer(addressValue, fixedSizeBuffer); + IGF.Builder.CreateLifetimeStart(fixedSizeBuffer, + getFixedBufferSize(IGF.IGM)); + } + IGF.setContainerOfUnallocatedAddress(addressValue, fixedSizeBuffer); return true; } return false; } -static void emitDebugDeclarationForAllocStack(IRGenSILFunction &IGF, - AllocStackInst *i, - const TypeInfo &type, - llvm::Value *addr) { +void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i, + const TypeInfo &type, + llvm::Value *addr) { VarDecl *Decl = i->getDecl(); - if (IGF.IGM.DebugInfo && Decl) { + if (IGM.DebugInfo && Decl) { auto *Pattern = Decl->getParentPattern(); if (!Pattern || !Pattern->isImplicit()) { auto DbgTy = DebugTypeInfo(Decl, type); @@ -3229,12 +3435,11 @@ static void emitDebugDeclarationForAllocStack(IRGenSILFunction &IGF, // is stored in the alloca, emitting it as a reference type would // be wrong. DbgTy.unwrapLValueOrInOutType(); - auto Name = i->getVarInfo().Name.empty() ? "_" : i->getVarInfo().Name; - auto DS = i->getDebugScope(); - if (DS) { - assert(DS->SILFn == IGF.CurSILFn || DS->InlinedCallSite); - IGF.emitDebugVariableDeclaration(addr, DbgTy, DS, Name, - i->getVarInfo().ArgNo); + StringRef Name = getVarName(i); + if (auto DS = i->getDebugScope()) { + assert(DS->SILFn == CurSILFn || DS->InlinedCallSite); + emitDebugVariableDeclaration(addr, DbgTy, DS, Name, + i->getVarInfo().ArgNo); } } } @@ -3248,7 +3453,7 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { StringRef dbgname; # ifndef NDEBUG // If this is a DEBUG build, use pretty names for the LLVM IR. - dbgname = i->getVarInfo().Name; + dbgname = getVarName(i); # endif (void) Decl; @@ -3256,8 +3461,7 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { // operation, we can combine the allocation and initialization using an // optimized value witness. if (tryDeferFixedSizeBufferInitialization(*this, i, type, - i->getContainerResult(), - i->getAddressResult(), + i, Address(), dbgname)) return; @@ -3265,12 +3469,10 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { auto addr = type.allocateStack(*this, i->getElementType(), dbgname); + + emitDebugInfoForAllocStack(i, type, addr.getAddress().getAddress()); - emitDebugDeclarationForAllocStack(*this, i, type, - addr.getAddress().getAddress()); - - setLoweredAddress(i->getContainerResult(), addr.getContainer()); - setLoweredAddress(i->getAddressResult(), addr.getAddress()); + setLoweredContainedAddress(i, addr); } void IRGenSILFunction::visitAllocRefInst(swift::AllocRefInst *i) { @@ -3290,7 +3492,7 @@ void IRGenSILFunction::visitAllocRefInst(swift::AllocRefInst *i) { } Explosion e; e.add(alloced); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitAllocRefDynamicInst(swift::AllocRefDynamicInst *i) { @@ -3300,14 +3502,21 @@ void IRGenSILFunction::visitAllocRefDynamicInst(swift::AllocRefDynamicInst *i) { i->getType(), i->isObjC()); Explosion e; e.add(alloced); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitDeallocStackInst(swift::DeallocStackInst *i) { - const TypeInfo &type = getTypeInfo(i->getOperand().getType()); - Address addr = getLoweredAddress(i->getOperand()); - type.deallocateStack(*this, addr, - i->getOperand().getType()); + auto allocatedType = i->getOperand()->getType(); + const TypeInfo &allocatedTI = getTypeInfo(allocatedType); + Address container = getLoweredContainerOfAddress(i->getOperand()); + + // If the type isn't fixed-size, check whether we added an emission note. + // If so, we should deallocate and destroy at the same time. + if (!isa(allocatedTI) && claimEmissionNote(i)) { + allocatedTI.destroyStack(*this, container, allocatedType); + } else { + allocatedTI.deallocateStack(*this, container, allocatedType); + } } void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) { @@ -3315,7 +3524,7 @@ void IRGenSILFunction::visitDeallocRefInst(swift::DeallocRefInst *i) { Explosion self = getLoweredExplosion(i->getOperand()); auto selfValue = self.claimNext(); if (!i->canAllocOnStack()) { - auto classType = i->getOperand()->getType(0); + auto classType = i->getOperand()->getType(); emitClassDeallocation(*this, classType, selfValue); return; } @@ -3344,7 +3553,7 @@ void IRGenSILFunction::visitDeallocPartialRefInst(swift::DeallocPartialRefInst * auto selfValue = self.claimNext(); Explosion metadata = getLoweredExplosion(i->getMetatype()); auto metadataValue = metadata.claimNext(); - auto classType = i->getInstance()->getType(0); + auto classType = i->getInstance()->getType(); emitPartialClassDeallocation(*this, classType, selfValue, metadataValue); } @@ -3353,7 +3562,7 @@ void IRGenSILFunction::visitDeallocBoxInst(swift::DeallocBoxInst *i) { Explosion owner = getLoweredExplosion(i->getOperand()); llvm::Value *ownerPtr = owner.claimNext(); - auto boxTy = i->getOperand().getType().castTo(); + auto boxTy = i->getOperand()->getType().castTo(); emitDeallocateBox(*this, ownerPtr, boxTy); } @@ -3362,7 +3571,7 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { // Derive name from SIL location. VarDecl *Decl = i->getDecl(); - StringRef Name = i->getVarInfo().Name; + StringRef Name = getVarName(i); StringRef DbgName = # ifndef NDEBUG // If this is a DEBUG build, use pretty names for the LLVM IR. @@ -3370,15 +3579,10 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { # else ""; # endif - OwnedAddress addr; - - auto boxTy = i->getContainerResult().getType().castTo(); - addr = emitAllocateBox(*this, boxTy, DbgName); - Explosion box; - box.add(addr.getOwner()); - setLoweredExplosion(SILValue(i, 0), box); - setLoweredAddress(SILValue(i, 1), addr.getAddress()); + auto boxTy = i->getType().castTo(); + OwnedAddress boxWithAddr = emitAllocateBox(*this, boxTy, DbgName); + setLoweredBox(i, boxWithAddr); if (IGM.DebugInfo && Decl) { // FIXME: This is a workaround to not produce local variables for @@ -3389,25 +3593,35 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { if (Name == IGM.Context.Id_self.str()) return; + DebugTypeInfo DbgTy(Decl, i->getElementType().getSwiftType(), type); IGM.DebugInfo->emitVariableDeclaration( - Builder, emitShadowCopy(addr.getAddress(), Name), - DebugTypeInfo(Decl, i->getElementType().getSwiftType(), type), - i->getDebugScope(), Name, 0, IndirectValue); + Builder, + emitShadowCopy(boxWithAddr.getAddress(), i->getDebugScope(), Name, 0), + DbgTy, i->getDebugScope(), Name, 0, + DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue); } } void IRGenSILFunction::visitProjectBoxInst(swift::ProjectBoxInst *i) { - auto boxTy = i->getOperand().getType().castTo(); + auto boxTy = i->getOperand()->getType().castTo(); - Explosion box = getLoweredExplosion(i->getOperand()); - auto addr = emitProjectBox(*this, box.claimNext(), boxTy); - setLoweredAddress(SILValue(i,0), addr); + const LoweredValue &val = getLoweredValue(i->getOperand()); + if (val.isBoxWithAddress()) { + // The operand is an alloc_box. We can directly reuse the address. + setLoweredAddress(i, val.getAddressOfBox()); + } else { + // The slow-path: we have to emit code to get from the box to it's + // value address. + Explosion box = val.getExplosion(*this); + auto addr = emitProjectBox(*this, box.claimNext(), boxTy); + setLoweredAddress(i, addr); + } } void IRGenSILFunction::visitConvertFunctionInst(swift::ConvertFunctionInst *i) { // This instruction is specified to be a no-op. Explosion temp = getLoweredExplosion(i->getOperand()); - setLoweredExplosion(SILValue(i, 0), temp); + setLoweredExplosion(i, temp); } void IRGenSILFunction::visitThinFunctionToPointerInst( @@ -3437,7 +3651,7 @@ void IRGenSILFunction::visitAddressToPointerInst(swift::AddressToPointerInst *i) if (addrValue->getType() != IGM.Int8PtrTy) addrValue = Builder.CreateBitCast(addrValue, IGM.Int8PtrTy); to.add(addrValue); - setLoweredExplosion(SILValue(i, 0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitPointerToAddressInst(swift::PointerToAddressInst *i) @@ -3450,7 +3664,7 @@ void IRGenSILFunction::visitPointerToAddressInst(swift::PointerToAddressInst *i) llvm::Type *destType = ti.getStorageType()->getPointerTo(); ptrValue = Builder.CreateBitCast(ptrValue, destType); - setLoweredAddress(SILValue(i, 0), + setLoweredAddress(i, ti.getAddressForPointer(ptrValue)); } @@ -3482,7 +3696,7 @@ static void emitPointerCastInst(IRGenSILFunction &IGF, void IRGenSILFunction::visitUncheckedRefCastInst( swift::UncheckedRefCastInst *i) { auto &ti = getTypeInfo(i->getType()); - emitPointerCastInst(*this, i->getOperand(), SILValue(i, 0), ti); + emitPointerCastInst(*this, i->getOperand(), i, ti); } // TODO: Although runtime checks are not required, we get them anyway when @@ -3501,7 +3715,7 @@ void IRGenSILFunction::visitUncheckedAddrCastInst( auto addr = getLoweredAddress(i->getOperand()); auto &ti = getTypeInfo(i->getType()); auto result = Builder.CreateBitCast(addr,ti.getStorageType()->getPointerTo()); - setLoweredAddress(SILValue(i, 0), result); + setLoweredAddress(i, result); } static bool isStructurallySame(const llvm::Type *T1, const llvm::Type *T2) { @@ -3551,9 +3765,9 @@ static void emitUncheckedValueBitCast(IRGenSILFunction &IGF, const LoadableTypeInfo &outTI) { // If the transfer is doable bitwise, and if the elements of the explosion are // the same type, then just transfer the elements. - if (inTI.isBitwiseTakable(ResilienceScope::Component) && - outTI.isBitwiseTakable(ResilienceScope::Component) && - isStructurallySame(inTI.StorageType, outTI.StorageType)) { + if (inTI.isBitwiseTakable(ResilienceExpansion::Maximal) && + outTI.isBitwiseTakable(ResilienceExpansion::Maximal) && + isStructurallySame(inTI.getStorageType(), outTI.getStorageType())) { in.transferInto(out, in.size()); return; } @@ -3567,12 +3781,17 @@ static void emitUncheckedValueBitCast(IRGenSILFunction &IGF, outTI.getFixedAlignment()), "bitcast"); + auto maxSize = std::max(inTI.getFixedSize(), outTI.getFixedSize()); + IGF.Builder.CreateLifetimeStart(inStorage, maxSize); + // Store the 'in' value. inTI.initialize(IGF, in, inStorage); // Load the 'out' value as the destination type. auto outStorage = IGF.Builder.CreateBitCast(inStorage, outTI.getStorageType()->getPointerTo()); outTI.loadAsTake(IGF, outStorage, out); + + IGF.Builder.CreateLifetimeEnd(inStorage, maxSize); return; } @@ -3597,10 +3816,10 @@ void IRGenSILFunction::visitUncheckedTrivialBitCastInst( Explosion out; emitValueBitwiseCast(*this, i->getLoc().getSourceLoc(), - in, cast(getTypeInfo(i->getOperand().getType())), + in, cast(getTypeInfo(i->getOperand()->getType())), out, cast(getTypeInfo(i->getType()))); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction:: @@ -3609,21 +3828,21 @@ visitUncheckedBitwiseCastInst(swift::UncheckedBitwiseCastInst *i) { Explosion out; emitValueBitwiseCast(*this, i->getLoc().getSourceLoc(), - in, cast(getTypeInfo(i->getOperand().getType())), + in, cast(getTypeInfo(i->getOperand()->getType())), out, cast(getTypeInfo(i->getType()))); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction::visitRefToRawPointerInst( swift::RefToRawPointerInst *i) { auto &ti = getTypeInfo(i->getType()); - emitPointerCastInst(*this, i->getOperand(), SILValue(i, 0), ti); + emitPointerCastInst(*this, i->getOperand(), i, ti); } void IRGenSILFunction::visitRawPointerToRefInst(swift::RawPointerToRefInst *i) { auto &ti = getTypeInfo(i->getType()); - emitPointerCastInst(*this, i->getOperand(), SILValue(i, 0), ti); + emitPointerCastInst(*this, i->getOperand(), i, ti); } // SIL scalar conversions which never change the IR type. @@ -3632,8 +3851,8 @@ static void trivialRefConversion(IRGenSILFunction &IGF, SILValue input, SILValue result) { Explosion temp = IGF.getLoweredExplosion(input); - auto &inputTI = IGF.getTypeInfo(input.getType()); - auto &resultTI = IGF.getTypeInfo(result.getType()); + auto &inputTI = IGF.getTypeInfo(input->getType()); + auto &resultTI = IGF.getTypeInfo(result->getType()); // If the types are the same, forward the existing value. if (inputTI.getStorageType() == resultTI.getStorageType()) { @@ -3665,7 +3884,7 @@ static void trivialRefConversion(IRGenSILFunction &IGF, // FIXME: Except for optionals, which get bit-packed into an integer. #define NOOP_CONVERSION(KIND) \ void IRGenSILFunction::visit##KIND##Inst(swift::KIND##Inst *i) { \ - ::trivialRefConversion(*this, i->getOperand(), SILValue(i, 0)); \ + ::trivialRefConversion(*this, i->getOperand(), i); \ } NOOP_CONVERSION(UnownedToRef) NOOP_CONVERSION(RefToUnowned) @@ -3680,7 +3899,7 @@ void IRGenSILFunction::visitThinToThickFunctionInst( Explosion to; to.add(from.claimNext()); to.add(IGM.RefCountedNull); - setLoweredExplosion(SILValue(i, 0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *i){ @@ -3691,7 +3910,7 @@ void IRGenSILFunction::visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *i){ llvm::Value *classPtr = emitClassHeapMetadataRefForMetatype(*this, swiftMeta, instanceType); to.add(Builder.CreateBitCast(classPtr, IGM.ObjCClassPtrTy)); - setLoweredExplosion(SILValue(i, 0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitObjCToThickMetatypeInst( @@ -3703,7 +3922,7 @@ void IRGenSILFunction::visitObjCToThickMetatypeInst( Explosion to; auto metadata = emitObjCMetadataRefForMetadata(*this, classPtr); to.add(metadata); - setLoweredExplosion(SILValue(i, 0), to); + setLoweredExplosion(i, to); } /// Emit a checked cast sequence. Returns an Address; this may be either @@ -3714,7 +3933,7 @@ void emitValueCheckedCast(IRGenSILFunction &IGF, SILType loweredTargetType, CheckedCastMode mode, Explosion &ex) { - CanType sourceType = operand.getType().getSwiftRValueType(); + CanType sourceType = operand->getType().getSwiftRValueType(); CanType targetType = loweredTargetType.getSwiftRValueType(); if (auto sourceMetaType = dyn_cast(sourceType)) { @@ -3732,7 +3951,7 @@ void emitValueCheckedCast(IRGenSILFunction &IGF, if (auto existential = dyn_cast(targetType)) emitScalarExistentialDowncast(IGF, metatypeVal, - operand.getType(), loweredTargetType, + operand->getType(), loweredTargetType, mode, existential->getRepresentation(), ex); @@ -3763,13 +3982,13 @@ void emitValueCheckedCast(IRGenSILFunction &IGF, Explosion existential = IGF.getLoweredExplosion(operand); llvm::Value *instance = emitClassExistentialProjection(IGF, existential, - operand.getType(), + operand->getType(), CanArchetypeType()); llvm::Value *toValue; if (loweredTargetType.isExistentialType()) { emitScalarExistentialDowncast(IGF, instance, - operand.getType(), + operand->getType(), loweredTargetType, mode, None /*not a metatype*/, ex); @@ -3784,7 +4003,7 @@ void emitValueCheckedCast(IRGenSILFunction &IGF, if (targetType.isExistentialType()) { Explosion from = IGF.getLoweredExplosion(operand); llvm::Value *fromValue = from.claimNext(); - emitScalarExistentialDowncast(IGF, fromValue, operand.getType(), + emitScalarExistentialDowncast(IGF, fromValue, operand->getType(), loweredTargetType, mode, None /*not a metatype*/, ex); @@ -3803,7 +4022,7 @@ void IRGenSILFunction::visitUnconditionalCheckedCastInst( Explosion ex; emitValueCheckedCast(*this, i->getOperand(), i->getType(), CheckedCastMode::Unconditional, ex); - setLoweredExplosion(SILValue(i,0), ex); + setLoweredExplosion(i, ex); } void IRGenSILFunction::visitObjCMetatypeToObjectInst( @@ -3815,7 +4034,7 @@ void IRGenSILFunction::visitObjCMetatypeToObjectInst( value = Builder.CreateBitCast(value, IGM.UnknownRefCountedPtrTy); Explosion to; to.add(value); - setLoweredExplosion(SILValue(i,0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitObjCExistentialMetatypeToObjectInst( @@ -3829,7 +4048,7 @@ void IRGenSILFunction::visitObjCExistentialMetatypeToObjectInst( value = Builder.CreateBitCast(value, IGM.UnknownRefCountedPtrTy); Explosion to; to.add(value); - setLoweredExplosion(SILValue(i,0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitObjCProtocolInst(ObjCProtocolInst *i) { // Get the protocol reference. @@ -3839,7 +4058,7 @@ void IRGenSILFunction::visitObjCProtocolInst(ObjCProtocolInst *i) { getTypeInfo(i->getType()).getStorageType()); Explosion ex; ex.add(protoRef); - setLoweredExplosion(SILValue(i,0), ex); + setLoweredExplosion(i, ex); } void IRGenSILFunction::visitRefToBridgeObjectInst( @@ -3858,7 +4077,7 @@ void IRGenSILFunction::visitRefToBridgeObjectInst( Explosion resultEx; resultEx.add(val); - setLoweredExplosion(SILValue(i, 0), resultEx); + setLoweredExplosion(i, resultEx); } void IRGenSILFunction::visitBridgeObjectToRefInst( @@ -3929,7 +4148,7 @@ void IRGenSILFunction::visitBridgeObjectToRefInst( } resultEx.add(result); - setLoweredExplosion(SILValue(i,0), resultEx); + setLoweredExplosion(i, resultEx); } void IRGenSILFunction::visitBridgeObjectToWordInst( @@ -3939,7 +4158,7 @@ void IRGenSILFunction::visitBridgeObjectToWordInst( val = Builder.CreatePtrToInt(val, IGM.SizeTy); Explosion wordEx; wordEx.add(val); - setLoweredExplosion(SILValue(i, 0), wordEx); + setLoweredExplosion(i, wordEx); } void IRGenSILFunction::visitUnconditionalCheckedCastAddrInst( @@ -3959,7 +4178,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst( auto operand = i->getOperand(); Explosion source = getLoweredExplosion(operand); castResult = emitClassIdenticalCast(*this, source.claimNext(), - operand.getType(), destTy); + operand->getType(), destTy); } else { emitValueCheckedCast(*this, i->getOperand(), i->getCastType(), CheckedCastMode::Conditional, ex); @@ -3975,7 +4194,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst( auto &successBB = getLoweredBB(i->getSuccessBB()); - llvm::Type *toTy = IGM.getTypeInfo(destTy).StorageType; + llvm::Type *toTy = IGM.getTypeInfo(destTy).getStorageType(); if (toTy->isPointerTy()) castResult.casted = Builder.CreateBitCast(castResult.casted, toTy); @@ -4009,7 +4228,7 @@ void IRGenSILFunction::visitIsNonnullInst(swift::IsNonnullInst *i) { llvm::Value *val; const LoweredValue &lv = getLoweredValue(i->getOperand()); - if (i->getOperand().getType().getSwiftType()->is()) { + if (i->getOperand()->getType().getSwiftType()->is()) { Explosion values = lv.getExplosion(*this); val = values.claimNext(); // Function pointer. values.claimNext(); // Ignore the data pointer. @@ -4027,19 +4246,19 @@ void IRGenSILFunction::visitIsNonnullInst(swift::IsNonnullInst *i) { Explosion out; out.add(result); - setLoweredExplosion(SILValue(i, 0), out); + setLoweredExplosion(i, out); } void IRGenSILFunction::visitUpcastInst(swift::UpcastInst *i) { auto toTy = getTypeInfo(i->getType()).getSchema()[0].getScalarType(); // If we have an address, just bitcast, don't explode. - if (i->getOperand().getType().isAddress()) { + if (i->getOperand()->getType().isAddress()) { Address fromAddr = getLoweredAddress(i->getOperand()); llvm::Value *toValue = Builder.CreateBitCast( fromAddr.getAddress(), toTy->getPointerTo()); Address Addr(toValue, fromAddr.getAlignment()); - setLoweredAddress(SILValue(i, 0), Addr); + setLoweredAddress(i, Addr); return; } @@ -4048,7 +4267,7 @@ void IRGenSILFunction::visitUpcastInst(swift::UpcastInst *i) { assert(from.size() == 1 && "class should explode to single value"); llvm::Value *fromValue = from.claimNext(); to.add(Builder.CreateBitCast(fromValue, toTy)); - setLoweredExplosion(SILValue(i, 0), to); + setLoweredExplosion(i, to); } void IRGenSILFunction::visitIndexAddrInst(swift::IndexAddrInst *i) { @@ -4056,11 +4275,11 @@ void IRGenSILFunction::visitIndexAddrInst(swift::IndexAddrInst *i) { Explosion indexValues = getLoweredExplosion(i->getIndex()); llvm::Value *index = indexValues.claimNext(); - auto baseTy = i->getBase().getType(); + auto baseTy = i->getBase()->getType(); auto &ti = getTypeInfo(baseTy); Address dest = ti.indexArray(*this, base, index, baseTy); - setLoweredAddress(SILValue(i, 0), dest); + setLoweredAddress(i, dest); } void IRGenSILFunction::visitIndexRawPointerInst(swift::IndexRawPointerInst *i) { @@ -4075,32 +4294,37 @@ void IRGenSILFunction::visitIndexRawPointerInst(swift::IndexRawPointerInst *i) { Explosion result; result.add(destValue); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitAllocValueBufferInst( swift::AllocValueBufferInst *i) { Address buffer = getLoweredAddress(i->getOperand()); - Address value = emitAllocateBuffer(*this, i->getValueType(), buffer); - setLoweredAddress(SILValue(i, 0), value); + auto valueType = i->getValueType(); + Address value = + getTypeInfo(valueType).allocateBuffer(*this, buffer, valueType); + setLoweredAddress(i, value); } void IRGenSILFunction::visitProjectValueBufferInst( swift::ProjectValueBufferInst *i) { Address buffer = getLoweredAddress(i->getOperand()); - Address value = emitProjectBuffer(*this, i->getValueType(), buffer); - setLoweredAddress(SILValue(i, 0), value); + auto valueType = i->getValueType(); + Address value = + getTypeInfo(valueType).projectBuffer(*this, buffer, valueType); + setLoweredAddress(i, value); } void IRGenSILFunction::visitDeallocValueBufferInst( swift::DeallocValueBufferInst *i) { Address buffer = getLoweredAddress(i->getOperand()); - emitDeallocateBuffer(*this, i->getValueType(), buffer); + auto valueType = i->getValueType(); + getTypeInfo(valueType).deallocateBuffer(*this, buffer, valueType); } void IRGenSILFunction::visitInitExistentialAddrInst(swift::InitExistentialAddrInst *i) { Address container = getLoweredAddress(i->getOperand()); - SILType destType = i->getOperand().getType(); + SILType destType = i->getOperand()->getType(); Address buffer = emitOpaqueExistentialContainerInit(*this, container, destType, @@ -4111,48 +4335,13 @@ void IRGenSILFunction::visitInitExistentialAddrInst(swift::InitExistentialAddrIn auto &srcTI = getTypeInfo(i->getLoweredConcreteType()); // See if we can defer initialization of the buffer to a copy_addr into it. - if (tryDeferFixedSizeBufferInitialization(*this, i, srcTI, SILValue(), i, - buffer, "")) + if (tryDeferFixedSizeBufferInitialization(*this, i, srcTI, i, buffer, "")) return; - // Compute basic layout information about the type. If we have a - // concrete type, we need to know how it packs into a fixed-size - // buffer. If we don't, we need a value witness table. - - - FixedPacking packing; - bool needValueWitnessToAllocate; - if (!isa(srcTI)) { - packing = (FixedPacking) -1; - needValueWitnessToAllocate = true; - } else { - packing = srcTI.getFixedPacking(IGM); - needValueWitnessToAllocate = false; - } - - // Project down to the destination fixed-size buffer. - Address address = [&]{ - // If the type is provably empty, we're done. - if (srcTI.isKnownEmpty()) { - assert(packing == FixedPacking::OffsetZero); - return buffer; - } - - // Otherwise, allocate if necessary. - - if (needValueWitnessToAllocate) { - // If we're using a witness-table to do this, we need to emit a - // value-witness call to allocate the fixed-size buffer. - return Address(emitAllocateBufferCall(*this, i->getLoweredConcreteType(), - buffer), - Alignment(1)); - } else { - // Otherwise, allocate using what we know statically about the type. - return emitAllocateBuffer(*this, i->getLoweredConcreteType(), buffer); - } - }(); - - setLoweredAddress(SILValue(i, 0), address); + // Allocate in the destination fixed-size buffer. + Address address = + srcTI.allocateBuffer(*this, buffer, i->getLoweredConcreteType()); + setLoweredAddress(i, address); } void IRGenSILFunction::visitInitExistentialMetatypeInst( @@ -4162,9 +4351,9 @@ void IRGenSILFunction::visitInitExistentialMetatypeInst( emitExistentialMetatypeContainer(*this, result, i->getType(), metatype.claimNext(), - i->getOperand().getType(), + i->getOperand()->getType(), i->getConformances()); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitInitExistentialRefInst(InitExistentialRefInst *i) { @@ -4174,20 +4363,20 @@ void IRGenSILFunction::visitInitExistentialRefInst(InitExistentialRefInst *i) { result, i->getType(), instance.claimNext(), i->getFormalConcreteType(), - i->getOperand().getType(), + i->getOperand()->getType(), i->getConformances()); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitDeinitExistentialAddrInst( swift::DeinitExistentialAddrInst *i) { Address container = getLoweredAddress(i->getOperand()); emitOpaqueExistentialContainerDeinit(*this, container, - i->getOperand().getType()); + i->getOperand()->getType()); } void IRGenSILFunction::visitOpenExistentialAddrInst(OpenExistentialAddrInst *i) { - SILType baseTy = i->getOperand().getType(); + SILType baseTy = i->getOperand()->getType(); Address base = getLoweredAddress(i->getOperand()); auto openedArchetype = cast( @@ -4195,12 +4384,12 @@ void IRGenSILFunction::visitOpenExistentialAddrInst(OpenExistentialAddrInst *i) Address object = emitOpaqueExistentialProjection(*this, base, baseTy, openedArchetype); - setLoweredAddress(SILValue(i, 0), object); + setLoweredAddress(i, object); } void IRGenSILFunction::visitOpenExistentialRefInst(OpenExistentialRefInst *i) { - SILType baseTy = i->getOperand().getType(); + SILType baseTy = i->getOperand()->getType(); Explosion base = getLoweredExplosion(i->getOperand()); auto openedArchetype = cast( i->getType().getSwiftRValueType()); @@ -4210,12 +4399,12 @@ void IRGenSILFunction::visitOpenExistentialRefInst(OpenExistentialRefInst *i) { = emitClassExistentialProjection(*this, base, baseTy, openedArchetype); result.add(instance); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitOpenExistentialMetatypeInst( OpenExistentialMetatypeInst *i) { - SILType baseTy = i->getOperand().getType(); + SILType baseTy = i->getOperand()->getType(); Explosion base = getLoweredExplosion(i->getOperand()); auto openedTy = i->getType().getSwiftRValueType(); @@ -4223,16 +4412,16 @@ void IRGenSILFunction::visitOpenExistentialMetatypeInst( emitExistentialMetatypeProjection(*this, base, baseTy, openedTy); Explosion result; result.add(metatype); - setLoweredExplosion(SILValue(i, 0), result); + setLoweredExplosion(i, result); } void IRGenSILFunction::visitProjectBlockStorageInst(ProjectBlockStorageInst *i){ // TODO Address block = getLoweredAddress(i->getOperand()); Address capture = projectBlockStorageCapture(*this, block, - i->getOperand().getType().castTo()); + i->getOperand()->getType().castTo()); - setLoweredAddress(SILValue(i, 0), capture); + setLoweredAddress(i, capture); } void IRGenSILFunction::visitInitBlockStorageHeaderInst( @@ -4251,33 +4440,30 @@ void IRGenSILFunction::visitInitBlockStorageHeaderInst( // Initialize the header. emitBlockHeader(*this, addr, - i->getBlockStorage().getType().castTo(), - invokeFn, i->getInvokeFunction().getType().castTo()); + i->getBlockStorage()->getType().castTo(), + invokeFn, i->getInvokeFunction()->getType().castTo()); // Cast the storage to the block type to produce the result value. llvm::Value *asBlock = Builder.CreateBitCast(addr.getAddress(), IGM.ObjCBlockPtrTy); Explosion e; e.add(asBlock); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitAllocExistentialBoxInst(AllocExistentialBoxInst *i){ - Explosion box; - auto projectionAddr = - emitBoxedExistentialContainerAllocation(*this, box, i->getExistentialType(), + OwnedAddress boxWithAddr = + emitBoxedExistentialContainerAllocation(*this, i->getExistentialType(), i->getFormalConcreteType(), - i->getLoweredConcreteType(), i->getConformances()); - setLoweredExplosion(i->getExistentialResult(), box); - setLoweredAddress(i->getValueAddressResult(), projectionAddr); + setLoweredBox(i, boxWithAddr); } void IRGenSILFunction::visitDeallocExistentialBoxInst( DeallocExistentialBoxInst *i) { Explosion box = getLoweredExplosion(i->getOperand()); emitBoxedExistentialContainerDeallocation(*this, box, - i->getOperand().getType(), + i->getOperand()->getType(), i->getConcreteType()); } @@ -4285,15 +4471,30 @@ void IRGenSILFunction::visitOpenExistentialBoxInst(OpenExistentialBoxInst *i) { Explosion box = getLoweredExplosion(i->getOperand()); auto openedArchetype = cast(i->getType().getSwiftRValueType()); - auto addr = emitBoxedExistentialProjection(*this, box, - i->getOperand().getType(), - openedArchetype); - setLoweredAddress(SILValue(i,0), addr); + auto addr = emitOpenExistentialBox(*this, box, i->getOperand()->getType(), + openedArchetype); + setLoweredAddress(i, addr); +} + +void +IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) { + const LoweredValue &val = getLoweredValue(i->getOperand()); + if (val.isBoxWithAddress()) { + // The operand is an alloc_existential_box. + // We can directly reuse the address. + setLoweredAddress(i, val.getAddressOfBox()); + } else { + Explosion box = getLoweredExplosion(i->getOperand()); + auto caddr = emitBoxedExistentialProjection(*this, box, + i->getOperand()->getType(), + i->getType().getSwiftRValueType()); + setLoweredAddress(i, caddr.getAddress()); + } } void IRGenSILFunction::visitDynamicMethodInst(DynamicMethodInst *i) { assert(i->getMember().isForeign && "dynamic_method requires [objc] method"); - setLoweredObjCMethod(SILValue(i, 0), i->getMember()); + setLoweredObjCMethod(i, i->getMember()); return; } @@ -4301,36 +4502,37 @@ void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) { // For Objective-C classes we need to arrange for a msgSend // to happen when the method is called. if (i->getMember().isForeign) { - setLoweredObjCMethod(SILValue(i, 0), i->getMember()); + setLoweredObjCMethod(i, i->getMember()); return; } CanType baseTy = i->getLookupType(); - ProtocolConformance *conformance = i->getConformance(); + ProtocolConformanceRef conformance = i->getConformance(); SILDeclRef member = i->getMember(); + // It would be nice if this weren't discarded. + llvm::Value *baseMetadataCache = nullptr; + Explosion lowered; - emitWitnessMethodValue(*this, baseTy, member, conformance, lowered); + emitWitnessMethodValue(*this, baseTy, &baseMetadataCache, + member, conformance, lowered); - setLoweredExplosion(SILValue(i, 0), lowered); + setLoweredExplosion(i, lowered); } void IRGenSILFunction::setAllocatedAddressForBuffer(SILValue v, const Address &allocedAddress) { - assert(getLoweredValue(v).kind == LoweredValue::Kind::UnallocatedAddressInBuffer - && "not an unallocated address"); - - overwriteLoweredAddress(v, allocedAddress); + overwriteAllocatedAddress(v, allocedAddress); + // Emit the debug info for the variable if any. if (auto allocStack = dyn_cast(v)) { - emitDebugDeclarationForAllocStack(*this, allocStack, - getTypeInfo(v.getType()), - allocedAddress.getAddress()); + emitDebugInfoForAllocStack(allocStack, getTypeInfo(v->getType()), + allocedAddress.getAddress()); } } void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) { - SILType addrTy = i->getSrc().getType(); + SILType addrTy = i->getSrc()->getType(); Address src = getLoweredAddress(i->getSrc()); Address dest; bool isFixedBufferInitialization; @@ -4338,7 +4540,7 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) { auto &loweredDest = getLoweredValue(i->getDest()); if (loweredDest.isUnallocatedAddressInBuffer()) { isFixedBufferInitialization = true; - dest = loweredDest.getAddressOfUnallocatedBuffer(); + dest = loweredDest.getContainerOfAddress(); } else { isFixedBufferInitialization = false; dest = loweredDest.getAddress(); @@ -4380,10 +4582,50 @@ void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) { } } +static DeallocStackInst * +findPairedDeallocStackForDestroyAddr(DestroyAddrInst *destroyAddr) { + // This peephole only applies if the address being destroyed is the + // result of an alloc_stack. + auto allocStack = dyn_cast(destroyAddr->getOperand()); + if (!allocStack) return nullptr; + + for (auto inst = destroyAddr->getNextNode(); !isa(inst); + inst = inst->getNextNode()) { + // If we find a dealloc_stack of the right memory, great. + if (auto deallocStack = dyn_cast(inst)) + if (deallocStack->getOperand() == allocStack) + return deallocStack; + + // Otherwise, if the instruction uses the alloc_stack result, treat it + // as interfering. This assumes that any re-initialization of + // the alloc_stack will be obvious in the function. + for (auto &operand : inst->getAllOperands()) + if (operand.get() == allocStack) + return nullptr; + } + + // If we ran into the terminator, stop; only apply this peephole locally. + // TODO: this could use a fancier dominance analysis, maybe. + return nullptr; +} + void IRGenSILFunction::visitDestroyAddrInst(swift::DestroyAddrInst *i) { - SILType addrTy = i->getOperand().getType(); - Address base = getLoweredAddress(i->getOperand()); + SILType addrTy = i->getOperand()->getType(); const TypeInfo &addrTI = getTypeInfo(addrTy); + + // Try to fold a destroy_addr of a dynamic alloc_stack into a single + // destroyBuffer operation. + if (!isa(addrTI)) { + // If we can find a matching dealloc stack, just set an emission note + // on it; that will cause it to destroy the current value. + if (auto deallocStack = findPairedDeallocStackForDestroyAddr(i)) { + addEmissionNote(deallocStack); + return; + } + } + + // Otherwise, do the normal thing. + Address base = getLoweredAddress(i->getOperand()); addrTI.destroy(*this, base, addrTy); } @@ -4407,14 +4649,14 @@ void IRGenSILFunction::visitCondFailInst(swift::CondFailInst *i) { void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) { if (i->getMember().isForeign) { - setLoweredObjCMethodBounded(SILValue(i, 0), i->getMember(), - i->getOperand().getType(), + setLoweredObjCMethodBounded(i, i->getMember(), + i->getOperand()->getType(), /*startAtSuper=*/true); return; } auto base = getLoweredExplosion(i->getOperand()); - auto baseType = i->getOperand().getType(); + auto baseType = i->getOperand()->getType(); llvm::Value *baseValue = base.claimNext(); auto method = i->getMember(); @@ -4427,14 +4669,14 @@ void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) { fnValue = Builder.CreateBitCast(fnValue, IGM.Int8PtrTy); Explosion e; e.add(fnValue); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } void IRGenSILFunction::visitClassMethodInst(swift::ClassMethodInst *i) { // For Objective-C classes we need to arrange for a msgSend // to happen when the method is called. if (i->getMember().isForeign) { - setLoweredObjCMethod(SILValue(i, 0), i->getMember()); + setLoweredObjCMethod(i, i->getMember()); return; } @@ -4447,13 +4689,13 @@ void IRGenSILFunction::visitClassMethodInst(swift::ClassMethodInst *i) { // For Swift classes, get the method implementation from the vtable. // FIXME: better explosion kind, map as static. llvm::Value *fnValue = emitVirtualMethodValue(*this, baseValue, - i->getOperand().getType(), + i->getOperand()->getType(), method, methodType, /*useSuperVTable*/ false); fnValue = Builder.CreateBitCast(fnValue, IGM.Int8PtrTy); Explosion e; e.add(fnValue); - setLoweredExplosion(SILValue(i, 0), e); + setLoweredExplosion(i, e); } static llvm::Constant *getConstantValue(IRGenModule &IGM, llvm::StructType *STy, diff --git a/lib/IRGen/IndirectTypeInfo.h b/lib/IRGen/IndirectTypeInfo.h index 55d3d79462a7f..a64b061e3e5be 100644 --- a/lib/IRGen/IndirectTypeInfo.h +++ b/lib/IRGen/IndirectTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 97f6e9012a3cc..93b51864b8dd3 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -84,39 +84,38 @@ static void mangleClangDecl(raw_ostream &buffer, void LinkEntity::mangle(raw_ostream &buffer) const { // Almost everything below gets the common prefix: // mangled-name ::= '_T' global - Mangler mangler(buffer); + Mangler mangler; switch (getKind()) { // global ::= 'w' value-witness-kind type // value witness case Kind::ValueWitness: - buffer << "_Tw"; - buffer << mangleValueWitness(getValueWitness()); - - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); - return; + mangler.append("_Tw"); + mangler.append(mangleValueWitness(getValueWitness())); + mangler.mangleType(getType(), 0); + return mangler.finalize(buffer); // global ::= 'WV' type // value witness case Kind::ValueWitnessTable: - buffer << "_TWV"; - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); - return; + mangler.append("_TWV"); + mangler.mangleType(getType(), 0); + return mangler.finalize(buffer); // global ::= 't' type // Abstract type manglings just follow . case Kind::TypeMangling: - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); - return; + mangler.mangleType(getType(), 0); + return mangler.finalize(buffer); // global ::= 'Ma' type // type metadata access function case Kind::TypeMetadataAccessFunction: - buffer << "_TMa"; - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); - return; + mangler.append("_TMa"); + mangler.mangleType(getType(), 0); + return mangler.finalize(buffer); // global ::= 'ML' type // type metadata lazy cache variable case Kind::TypeMetadataLazyCacheVariable: - buffer << "_TML"; - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); - return; + mangler.append("_TML"); + mangler.mangleType(getType(), 0); + return mangler.finalize(buffer); // global ::= 'Mf' type // 'full' type metadata // global ::= 'M' directness type // type metadata @@ -130,91 +129,103 @@ void LinkEntity::mangle(raw_ostream &buffer) const { mangler.mangleTypeMetadataFull(getType(), isMetadataPattern()); break; } - return; + return mangler.finalize(buffer); // global ::= 'M' directness type // type metadata case Kind::ForeignTypeMetadataCandidate: mangler.mangleTypeMetadataFull(getType(), /*isPattern=*/false); - return; + return mangler.finalize(buffer); // global ::= 'Mm' type // class metaclass case Kind::SwiftMetaclassStub: - buffer << "_TMm"; + mangler.append("_TMm"); mangler.mangleNominalType(cast(getDecl()), - ResilienceExpansion::Minimal, Mangler::BindGenerics::None); - return; - + return mangler.finalize(buffer); + // global ::= 'Mn' type // nominal type descriptor case Kind::NominalTypeDescriptor: - buffer << "_TMn"; + mangler.append("_TMn"); mangler.mangleNominalType(cast(getDecl()), - ResilienceExpansion::Minimal, Mangler::BindGenerics::None); - return; + return mangler.finalize(buffer); // global ::= 'Mp' type // protocol descriptor case Kind::ProtocolDescriptor: - buffer << "_TMp"; + mangler.append("_TMp"); mangler.mangleProtocolName(cast(getDecl())); - return; - + return mangler.finalize(buffer); + // global ::= 'Wo' entity case Kind::WitnessTableOffset: - buffer << "_TWo"; + mangler.append("_TWo"); // Witness table entries for constructors always refer to the allocating // constructor. if (auto ctor = dyn_cast(getDecl())) mangler.mangleConstructorEntity(ctor, /*isAllocating=*/true, - getResilienceExpansion(), getUncurryLevel()); else - mangler.mangleEntity(getDecl(), getResilienceExpansion(), getUncurryLevel()); - return; + mangler.mangleEntity(getDecl(), getUncurryLevel()); + return mangler.finalize(buffer); // global ::= 'Wv' directness entity case Kind::FieldOffset: mangler.mangleFieldOffsetFull(getDecl(), isOffsetIndirect()); - return; - + return mangler.finalize(buffer); + // global ::= 'WP' protocol-conformance case Kind::DirectProtocolWitnessTable: - buffer << "_TWP"; + mangler.append("_TWP"); mangler.mangleProtocolConformance(getProtocolConformance()); - return; + return mangler.finalize(buffer); + + // global ::= 'WG' protocol-conformance + case Kind::GenericProtocolWitnessTableCache: + buffer << "_TWG"; + mangler.mangleProtocolConformance(getProtocolConformance()); + return mangler.finalize(buffer); + + // global ::= 'WI' protocol-conformance + case Kind::GenericProtocolWitnessTableInstantiationFunction: + buffer << "_TWI"; + mangler.mangleProtocolConformance(getProtocolConformance()); + return mangler.finalize(buffer); // global ::= 'Wa' protocol-conformance case Kind::ProtocolWitnessTableAccessFunction: - buffer << "_TWa"; + mangler.append("_TWa"); mangler.mangleProtocolConformance(getProtocolConformance()); - return; + return mangler.finalize(buffer); // global ::= 'Wl' type protocol-conformance case Kind::ProtocolWitnessTableLazyAccessFunction: - buffer << "_TWl"; - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); + mangler.append("_TWl"); + mangler.mangleType(getType(), 0); mangler.mangleProtocolConformance(getProtocolConformance()); - return; + return mangler.finalize(buffer); // global ::= 'WL' type protocol-conformance case Kind::ProtocolWitnessTableLazyCacheVariable: - buffer << "_TWL"; - mangler.mangleType(getType(), ResilienceExpansion::Minimal, 0); + mangler.append("_TWL"); + mangler.mangleType(getType(), 0); mangler.mangleProtocolConformance(getProtocolConformance()); - return; + return mangler.finalize(buffer); - // global ::= 'WD' protocol-conformance - case Kind::DependentProtocolWitnessTableGenerator: - buffer << "_TWD"; + // global ::= 'Wt' protocol-conformance identifier + case Kind::AssociatedTypeMetadataAccessFunction: + mangler.append("_TWt"); mangler.mangleProtocolConformance(getProtocolConformance()); - return; - - // global ::= 'Wd' protocol-conformance - case Kind::DependentProtocolWitnessTableTemplate: - buffer << "_TWd"; + mangler.mangleIdentifier(getAssociatedType()->getNameStr()); + return mangler.finalize(buffer); + + // global ::= 'WT' protocol-conformance identifier nominal-type + case Kind::AssociatedTypeWitnessTableAccessFunction: + mangler.append("_TWT"); mangler.mangleProtocolConformance(getProtocolConformance()); - return; + mangler.mangleIdentifier(getAssociatedType()->getNameStr()); + mangler.mangleProtocolDecl(getAssociatedProtocol()); + return mangler.finalize(buffer); // For all the following, this rule was imposed above: // global ::= local-marker? entity // some identifiable thing @@ -223,8 +234,8 @@ void LinkEntity::mangle(raw_ostream &buffer) const { case Kind::Function: // As a special case, functions can have external asm names. if (auto AsmA = getDecl()->getAttrs().getAttribute()) { - buffer << AsmA->Name; - return; + mangler.append(AsmA->Name); + return mangler.finalize(buffer); } // Otherwise, fall through into the 'other decl' case. @@ -235,54 +246,58 @@ void LinkEntity::mangle(raw_ostream &buffer) const { if (auto clangDecl = getDecl()->getClangDecl()) { if (auto namedClangDecl = dyn_cast(clangDecl)) { if (auto asmLabel = namedClangDecl->getAttr()) { - buffer << '\01' << asmLabel->getLabel(); + mangler.append('\01'); + mangler.append(asmLabel->getLabel()); } else if (namedClangDecl->hasAttr()) { // FIXME: When we can import C++, use Clang's mangler all the time. - mangleClangDecl(buffer, namedClangDecl, getDecl()->getASTContext()); + std::string storage; + llvm::raw_string_ostream SS(storage); + mangleClangDecl(SS, namedClangDecl, getDecl()->getASTContext()); + mangler.append(SS.str()); } else { - buffer << namedClangDecl->getName(); + mangler.append(namedClangDecl->getName()); } - return; + return mangler.finalize(buffer); } } - buffer << "_T"; + mangler.append("_T"); if (auto type = dyn_cast(getDecl())) { - mangler.mangleNominalType(type, getResilienceExpansion(), - Mangler::BindGenerics::None); + mangler.mangleNominalType(type, Mangler::BindGenerics::None); } else if (auto ctor = dyn_cast(getDecl())) { // FIXME: Hack. LinkInfo should be able to refer to the allocating // constructor rather than inferring it here. mangler.mangleConstructorEntity(ctor, /*isAllocating=*/true, - getResilienceExpansion(), getUncurryLevel()); } else { - mangler.mangleEntity(getDecl(), getResilienceExpansion(), getUncurryLevel()); + mangler.mangleEntity(getDecl(), getUncurryLevel()); } - return; + return mangler.finalize(buffer); // An Objective-C class reference; not a swift mangling. case Kind::ObjCClass: { - llvm::SmallString<64> nameBuffer; - buffer << "OBJC_CLASS_$_" - << cast(getDecl())->getObjCRuntimeName(nameBuffer); - return; + llvm::SmallString<64> TempBuffer; + mangler.append("OBJC_CLASS_$_"); + StringRef Name = cast(getDecl())->getObjCRuntimeName(TempBuffer); + mangler.append(Name); + return mangler.finalize(buffer); } // An Objective-C metaclass reference; not a swift mangling. case Kind::ObjCMetaclass: { - llvm::SmallString<64> nameBuffer; - buffer << "OBJC_METACLASS_$_" - << cast(getDecl())->getObjCRuntimeName(nameBuffer); - return; + llvm::SmallString<64> TempBuffer; + mangler.append("OBJC_METACLASS_$_"); + StringRef Name = cast(getDecl())->getObjCRuntimeName(TempBuffer); + mangler.append(Name); + return mangler.finalize(buffer); } case Kind::SILFunction: - buffer << getSILFunction()->getName(); - return; + mangler.appendSymbol(getSILFunction()->getName()); + return mangler.finalize(buffer); case Kind::SILGlobalVariable: - buffer << getSILGlobalVariable()->getName(); - return; + mangler.appendSymbol(getSILGlobalVariable()->getName()); + return mangler.finalize(buffer); } llvm_unreachable("bad entity kind!"); } diff --git a/lib/IRGen/Linking.h b/lib/IRGen/Linking.h index b74101ac2d20d..9af0616524333 100644 --- a/lib/IRGen/Linking.h +++ b/lib/IRGen/Linking.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -54,9 +54,8 @@ enum class TypeMetadataAddress { /// the information necessary to distinguish specific implementations /// of the declaration from each other. /// -/// For example, functions may be exploded or uncurried at different -/// levels, each of which potentially creates a different top-level -/// function. +/// For example, functions may be uncurried at different levels, each of +/// which potentially creates a different top-level function. class LinkEntity { /// ValueDecl*, SILFunction*, or TypeBase*, depending on Kind. void *Pointer; @@ -71,8 +70,7 @@ class LinkEntity { KindShift = 0, KindMask = 0xFF, // These fields appear in decl kinds. - ExplosionLevelShift = 8, ExplosionLevelMask = 0xFF00, - UncurryLevelShift = 16, UncurryLevelMask = 0xFF0000, + UncurryLevelShift = 8, UncurryLevelMask = 0xFF00, // This field appears in the ValueWitness kind. ValueWitnessShift = 8, ValueWitnessMask = 0xFF00, @@ -83,6 +81,9 @@ class LinkEntity { // These fields appear in the TypeMetadata kind. MetadataAddressShift = 8, MetadataAddressMask = 0x0300, IsPatternShift = 10, IsPatternMask = 0x0400, + + // This field appears in associated type access function kinds. + AssociatedTypeIndexShift = 8, AssociatedTypeIndexMask = ~KindMask, }; #define LINKENTITY_SET_FIELD(field, value) (value << field##Shift) #define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift) @@ -127,6 +128,8 @@ class LinkEntity { /// A SIL global variable. The pointer is a SILGlobalVariable*. SILGlobalVariable, + // These next few are protocol-conformance kinds. + /// A direct protocol witness table. The secondary pointer is a /// ProtocolConformance*. DirectProtocolWitnessTable, @@ -134,14 +137,25 @@ class LinkEntity { /// A witness accessor function. The secondary pointer is a /// ProtocolConformance*. ProtocolWitnessTableAccessFunction, + + /// A generic protocol witness table cache. The secondary pointer is a + /// ProtocolConformance*. + GenericProtocolWitnessTableCache, + + /// The instantiation function for a generic protocol witness table. + /// The secondary pointer is a ProtocolConformance*. + GenericProtocolWitnessTableInstantiationFunction, - /// A dependent protocol witness table instantiation function. The - /// secondary pointer is a ProtocolConformance*. - DependentProtocolWitnessTableGenerator, - - /// A template for dependent protocol witness table instantiation. The - /// secondary pointer is a ProtocolConformance*. - DependentProtocolWitnessTableTemplate, + /// A function which returns the type metadata for the associated type + /// of a protocol. The secondary pointer is a ProtocolConformance*. + /// The index of the associated type declaration is stored in the data. + AssociatedTypeMetadataAccessFunction, + + /// A function which returns the witness table for a protocol-constrained + /// associated type of a protocol. The secondary pointer is a + /// ProtocolConformance*. The primary pointer is a ProtocolDecl*. + /// The index of the associated type declaration is stored in the data. + AssociatedTypeWitnessTableAccessFunction, // These are both type kinds and protocol-conformance kinds. @@ -212,14 +226,11 @@ class LinkEntity { && k <= Kind::ProtocolWitnessTableLazyCacheVariable; } - void setForDecl(Kind kind, - ValueDecl *decl, ResilienceExpansion explosionKind, - unsigned uncurryLevel) { + void setForDecl(Kind kind, ValueDecl *decl, unsigned uncurryLevel) { assert(isDeclKind(kind)); Pointer = decl; SecondaryPointer = nullptr; Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) - | LINKENTITY_SET_FIELD(ExplosionLevel, unsigned(explosionKind)) | LINKENTITY_SET_FIELD(UncurryLevel, uncurryLevel); } @@ -238,6 +249,43 @@ class LinkEntity { Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)); } + void setForProtocolConformanceAndAssociatedType(Kind kind, + const ProtocolConformance *c, + AssociatedTypeDecl *associate, + ProtocolDecl *associatedProtocol = nullptr) { + assert(isProtocolConformanceKind(kind)); + Pointer = associatedProtocol; + SecondaryPointer = const_cast(static_cast(c)); + Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) | + LINKENTITY_SET_FIELD(AssociatedTypeIndex, + getAssociatedTypeIndex(c, associate)); + } + + // We store associated types using their index in their parent protocol + // in order to avoid bloating LinkEntity out to three key pointers. + static unsigned getAssociatedTypeIndex(const ProtocolConformance *conformance, + AssociatedTypeDecl *associate) { + assert(conformance->getProtocol() == associate->getProtocol()); + unsigned result = 0; + for (auto requirement : associate->getProtocol()->getMembers()) { + if (requirement == associate) return result; + if (isa(requirement)) result++; + } + llvm_unreachable("didn't find associated type in protocol?"); + } + + static AssociatedTypeDecl * + getAssociatedTypeByIndex(const ProtocolConformance *conformance, + unsigned index) { + for (auto requirement : conformance->getProtocol()->getMembers()) { + if (auto associate = dyn_cast(requirement)) { + if (index == 0) return associate; + index--; + } + } + llvm_unreachable("didn't find associated type in protocol?"); + } + void setForType(Kind kind, CanType type) { assert(isTypeKind(kind)); Pointer = type.getPointer(); @@ -252,16 +300,14 @@ class LinkEntity { assert(!isFunction(decl)); LinkEntity entity; - entity.setForDecl(Kind::Other, decl, ResilienceExpansion(0), 0); + entity.setForDecl(Kind::Other, decl, 0); return entity; } static LinkEntity forWitnessTableOffset(ValueDecl *decl, - ResilienceExpansion explosionKind, unsigned uncurryLevel) { LinkEntity entity; - entity.setForDecl(Kind::WitnessTableOffset, decl, - explosionKind, uncurryLevel); + entity.setForDecl(Kind::WitnessTableOffset, decl, uncurryLevel); return entity; } @@ -276,20 +322,19 @@ class LinkEntity { static LinkEntity forObjCClass(ClassDecl *decl) { LinkEntity entity; - entity.setForDecl(Kind::ObjCClass, decl, ResilienceExpansion::Minimal, 0); + entity.setForDecl(Kind::ObjCClass, decl, 0); return entity; } static LinkEntity forObjCMetaclass(ClassDecl *decl) { LinkEntity entity; - entity.setForDecl(Kind::ObjCMetaclass, decl, ResilienceExpansion::Minimal, 0); + entity.setForDecl(Kind::ObjCMetaclass, decl, 0); return entity; } static LinkEntity forSwiftMetaclassStub(ClassDecl *decl) { LinkEntity entity; - entity.setForDecl(Kind::SwiftMetaclassStub, - decl, ResilienceExpansion::Minimal, 0); + entity.setForDecl(Kind::SwiftMetaclassStub, decl, 0); return entity; } @@ -325,15 +370,13 @@ class LinkEntity { static LinkEntity forNominalTypeDescriptor(NominalTypeDecl *decl) { LinkEntity entity; - entity.setForDecl(Kind::NominalTypeDescriptor, - decl, ResilienceExpansion::Minimal, 0); + entity.setForDecl(Kind::NominalTypeDescriptor, decl, 0); return entity; } static LinkEntity forProtocolDescriptor(ProtocolDecl *decl) { LinkEntity entity; - entity.setForDecl(Kind::ProtocolDescriptor, - decl, ResilienceExpansion::Minimal, 0); + entity.setForDecl(Kind::ProtocolDescriptor, decl, 0); return entity; } @@ -389,6 +432,22 @@ class LinkEntity { return entity; } + static LinkEntity + forGenericProtocolWitnessTableCache(const ProtocolConformance *C) { + LinkEntity entity; + entity.setForProtocolConformance(Kind::GenericProtocolWitnessTableCache, C); + return entity; + } + + static LinkEntity + forGenericProtocolWitnessTableInstantiationFunction( + const ProtocolConformance *C) { + LinkEntity entity; + entity.setForProtocolConformance( + Kind::GenericProtocolWitnessTableInstantiationFunction, C); + return entity; + } + static LinkEntity forProtocolWitnessTableLazyAccessFunction(const ProtocolConformance *C, CanType type) { @@ -407,6 +466,26 @@ class LinkEntity { return entity; } + static LinkEntity + forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C, + AssociatedTypeDecl *associate) { + LinkEntity entity; + entity.setForProtocolConformanceAndAssociatedType( + Kind::AssociatedTypeMetadataAccessFunction, C, associate); + return entity; + } + + static LinkEntity + forAssociatedTypeWitnessTableAccessFunction(const ProtocolConformance *C, + AssociatedTypeDecl *associate, + ProtocolDecl *associateProtocol) { + LinkEntity entity; + entity.setForProtocolConformanceAndAssociatedType( + Kind::AssociatedTypeWitnessTableAccessFunction, C, associate, + associateProtocol); + return entity; + } + void mangle(llvm::raw_ostream &out) const; void mangle(SmallVectorImpl &buffer) const; @@ -436,11 +515,19 @@ class LinkEntity { assert(isProtocolConformanceKind(getKind())); return reinterpret_cast(SecondaryPointer); } - - ResilienceExpansion getResilienceExpansion() const { - assert(isDeclKind(getKind())); - return ResilienceExpansion(LINKENTITY_GET_FIELD(Data, ExplosionLevel)); + + AssociatedTypeDecl *getAssociatedType() const { + assert(getKind() == Kind::AssociatedTypeMetadataAccessFunction || + getKind() == Kind::AssociatedTypeWitnessTableAccessFunction); + return getAssociatedTypeByIndex(getProtocolConformance(), + LINKENTITY_GET_FIELD(Data, AssociatedTypeIndex)); + } + + ProtocolDecl *getAssociatedProtocol() const { + assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction); + return reinterpret_cast(Pointer); } + unsigned getUncurryLevel() const { return LINKENTITY_GET_FIELD(Data, UncurryLevel); } diff --git a/lib/IRGen/LoadableTypeInfo.h b/lib/IRGen/LoadableTypeInfo.h index 29e1bbec3ad3e..17d78762a2628 100644 --- a/lib/IRGen/LoadableTypeInfo.h +++ b/lib/IRGen/LoadableTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -113,7 +113,7 @@ class LoadableTypeInfo : public FixedTypeInfo { virtual void consume(IRGenFunction &IGF, Explosion &explosion) const = 0; /// Fix the lifetime of the source explosion by creating opaque calls to - /// swift_keepAlive for all reference types in the explosion. + /// swift_fixLifetime for all reference types in the explosion. virtual void fixLifetime(IRGenFunction &IGF, Explosion &explosion) const = 0; /// Pack the source explosion into an enum payload. @@ -129,7 +129,7 @@ class LoadableTypeInfo : public FixedTypeInfo { Explosion &targetExplosion, unsigned offset) const = 0; - /// Load a a reference counted pointer from an address. + /// Load a reference counted pointer from an address. /// Return the loaded pointer value. virtual LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc, Address addr) const; diff --git a/lib/IRGen/LocalTypeData.cpp b/lib/IRGen/LocalTypeData.cpp new file mode 100644 index 0000000000000..5ce75e2d075d0 --- /dev/null +++ b/lib/IRGen/LocalTypeData.cpp @@ -0,0 +1,437 @@ +//===--- LocalTypeData.cpp - Local type data search -----------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements routines for finding and caching local type data +// for a search. +// +//===----------------------------------------------------------------------===// + +#include "LocalTypeData.h" +#include "Fulfillment.h" +#include "GenMeta.h" +#include "GenProto.h" +#include "IRGenDebugInfo.h" +#include "IRGenFunction.h" +#include "IRGenModule.h" +#include "swift/AST/IRGenOptions.h" +#include "swift/SIL/SILModule.h" + +using namespace swift; +using namespace irgen; + +LocalTypeDataKey LocalTypeDataKey::getCachingKey() const { + return { Type, Kind.getCachingKind() }; +} + +LocalTypeDataKind LocalTypeDataKind::getCachingKind() const { + // Most local type data kinds are already canonical. + if (!isConcreteProtocolConformance()) return *this; + + // Map protocol conformances to their root normal conformance. + auto conformance = getConcreteProtocolConformance(); + return forConcreteProtocolWitnessTable( + conformance->getRootNormalConformance()); +} + +LocalTypeDataCache &IRGenFunction::getOrCreateLocalTypeData() { + // Lazily allocate it. + if (LocalTypeData) return *LocalTypeData; + LocalTypeData = new LocalTypeDataCache(); + return *LocalTypeData; +} + +void IRGenFunction::destroyLocalTypeData() { + delete LocalTypeData; +} + +unsigned LocalTypeDataCache::CacheEntry::cost() const { + switch (getKind()) { + case Kind::Concrete: + return static_cast(this)->cost(); + case Kind::Abstract: + return static_cast(this)->cost(); + } + llvm_unreachable("bad cache entry kind"); +} + +void LocalTypeDataCache::CacheEntry::erase() const { + switch (getKind()) { + case Kind::Concrete: + delete static_cast(this); + return; + case Kind::Abstract: + delete static_cast(this); + return; + } + llvm_unreachable("bad cache entry kind"); +} + +llvm::Value *IRGenFunction::getLocalTypeData(CanType type, + LocalTypeDataKind kind) { + assert(LocalTypeData); + return LocalTypeData->get(*this, LocalTypeDataCache::getKey(type, kind)); +} + +llvm::Value *IRGenFunction::tryGetConcreteLocalTypeData(LocalTypeDataKey key) { + if (!LocalTypeData) return nullptr; + return LocalTypeData->tryGet(*this, key, /*allow abstract*/ false); +} + +llvm::Value *IRGenFunction::tryGetLocalTypeData(LocalTypeDataKey key) { + if (!LocalTypeData) return nullptr; + return LocalTypeData->tryGet(*this, key); +} + +llvm::Value *LocalTypeDataCache::tryGet(IRGenFunction &IGF, Key key, + bool allowAbstract) { + auto it = Map.find(key); + if (it == Map.end()) return nullptr; + auto &chain = it->second; + + CacheEntry *best = nullptr, *bestPrev = nullptr; + Optional bestCost; + + CacheEntry *next = chain.Root, *nextPrev = nullptr; + while (next) { + CacheEntry *cur = next, *curPrev = nextPrev; + nextPrev = cur; + next = cur->getNext(); + + // Ignore abstract entries if so requested. + if (!allowAbstract && cur->getKind() != CacheEntry::Kind::Concrete) + continue; + + // Ignore unacceptable entries. + if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint)) + continue; + + // If there's a collision, compare by cost, ignoring higher-cost entries. + if (best) { + // Compute the cost of the best entry if we haven't done so already. + // If that's zero, go ahead and short-circuit out. + if (!bestCost) { + bestCost = best->cost(); + if (*bestCost == 0) break; + } + + auto curCost = cur->cost(); + if (curCost >= *bestCost) continue; + + // Replace the best cost and fall through. + bestCost = curCost; + } + best = cur; + bestPrev = curPrev; + } + + // If we didn't find anything, we're done. + if (!best) return nullptr; + + // Okay, we've found the best entry available. + switch (best->getKind()) { + + // For concrete caches, this is easy. + case CacheEntry::Kind::Concrete: + return static_cast(best)->Value; + + // For abstract caches, we need to follow a path. + case CacheEntry::Kind::Abstract: { + auto entry = static_cast(best); + + // Follow the path. + auto &source = AbstractSources[entry->SourceIndex]; + auto result = entry->follow(IGF, source); + + // Following the path automatically caches at every point along it, + // including the end. + assert(chain.Root->DefinitionPoint == IGF.getActiveDominancePoint()); + assert(chain.Root->getKind() == CacheEntry::Kind::Concrete); + + return result; + } + + } + llvm_unreachable("bad cache entry kind"); +} + +llvm::Value * +LocalTypeDataCache::AbstractCacheEntry::follow(IRGenFunction &IGF, + AbstractSource &source) const { + switch (source.getKind()) { + case AbstractSource::Kind::TypeMetadata: + return Path.followFromTypeMetadata(IGF, source.getType(), + source.getValue(), nullptr); + + case AbstractSource::Kind::ProtocolWitnessTable: + return Path.followFromWitnessTable(IGF, source.getType(), + source.getProtocolConformance(), + source.getValue(), nullptr); + } + llvm_unreachable("bad source kind"); +} + +static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF, + LocalTypeDataKey key, + llvm::Value *data) { + // Only if debug info is enabled. + if (!IGF.IGM.DebugInfo) return; + + // Only for type metadata. + if (key.Kind != LocalTypeDataKind::forTypeMetadata()) return; + + // Only for archetypes, and not for opened archetypes. + auto type = dyn_cast(key.Type); + if (!type) return; + if (type->getOpenedExistentialType()) return; + + // At -O0, create an alloca to keep the type alive. + auto name = type->getFullName(); + if (!IGF.IGM.Opts.Optimize) { + auto temp = IGF.createAlloca(data->getType(), IGF.IGM.getPointerAlignment(), + name); + IGF.Builder.CreateStore(data, temp); + data = temp.getAddress(); + } + + // Emit debug info for the metadata. + IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data, name); +} + +void IRGenFunction::setScopedLocalTypeData(LocalTypeDataKey key, + llvm::Value *data) { + maybeEmitDebugInfoForLocalTypeData(*this, key, data); + + // Register with the active ConditionalDominanceScope if necessary. + bool isConditional = isConditionalDominancePoint(); + if (isConditional) { + registerConditionalLocalTypeDataKey(key); + } + + getOrCreateLocalTypeData().addConcrete(getActiveDominancePoint(), + isConditional, key, data); +} + +void IRGenFunction::setUnscopedLocalTypeData(LocalTypeDataKey key, + llvm::Value *data) { + maybeEmitDebugInfoForLocalTypeData(*this, key, data); + + // This is supportable, but it would require ensuring that we add the + // entry after any conditional entries; otherwise the stack discipline + // will get messed up. + assert(!isConditionalDominancePoint() && + "adding unscoped local type data while in conditional scope"); + getOrCreateLocalTypeData().addConcrete(DominancePoint::universal(), + /*conditional*/ false, key, data); +} + +void IRGenFunction::bindLocalTypeDataFromTypeMetadata(CanType type, + IsExact_t isExact, + llvm::Value *metadata) { + // Remember that we have this type metadata concretely. + if (isExact) { + if (!metadata->hasName()) setTypeMetadataName(IGM, metadata, type); + setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), metadata); + } + + // Don't bother adding abstract fulfillments at a conditional dominance + // point; we're too likely to throw them all away. + if (isConditionalDominancePoint()) + return; + + getOrCreateLocalTypeData() + .addAbstractForTypeMetadata(*this, type, isExact, metadata); +} + +void LocalTypeDataCache::addAbstractForTypeMetadata(IRGenFunction &IGF, + CanType type, + IsExact_t isExact, + llvm::Value *metadata) { + // Look for anything at all that's fulfilled by this. If we don't find + // anything, stop. + FulfillmentMap fulfillments; + if (!fulfillments.searchTypeMetadata(*IGF.IGM.SILMod->getSwiftModule(), + type, isExact, + /*source*/ 0, MetadataPath(), + FulfillmentMap::Everything())) { + return; + } + + addAbstractForFulfillments(IGF, std::move(fulfillments), + [&]() -> AbstractSource { + return AbstractSource(type, metadata); + }); +} + +void LocalTypeDataCache:: +addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments, + llvm::function_ref createSource) { + // Add the source lazily. + Optional sourceIndex; + auto getSourceIndex = [&]() -> unsigned { + if (!sourceIndex) { + AbstractSources.emplace_back(createSource()); + sourceIndex = AbstractSources.size() - 1; + } + return *sourceIndex; + }; + + for (auto &fulfillment : fulfillments) { + CanType type = CanType(fulfillment.first.first); + LocalTypeDataKind localDataKind; + + // For now, ignore witness-table fulfillments when they're not for + // archetypes. + if (ProtocolDecl *protocol = fulfillment.first.second) { + if (auto archetype = dyn_cast(type)) { + auto conformsTo = archetype->getConformsTo(); + auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol); + if (it == conformsTo.end()) continue; + localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it); + } else { + continue; + } + + } else { + // Ignore type metadata fulfillments for non-dependent types that + // we can produce very cheaply. We don't want to end up emitting + // the type metadata for Int by chasing through N layers of metadata + // just because that path happens to be in the cache. + if (!type->hasArchetype() && + isTypeMetadataAccessTrivial(IGF.IGM, type)) { + continue; + } + + localDataKind = LocalTypeDataKind::forTypeMetadata(); + } + + // Find the chain for the key. + auto key = getKey(type, localDataKind); + auto &chain = Map[key]; + + // Check whether there's already an entry that's at least as good as the + // fulfillment. + Optional fulfillmentCost; + auto getFulfillmentCost = [&]() -> unsigned { + if (!fulfillmentCost) + fulfillmentCost = fulfillment.second.Path.cost(); + return *fulfillmentCost; + }; + + bool isConditional = IGF.isConditionalDominancePoint(); + + bool foundBetter = false; + for (CacheEntry *cur = chain.Root, *last = nullptr; cur; + last = cur, cur = cur->getNext()) { + // Ensure the entry is acceptable. + if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint)) + continue; + + // Ensure that the entry isn't better than the fulfillment. + auto curCost = cur->cost(); + if (curCost == 0 || curCost <= getFulfillmentCost()) { + foundBetter = true; + break; + } + + // If the entry is defined at the current point, (1) we know there + // won't be a better entry and (2) we should remove it. + if (cur->DefinitionPoint == IGF.getActiveDominancePoint() && + !isConditional) { + // Splice it out of the chain. + assert(!cur->isConditional()); + chain.eraseEntry(last, cur); + break; + } + } + if (foundBetter) continue; + + // Okay, make a new entry. + + // Register with the conditional dominance scope if necessary. + if (isConditional) { + IGF.registerConditionalLocalTypeDataKey(key); + } + + // Allocate the new entry. + auto newEntry = new AbstractCacheEntry(IGF.getActiveDominancePoint(), + isConditional, + getSourceIndex(), + std::move(fulfillment.second.Path)); + + // Add it to the front of the chain. + chain.push_front(newEntry); + } +} + +void LocalTypeDataCache::dump() const { + auto &out = llvm::errs(); + + if (Map.empty()) { + out << "(empty)\n"; + return; + } + + for (auto &mapEntry : Map) { + out << "(" << mapEntry.first.Type.getPointer() + << "," << mapEntry.first.Kind.getRawValue() << ") => ["; + if (mapEntry.second.Root) out << "\n"; + for (auto cur = mapEntry.second.Root; cur; cur = cur->getNext()) { + out << " ("; + if (cur->DefinitionPoint.isUniversal()) out << "universal"; + else out << cur->DefinitionPoint.as(); + out << ") "; + + if (cur->isConditional()) out << "conditional "; + + switch (cur->getKind()) { + case CacheEntry::Kind::Concrete: { + auto entry = static_cast(cur); + out << "concrete: " << entry->Value << "\n "; + if (!isa(entry->Value)) out << " "; + entry->Value->dump(); + break; + } + + case CacheEntry::Kind::Abstract: { + auto entry = static_cast(cur); + out << "abstract: source=" << entry->SourceIndex << "\n"; + break; + } + } + } + out << "]\n"; + } +} + +IRGenFunction::ConditionalDominanceScope::~ConditionalDominanceScope() { + IGF.ConditionalDominance = OldScope; + + // Remove any conditional entries from the chains that were added in this + // scope. + for (auto &key : RegisteredKeys) { + IGF.LocalTypeData->eraseConditional(key); + } +} + +void LocalTypeDataCache::eraseConditional(ArrayRef keys) { + for (auto &key : keys) { + auto &chain = Map[key]; + + // Our ability to simply delete the front of the chain relies on an + // assumption that (1) conditional additions always go to the front of + // the chain and (2) we never add something unconditionally while in + // an unconditional scope. + assert(chain.Root); + assert(chain.Root->isConditional()); + chain.eraseEntry(nullptr, chain.Root); + } +} diff --git a/lib/IRGen/LocalTypeData.h b/lib/IRGen/LocalTypeData.h new file mode 100644 index 0000000000000..91e948e3a8461 --- /dev/null +++ b/lib/IRGen/LocalTypeData.h @@ -0,0 +1,255 @@ +//===--- LocalTypeData.h - Dominance-scoped type data -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines types relating to the local caching of type data, +// such as type metadata, value witness tables, and protocol witness tables. +// +// Type data may be cached concretely, meaning that it was already fully +// computed, or abstractly, meaning that we remember how to recreate it +// but haven't actually done so yet. +// +// Type data may be cached at different points within a function. +// Some of these points may not dominate all possible use sites. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_LOCALTYPEDATA_H +#define SWIFT_IRGEN_LOCALTYPEDATA_H + +#include "LocalTypeDataKind.h" +#include "DominancePoint.h" +#include "MetadataPath.h" +#include "swift/AST/Type.h" +#include "llvm/ADT/STLExtras.h" +#include + +namespace swift { + class TypeBase; + +namespace irgen { + class FulfillmentMap; + enum IsExact_t : bool; + + +/// A cache of local type data. +/// +/// Basic design considerations: +/// +/// - We want to be able to efficiently look up a key and find something. +/// Generally this will find something from the entry block. We shouldn't +/// have to scan all the dominating points first. +/// +/// - We don't expect to have multiple definitions for a key very often. +/// Therefore, given a collision, it should be okay to scan a list and +/// ask whether each is acceptable. +class LocalTypeDataCache { +public: + using Key = LocalTypeDataKey; + + static Key getKey(CanType type, LocalTypeDataKind index) { + return { type, index }; + } + +private: + struct CacheEntry { + enum class Kind { + Concrete, Abstract + }; + + DominancePoint DefinitionPoint; + + private: + enum { KindMask = 0x1, ConditionalMask = 0x2 }; + llvm::PointerIntPair NextAndFlags; + + public: + Kind getKind() const { + return Kind(NextAndFlags.getInt() & KindMask); + } + CacheEntry *getNext() const { return NextAndFlags.getPointer(); } + void setNext(CacheEntry *next) { NextAndFlags.setPointer(next); } + + /// Return the abstract cost of evaluating this cache entry. + unsigned cost() const; + + /// Destruct and deallocate this cache entry. + void erase() const; + + bool isConditional() const { + return NextAndFlags.getInt() & ConditionalMask; + } + + protected: + CacheEntry(Kind kind, DominancePoint point, bool isConditional) + : DefinitionPoint(point), + NextAndFlags(nullptr, + unsigned(kind) | (isConditional ? ConditionalMask : 0)) { + } + ~CacheEntry() = default; + }; + + /// A concrete entry in the cache, which directly stores the desired value. + struct ConcreteCacheEntry : CacheEntry { + llvm::Value *Value; + + ConcreteCacheEntry(DominancePoint point, bool isConditional, + llvm::Value *value) + : CacheEntry(Kind::Concrete, point, isConditional), Value(value) {} + + unsigned cost() const { return 0; } + }; + + /// A source of concrete data from which abstract cache entries can be + /// derived. + class AbstractSource { + public: + enum class Kind { + TypeMetadata, + ProtocolWitnessTable, + }; + private: + CanType Type; + void *Conformance; + llvm::Value *Value; + + public: + explicit AbstractSource(CanType type, ProtocolConformanceRef conformance, + llvm::Value *value) + : Type(type), Conformance(conformance.getOpaqueValue()), Value(value) { + assert(Conformance != nullptr); + } + explicit AbstractSource(CanType type, llvm::Value *value) + : Type(type), Conformance(nullptr), Value(value) {} + + Kind getKind() const { + return (Conformance ? Kind::ProtocolWitnessTable : Kind::TypeMetadata); + } + + CanType getType() const { + return Type; + } + ProtocolConformanceRef getProtocolConformance() const { + assert(Conformance && "not a protocol conformance"); + return ProtocolConformanceRef::getFromOpaqueValue(Conformance); + } + llvm::Value *getValue() const { + return Value; + } + }; + + /// An abstract entry in the cache, which requires some amount of + /// non-trivial evaluation to derive the desired value. + struct AbstractCacheEntry : CacheEntry { + unsigned SourceIndex; + MetadataPath Path; + + AbstractCacheEntry(DominancePoint point, bool isConditional, + unsigned sourceIndex, MetadataPath &&path) + : CacheEntry(Kind::Abstract, point, isConditional), + SourceIndex(sourceIndex), Path(std::move(path)) {} + + llvm::Value *follow(IRGenFunction &IGF, AbstractSource &source) const; + + unsigned cost() const { return Path.cost(); } + }; + + /// The linked list of cache entries corresponding to a particular key. + struct CacheEntryChain { + CacheEntry *Root; + + explicit CacheEntryChain(CacheEntry *root = nullptr) : Root(root) {} + + CacheEntryChain(const CacheEntryChain &other) = delete; + CacheEntryChain &operator=(const CacheEntryChain &other) = delete; + + CacheEntryChain(CacheEntryChain &&other) : Root(other.Root) { + other.Root = nullptr; + } + CacheEntryChain &operator=(CacheEntryChain &&other) { + Root = other.Root; + other.Root = nullptr; + return *this; + } + + void push_front(CacheEntry *entry) { + entry->setNext(Root); + Root = entry; + } + + void eraseEntry(CacheEntry *prev, CacheEntry *entry) { + if (prev) { + assert(prev->getNext() == entry); + prev->setNext(entry->getNext()); + } else { + assert(Root == entry); + Root = entry->getNext(); + } + entry->erase(); + } + + /// Delete the linked list. + ~CacheEntryChain() { + auto next = Root; + while (next) { + auto cur = next; + next = cur->getNext(); + cur->erase(); + } + } + }; + + llvm::DenseMap Map; + + std::vector AbstractSources; + + void addAbstractForFulfillments(IRGenFunction &IGF, + FulfillmentMap &&fulfillments, + llvm::function_ref createSource); + + +public: + LocalTypeDataCache() = default; + LocalTypeDataCache(const LocalTypeDataCache &other) = delete; + LocalTypeDataCache &operator=(const LocalTypeDataCache &other) = delete; + + /// Load the value from cache if possible. This may require emitting + /// code if the value is cached abstractly. + llvm::Value *tryGet(IRGenFunction &IGF, Key key, bool allowAbstract = true); + + /// Load the value from cache, asserting its presence. + llvm::Value *get(IRGenFunction &IGF, Key key) { + auto result = tryGet(IGF, key); + assert(result && "get() on unmapped entry?"); + return result; + } + + /// Add a new concrete entry to the cache at the given definition point. + void addConcrete(DominancePoint point, bool isConditional, + Key key, llvm::Value *value) { + auto newEntry = new ConcreteCacheEntry(point, isConditional, value); + Map[key].push_front(newEntry); + } + + /// Add entries based on what can be fulfilled from the given type metadata. + void addAbstractForTypeMetadata(IRGenFunction &IGF, CanType type, + IsExact_t isExact, llvm::Value *metadata); + + void dump() const; + + // Private details for ConditionalDominanceScope. + void eraseConditional(ArrayRef keys); +}; + +} +} + +#endif diff --git a/lib/IRGen/LocalTypeDataCache.h b/lib/IRGen/LocalTypeDataCache.h new file mode 100644 index 0000000000000..0f726946bdda4 --- /dev/null +++ b/lib/IRGen/LocalTypeDataCache.h @@ -0,0 +1,141 @@ +//===-- LocalTypeDataCache.h - Dominance-scoped type data cache -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the LocalTypeDataCache type, which is used by +// IRGenFunction to cache the information available for types in a local +// context. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_LOCALTYPEDATACACHE_H +#define SWIFT_IRGEN_LOCALTYPEDATACACHE_H + +#include "swift/AST/Type.h" +#include + +namespace swift { +class TypeBase; + +namespace irgen { +enum class ValueWitness : unsigned; + +/// A nonce value for storing some sort of locally-known information +/// about a type. +class LocalTypeData { +public: + using RawType = unsigned; +private: + RawType Value; + + explicit LocalTypeData(unsigned Value) : Value(Value) {} + + /// Magic values for special kinds of index. + enum : RawType { + Metatype = ~0U, + ValueWitnessTable = ~1U, + + ValueWitnessBase = 0xFFFFFF00U, + }; + +public: + LocalTypeData() = default; + + // The magic values are all in the "negative" range and so do + // not collide with reasonable index values. + + /// A reference to the type metadata. + static LocalTypeData forMetatype() { return LocalTypeData(Metatype); } + /// A reference to the value witness table. + static LocalTypeData forValueWitnessTable() { + return LocalTypeData(ValueWitnessTable); + } + + /// A reference to a specific value witness. + static LocalTypeData forValueWitness(ValueWitness witness) { + return LocalTypeData((unsigned)witness + ValueWitnessBase); + } + + /// A reference to a protocol witness table for an archetype. + static LocalTypeData forArchetypeProtocolWitness(unsigned index) { + return LocalTypeData(index); + } + + RawType getRawValue() const { + return Value; + } +}; + +class LocalTypeDataCache { +public: + using Key = std::pair; + + static Key getKey(CanType type, LocalTypeData index) { + return Key(type.getPointer(), index.getRawValue()); + } + + /// An opaque class for storing keys for the dominance callback. The + /// key is assumed to be something like a pointer, and a null pointer is + /// assumed to mean a non-dominating point. + class DominanceKey { + void *Value; + public: + explicit DominanceKey(void *value = nullptr) : Value(value) {} + template T* as() const { return reinterpret_cast(Value); } + explicit operator bool() const { return Value != nullptr; } + }; + + /// A RAII object for managing a dominance scope. + class DominanceScope { + LocalTypeDataCache &Cache; + DominanceKey OldDefinitionPoint; + public: + explicit DominanceScope(LocalTypeDataCache &cache, DominanceKey newPoint) + : Cache(cache), OldDefinitionPoint(cache.ActiveDefinitionPoint) { + cache.ActiveDefinitionPoint = newPoint; + assert(!newPoint || cache.Callback); + } + + DominanceScope(const DominanceScope &other) = delete; + DominanceScope &operator=(const DominanceScope &other) = delete; + + ~DominanceScope() { + Cache.ActiveDefinitionPoint = OldDefinitionPoint; + } + }; + + using DominanceCallback = bool(IRGenFunction &IGF, DominanceKey key); + +private: + /// The dominance callback. This can be set at most once; when it's not + /// set, the cache must never have a non-null active definition point. + DominanceCallback *Callback = nullptr; + DominanceKey ActiveDefinitionPoint; + + struct CacheEntryBase { + DominanceKey DefinitionPoint; + + }; + + struct Source { + llvm::Value *Value; + MetadataPath::Map Path; + }; + + std::vector< + +public: +}; + +} +} + +#endif diff --git a/lib/IRGen/LocalTypeDataKind.h b/lib/IRGen/LocalTypeDataKind.h new file mode 100644 index 0000000000000..5fc3e86f692b0 --- /dev/null +++ b/lib/IRGen/LocalTypeDataKind.h @@ -0,0 +1,193 @@ +//===-- LocalTypeDataKind.h - Kinds of locally-cached type data -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file defines the LocalTypeDataKind class, which opaquely +// represents a particular kind of local type data that we might +// want to cache during emission. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IRGEN_LOCALTYPEDATAKIND_H +#define SWIFT_IRGEN_LOCALTYPEDATAKIND_H + +#include "swift/AST/ProtocolConformanceRef.h" +#include "swift/AST/Type.h" +#include +#include "llvm/ADT/DenseMapInfo.h" + +namespace swift { + class NormalProtocolConformance; + class ProtocolDecl; + +namespace irgen { + enum class ValueWitness : unsigned; + +/// The kind of local type data we might want to store for a type. +class LocalTypeDataKind { +public: + using RawType = uintptr_t; +private: + RawType Value; + + explicit LocalTypeDataKind(RawType Value) : Value(Value) {} + + /// Magic values for special kinds of type metadata. These should be + /// small so that they should never conflict with a valid pointer. + /// + /// Since this representation is opaque, we don't worry about being able + /// to distinguish different kinds of pointer; we just assume that e.g. a + /// ProtocolConformance will never have the same address as a Decl. + enum : RawType { + TypeMetadata, + ValueWitnessTable, + // <- add more special cases here + + // The first enumerator for an individual value witness. + ValueWitnessBase, + + FirstPayloadValue = 2048, + Kind_Decl = 0, + Kind_Conformance = 1, + KindMask = 0x1, + }; + +public: + LocalTypeDataKind() = default; + + // The magic values are all odd and so do not collide with pointer values. + + /// A reference to the type metadata. + static LocalTypeDataKind forTypeMetadata() { + return LocalTypeDataKind(TypeMetadata); + } + + /// A reference to the value witness table. + static LocalTypeDataKind forValueWitnessTable() { + return LocalTypeDataKind(ValueWitnessTable); + } + + /// A reference to a specific value witness. + static LocalTypeDataKind forValueWitness(ValueWitness witness) { + return LocalTypeDataKind(ValueWitnessBase + (unsigned)witness); + } + + /// A reference to a protocol witness table for an archetype. + /// + /// This only works for non-concrete types because in principle we might + /// have multiple concrete conformances for a concrete type used in the + /// same function. + static LocalTypeDataKind + forAbstractProtocolWitnessTable(ProtocolDecl *protocol) { + assert(protocol && "protocol reference may not be null"); + return LocalTypeDataKind(uintptr_t(protocol) | Kind_Decl); + } + + /// A reference to a protocol witness table for an archetype. + static LocalTypeDataKind + forConcreteProtocolWitnessTable(ProtocolConformance *conformance) { + assert(conformance && "conformance reference may not be null"); + return LocalTypeDataKind(uintptr_t(conformance) | Kind_Conformance); + } + + static LocalTypeDataKind + forProtocolWitnessTable(ProtocolConformanceRef conformance) { + if (conformance.isConcrete()) { + return forConcreteProtocolWitnessTable(conformance.getConcrete()); + } else { + return forAbstractProtocolWitnessTable(conformance.getAbstract()); + } + } + + LocalTypeDataKind getCachingKind() const; + + bool isSingletonKind() const { + return (Value < FirstPayloadValue); + } + + bool isConcreteProtocolConformance() const { + return (!isSingletonKind() && + ((Value & KindMask) == Kind_Conformance)); + } + + ProtocolConformance *getConcreteProtocolConformance() const { + assert(isConcreteProtocolConformance()); + return reinterpret_cast(Value - Kind_Conformance); + } + + bool isAbstractProtocolConformance() const { + return (!isSingletonKind() && + ((Value & KindMask) == Kind_Decl)); + } + + ProtocolDecl *getAbstractProtocolConformance() const { + assert(isAbstractProtocolConformance()); + return reinterpret_cast(Value - Kind_Decl); + } + + ProtocolConformanceRef getProtocolConformance() const { + assert(!isSingletonKind()); + if ((Value & KindMask) == Kind_Decl) { + return ProtocolConformanceRef(getAbstractProtocolConformance()); + } else { + return ProtocolConformanceRef(getConcreteProtocolConformance()); + } + } + + + RawType getRawValue() const { + return Value; + } + + bool operator==(LocalTypeDataKind other) const { + return Value == other.Value; + } + bool operator!=(LocalTypeDataKind other) const { + return Value != other.Value; + } +}; + +class LocalTypeDataKey { +public: + CanType Type; + LocalTypeDataKind Kind; + + LocalTypeDataKey getCachingKey() const; + + bool operator==(const LocalTypeDataKey &other) const { + return Type == other.Type && Kind == other.Kind; + } +}; + +} +} + +template <> struct llvm::DenseMapInfo { + using LocalTypeDataKey = swift::irgen::LocalTypeDataKey; + using CanTypeInfo = DenseMapInfo; + static inline LocalTypeDataKey getEmptyKey() { + return { CanTypeInfo::getEmptyKey(), + swift::irgen::LocalTypeDataKind::forTypeMetadata() }; + } + static inline LocalTypeDataKey getTombstoneKey() { + return { CanTypeInfo::getTombstoneKey(), + swift::irgen::LocalTypeDataKind::forTypeMetadata() }; + } + static unsigned getHashValue(const LocalTypeDataKey &key) { + return combineHashValue(CanTypeInfo::getHashValue(key.Type), + key.Kind.getRawValue()); + } + static bool isEqual(const LocalTypeDataKey &a, const LocalTypeDataKey &b) { + return a == b; + } +}; + +#endif diff --git a/lib/IRGen/MetadataLayout.h b/lib/IRGen/MetadataLayout.h index ed1f6f94603c0..687039ed1ed8d 100644 --- a/lib/IRGen/MetadataLayout.h +++ b/lib/IRGen/MetadataLayout.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/MetadataPath.h b/lib/IRGen/MetadataPath.h index a98a34ee8ee8b..86dd92fa25932 100644 --- a/lib/IRGen/MetadataPath.h +++ b/lib/IRGen/MetadataPath.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// // // This file defines the MetadataPath type, which efficiently records the -// path to an metadata object. +// path to a metadata object. // //===----------------------------------------------------------------------===// @@ -25,10 +25,13 @@ namespace llvm { } namespace swift { + class ProtocolDecl; class CanType; + class Decl; namespace irgen { class IRGenFunction; + class LocalTypeDataKey; /// A path from one source metadata --- either Swift type metadata or a Swift /// protocol conformance --- to another. @@ -46,6 +49,9 @@ class MetadataPath { // Everything past this point has at most one index. + /// Base protocol P of a protocol. + InheritedProtocol, + /// Type argument P of a generic nominal type. NominalTypeArgument, LastWithPrimaryIndex = NominalTypeArgument, @@ -168,6 +174,14 @@ class MetadataPath { argIndex, conformanceIndex)); } + /// Add a step to this path which gets the kth inherited protocol from a + /// witness table. + /// + /// k is computed including protocols which do not have witness tables. + void addInheritedProtocolComponent(unsigned index) { + Path.push_back(Component(Component::Kind::InheritedProtocol, index)); + } + /// Return an abstract measurement of the cost of this path. unsigned cost() const { unsigned cost = 0; @@ -184,22 +198,22 @@ class MetadataPath { /// Given a pointer to a protocol witness table, follow a path from it. llvm::Value *followFromWitnessTable(IRGenFunction &IGF, - ProtocolDecl *sourceDecl, + CanType conformingType, + ProtocolConformanceRef conformance, llvm::Value *source, Map *cache) const; private: static llvm::Value *follow(IRGenFunction &IGF, - CanType sourceType, - Decl *sourceDecl, + LocalTypeDataKey key, llvm::Value *source, MetadataPath::iterator begin, MetadataPath::iterator end, Map *cache); + /// Follow a single component of a metadata path. static llvm::Value *followComponent(IRGenFunction &IGF, - CanType &sourceType, - Decl *&sourceDecl, + LocalTypeDataKey &key, llvm::Value *source, Component component); }; diff --git a/lib/IRGen/NecessaryBindings.h b/lib/IRGen/NecessaryBindings.h index 1a41cb2b86f6a..2cb22ef180f8e 100644 --- a/lib/IRGen/NecessaryBindings.h +++ b/lib/IRGen/NecessaryBindings.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/NonFixedTypeInfo.h b/lib/IRGen/NonFixedTypeInfo.h index 4e76f0179048c..e5d01ff93cf70 100644 --- a/lib/IRGen/NonFixedTypeInfo.h +++ b/lib/IRGen/NonFixedTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,7 +15,7 @@ // statically. // // These classes are useful only for creating TypeInfo -// implementations; unlike the similiarly-named FixedTypeInfo, they +// implementations; unlike the similarly-named FixedTypeInfo, they // do not provide a supplemental API. // //===----------------------------------------------------------------------===// @@ -62,6 +62,7 @@ class WitnessSizedTypeInfo : public IndirectTypeInfo { const llvm::Twine &name) const override { // Make a fixed-size buffer. Address buffer = IGF.createFixedSizeBufferAlloca(name); + IGF.Builder.CreateLifetimeStart(buffer, getFixedBufferSize(IGF.IGM)); // Allocate an object of the appropriate type within it. llvm::Value *address = emitAllocateBufferCall(IGF, T, buffer); @@ -71,6 +72,13 @@ class WitnessSizedTypeInfo : public IndirectTypeInfo { void deallocateStack(IRGenFunction &IGF, Address buffer, SILType T) const override { emitDeallocateBufferCall(IGF, T, buffer); + IGF.Builder.CreateLifetimeEnd(buffer, getFixedBufferSize(IGF.IGM)); + } + + void destroyStack(IRGenFunction &IGF, Address buffer, + SILType T) const override { + emitDestroyBufferCall(IGF, T, buffer); + IGF.Builder.CreateLifetimeEnd(buffer, getFixedBufferSize(IGF.IGM)); } llvm::Value *getValueWitnessTable(IRGenFunction &IGF, SILType T) const { diff --git a/lib/IRGen/ProtocolInfo.h b/lib/IRGen/ProtocolInfo.h index 1b98a7838ae52..b827b812cda57 100644 --- a/lib/IRGen/ProtocolInfo.h +++ b/lib/IRGen/ProtocolInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -124,6 +124,20 @@ class WitnessTableEntry { assert(isAssociatedType()); return BeginIndex; } + + WitnessIndex + getAssociatedTypeWitnessTableIndex(ProtocolDecl *target) const { + assert(!BeginIndex.isPrefix()); + auto index = BeginIndex.getValue() + 1; + for (auto protocol : + cast(Member)->getConformingProtocols(nullptr)) { + if (protocol == target) { + return WitnessIndex(index, false); + } + index++; + } + llvm_unreachable("protocol not in direct conformance list?"); + } }; /// An abstract description of a protocol. @@ -164,17 +178,14 @@ class ProtocolInfo { ProtocolDecl *protocol, const ProtocolConformance *conf) const; + /// The number of witness slots in a conformance to this protocol; + /// in other words, the size of the table in words. unsigned getNumWitnesses() const { return NumWitnesses; } - unsigned getNumTableEntries() const { - return NumTableEntries; - } - ArrayRef getWitnessEntries() const { - return ArrayRef(getEntriesBuffer(), - getNumTableEntries()); + return ArrayRef(getEntriesBuffer(), NumTableEntries); } const WitnessTableEntry &getWitnessEntry(Decl *member) const { diff --git a/lib/IRGen/ReferenceTypeInfo.h b/lib/IRGen/ReferenceTypeInfo.h index 9fae5d3849094..1459ea71d6131 100644 --- a/lib/IRGen/ReferenceTypeInfo.h +++ b/lib/IRGen/ReferenceTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/ResilientTypeInfo.h b/lib/IRGen/ResilientTypeInfo.h index 158f19b7d1d62..3fd91f584c2ce 100644 --- a/lib/IRGen/ResilientTypeInfo.h +++ b/lib/IRGen/ResilientTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -49,74 +49,101 @@ class ResilientTypeInfo : public WitnessSizedTypeInfo { public: void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - emitAssignWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress()); + emitAssignWithCopyCall(IGF, T, dest, src); } void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - emitAssignWithTakeCall(IGF, T, - dest.getAddress(), src.getAddress()); + emitAssignWithTakeCall(IGF, T, dest, src); + } + + Address allocateBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const override { + auto addr = emitAllocateBufferCall(IGF, T, buffer); + return this->getAddressForPointer(addr); + } + + Address projectBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const override { + auto addr = emitProjectBufferCall(IGF, T, buffer); + return this->getAddressForPointer(addr); + } + + void destroyBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const override { + emitDestroyBufferCall(IGF, T, buffer); + } + + void deallocateBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const override { + emitDeallocateBufferCall(IGF, T, buffer); + } + + Address initializeBufferWithCopyOfBuffer(IRGenFunction &IGF, + Address dest, Address src, + SILType T) const override { + auto addr = emitInitializeBufferWithCopyOfBufferCall(IGF, T, dest, src); + return this->getAddressForPointer(addr); + } + + Address initializeBufferWithTakeOfBuffer(IRGenFunction &IGF, + Address dest, Address src, + SILType T) const override { + auto addr = emitInitializeBufferWithTakeOfBufferCall(IGF, T, dest, src); + return this->getAddressForPointer(addr); } Address initializeBufferWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - auto addr = emitInitializeBufferWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress()); + auto addr = emitInitializeBufferWithCopyCall(IGF, T, dest, src); return this->getAddressForPointer(addr); } Address initializeBufferWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - auto addr = emitInitializeBufferWithTakeCall(IGF, T, - dest.getAddress(), src.getAddress()); + auto addr = emitInitializeBufferWithTakeCall(IGF, T, dest, src); return this->getAddressForPointer(addr); } void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - emitInitializeWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress()); + emitInitializeWithCopyCall(IGF, T, dest, src); } void initializeArrayWithCopy(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const override { - emitInitializeArrayWithCopyCall(IGF, T, - dest.getAddress(), src.getAddress(), count); + emitInitializeArrayWithCopyCall(IGF, T, dest, src, count); } void initializeWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const override { - emitInitializeWithTakeCall(IGF, T, - dest.getAddress(), src.getAddress()); + emitInitializeWithTakeCall(IGF, T, dest, src); } void initializeArrayWithTakeFrontToBack(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const override { - emitInitializeArrayWithTakeFrontToBackCall(IGF, T, - dest.getAddress(), src.getAddress(), count); + emitInitializeArrayWithTakeFrontToBackCall(IGF, T, dest, src, count); } void initializeArrayWithTakeBackToFront(IRGenFunction &IGF, Address dest, Address src, llvm::Value *count, SILType T) const override { - emitInitializeArrayWithTakeBackToFrontCall(IGF, T, - dest.getAddress(), src.getAddress(), count); + emitInitializeArrayWithTakeBackToFrontCall(IGF, T, dest, src, count); } void destroy(IRGenFunction &IGF, Address addr, SILType T) const override { - emitDestroyCall(IGF, T, addr.getAddress()); + emitDestroyCall(IGF, T, addr); } void destroyArray(IRGenFunction &IGF, Address addr, llvm::Value *count, SILType T) const override { - emitDestroyArrayCall(IGF, T, addr.getAddress(), count); + emitDestroyArrayCall(IGF, T, addr, count); } bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { @@ -125,13 +152,13 @@ class ResilientTypeInfo : public WitnessSizedTypeInfo { llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, SILType T) const override { - return emitGetExtraInhabitantIndexCall(IGF, T, src.getAddress()); + return emitGetExtraInhabitantIndexCall(IGF, T, src); } void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, Address dest, SILType T) const override { - emitStoreExtraInhabitantCall(IGF, T, index, dest.getAddress()); + emitStoreExtraInhabitantCall(IGF, T, index, dest); } void initializeMetadata(IRGenFunction &IGF, diff --git a/lib/IRGen/RuntimeFunctions.def b/lib/IRGen/RuntimeFunctions.def index ab5371f6499fb..908f6858b7fcb 100644 --- a/lib/IRGen/RuntimeFunctions.def +++ b/lib/IRGen/RuntimeFunctions.def @@ -1,8 +1,8 @@ -//===-- RuntimeFunctions.def - Runtime Functions Database -------*- C++ -*-===// +//===--- RuntimeFunctions.def - Runtime Functions Database ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,7 +17,7 @@ /// FUNCTION(Id, Name, ReturnTys, ArgTys, CC, Attrs) /// Makes available as "Id" the following runtime function: -/// ReturnTy Name(ArgsTys...); +/// ReturnTy Name(ArgTys...); /// ReturnTys is a call to RETURNS, which takes a non-empty list /// of expressions meant to be looked up in IRGenModule. /// ArgTys is either NO_ARGS or a call to ARGS, which takes a non-empty @@ -150,12 +150,6 @@ FUNCTION(NativeUnpin, swift_unpin, RuntimeCC, ARGS(RefCountedPtrTy), ATTRS(NoUnwind)) -// void swift_fixLifetime(void *ptr); -FUNCTION(FixLifetime, swift_fixLifetime, RuntimeCC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind)) - // void swift_unknownRetain(void *ptr); FUNCTION(UnknownRetain, swift_unknownRetain, RuntimeCC, RETURNS(VoidTy), @@ -510,35 +504,16 @@ FUNCTION(AllocateGenericValueMetadata, swift_allocateGenericValueMetadata, ARGS(TypeMetadataPatternPtrTy, Int8PtrPtrTy), ATTRS(NoUnwind)) -// Metadata *swift_getGenericMetadata1(GenericMetadata *pattern, -// const void *arg0); -FUNCTION(GetGenericMetadata1, swift_getGenericMetadata1, RuntimeCC, - RETURNS(TypeMetadataPtrTy), - ARGS(TypeMetadataPatternPtrTy, Int8PtrTy), - ATTRS(NoUnwind, ReadNone)) - -// Metadata *swift_getGenericMetadata2(GenericMetadata *pattern, -// const void *arg0, const void *arg1); -FUNCTION(GetGenericMetadata2, swift_getGenericMetadata2, RuntimeCC, - RETURNS(TypeMetadataPtrTy), - ARGS(TypeMetadataPatternPtrTy, Int8PtrTy, Int8PtrTy), - ATTRS(NoUnwind, ReadNone)) - -// Metadata *swift_getGenericMetadata3(GenericMetadata *pattern, -// const void *arg0, const void *arg1, -// const void *arg2); -FUNCTION(GetGenericMetadata3, swift_getGenericMetadata3, RuntimeCC, - RETURNS(TypeMetadataPtrTy), - ARGS(TypeMetadataPatternPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy), - ATTRS(NoUnwind, ReadNone)) - -// Metadata *swift_getGenericMetadata4(GenericMetadata *pattern, -// const void *arg0, const void *arg1, -// const void *arg2, const void *arg3); -FUNCTION(GetGenericMetadata4, swift_getGenericMetadata4, RuntimeCC, - RETURNS(TypeMetadataPtrTy), - ARGS(TypeMetadataPatternPtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy, Int8PtrTy), - ATTRS(NoUnwind, ReadNone)) +// const ProtocolWitnessTable * +// swift_getGenericWitnessTable(GenericProtocolWitnessTable *genericTable, +// const Metadata *type, +// void * const *otherData); +FUNCTION(GetGenericWitnessTable, swift_getGenericWitnessTable, RuntimeCC, + RETURNS(WitnessTablePtrTy), + ARGS(getGenericWitnessTableCacheTy()->getPointerTo(), + TypeMetadataPtrTy, + Int8PtrPtrTy), + ATTRS(NoUnwind, ReadOnly)) // Metadata *swift_getMetatypeMetadata(Metadata *instanceTy); FUNCTION(GetMetatypeMetadata, swift_getMetatypeMetadata, RuntimeCC, @@ -559,11 +534,6 @@ FUNCTION(GetObjCClassMetadata, swift_getObjCClassMetadata, RuntimeCC, ARGS(ObjCClassPtrTy), ATTRS(NoUnwind, ReadNone)) -// _Bool swift_objcRespondsToSelector(id, void*); -FUNCTION(ObjCRespondsToSelector, swift_objcRespondsToSelector, C_CC, - RETURNS(Int1Ty), ARGS(ObjCPtrTy, Int8PtrTy), - ATTRS(NoUnwind, ReadOnly)) - // Metadata *swift_getTupleTypeMetadata(size_t numElements, // Metadata * const *elts, // const char *labels, @@ -601,23 +571,15 @@ FUNCTION(GetExistentialMetadata, ProtocolDescriptorPtrTy->getPointerTo()), ATTRS(NoUnwind, ReadOnly)) -// const char *swift_getGenericClassObjCName(Metadata *self); -FUNCTION(GetGenericClassObjCName, - swift_getGenericClassObjCName, RuntimeCC, - RETURNS(Int8PtrTy), - ARGS(TypeMetadataPtrTy), - ATTRS(NoUnwind)) - // struct FieldInfo { size_t Size; size_t AlignMask; }; // void swift_initClassMetadata_UniversalStrategy(Metadata *self, -// Metadata *super, // size_t numFields, // const FieldInfo *fields, // size_t *fieldOffsets); FUNCTION(InitClassMetadataUniversal, swift_initClassMetadata_UniversalStrategy, RuntimeCC, RETURNS(VoidTy), - ARGS(TypeMetadataPtrTy, TypeMetadataPtrTy, SizeTy, + ARGS(TypeMetadataPtrTy, SizeTy, SizeTy->getPointerTo(), SizeTy->getPointerTo()), ATTRS(NoUnwind)) @@ -874,10 +836,15 @@ FUNCTION(RegisterProtocolConformances, RETURNS(VoidTy), ARGS(ProtocolConformanceRecordPtrTy, ProtocolConformanceRecordPtrTy), ATTRS(NoUnwind)) +FUNCTION(RegisterTypeMetadataRecords, + swift_registerTypeMetadataRecords, RuntimeCC, + RETURNS(VoidTy), + ARGS(TypeMetadataRecordPtrTy, TypeMetadataRecordPtrTy), + ATTRS(NoUnwind)) FUNCTION(InitializeSuperclass, swift_initializeSuperclass, RuntimeCC, RETURNS(VoidTy), - ARGS(TypeMetadataPtrTy, TypeMetadataPtrTy), + ARGS(TypeMetadataPtrTy, Int1Ty), ATTRS(NoUnwind)) FUNCTION(InstantiateObjCClass, swift_instantiateObjCClass, RuntimeCC, RETURNS(VoidTy), @@ -966,8 +933,8 @@ FUNCTION(BlockRelease, _Block_release, C_CC, ARGS(ObjCBlockPtrTy), ATTRS(NoUnwind)) -// void swift_reportMissingMethod(); -FUNCTION(DeadMethodError, swift_reportMissingMethod, C_CC, +// void swift_deletedMethodError(); +FUNCTION(DeletedMethodError, swift_deletedMethodError, C_CC, RETURNS(VoidTy), ARGS(), ATTRS(NoUnwind)) diff --git a/lib/IRGen/ScalarTypeInfo.h b/lib/IRGen/ScalarTypeInfo.h index 1378632567335..1f434bb6fbfb1 100644 --- a/lib/IRGen/ScalarTypeInfo.h +++ b/lib/IRGen/ScalarTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index 0a1019f09099e..256a58ef0d769 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -1,8 +1,8 @@ -//===--- StructLayout.cpp - Layout of structures -------------------------===// +//===--- StructLayout.cpp - Layout of structures --------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -109,7 +109,7 @@ StructLayout::StructLayout(IRGenModule &IGM, CanType astTy, // If the struct is not @_fixed_layout, it will have a dynamic // layout outside of its resilience domain. if (astTy && astTy->getAnyNominal()) - if (IGM.isResilient(astTy->getAnyNominal(), ResilienceScope::Universal)) + if (IGM.isResilient(astTy->getAnyNominal(), ResilienceExpansion::Minimal)) IsKnownAlwaysFixedSize = IsNotFixedSize; assert(typeToFill == nullptr || Ty == typeToFill); @@ -208,12 +208,12 @@ bool StructLayoutBuilder::addFields(llvm::MutableArrayRef elts, // is Type; StructIndex and ByteOffset need to be laid out. for (auto &elt : elts) { auto &eltTI = elt.getType(); - IsKnownPOD &= eltTI.isPOD(ResilienceScope::Component); - IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceScope::Component); - IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceScope::Universal); + IsKnownPOD &= eltTI.isPOD(ResilienceExpansion::Maximal); + IsKnownBitwiseTakable &= eltTI.isBitwiseTakable(ResilienceExpansion::Maximal); + IsKnownAlwaysFixedSize &= eltTI.isFixedSize(ResilienceExpansion::Minimal); // If the element type is empty, it adds nothing. - if (eltTI.isKnownEmpty()) { + if (eltTI.isKnownEmpty(ResilienceExpansion::Maximal)) { addEmptyElement(elt); } else { // Anything else we do at least potentially adds storage requirements. @@ -307,7 +307,7 @@ void StructLayoutBuilder::addNonFixedSizeElement(ElementLayout &elt) { /// Add an empty element to the aggregate. void StructLayoutBuilder::addEmptyElement(ElementLayout &elt) { - elt.completeEmpty(elt.getType().isPOD(ResilienceScope::Component)); + elt.completeEmpty(elt.getType().isPOD(ResilienceExpansion::Maximal)); } /// Add an element at the fixed offset of the current end of the @@ -316,7 +316,7 @@ void StructLayoutBuilder::addElementAtFixedOffset(ElementLayout &elt) { assert(isFixedLayout()); auto &eltTI = cast(elt.getType()); - elt.completeFixed(elt.getType().isPOD(ResilienceScope::Component), + elt.completeFixed(elt.getType().isPOD(ResilienceExpansion::Maximal), CurSize, StructFields.size()); StructFields.push_back(elt.getType().getStorageType()); @@ -327,7 +327,7 @@ void StructLayoutBuilder::addElementAtFixedOffset(ElementLayout &elt) { /// Add an element at a non-fixed offset to the aggregate. void StructLayoutBuilder::addElementAtNonFixedOffset(ElementLayout &elt) { assert(!isFixedLayout()); - elt.completeNonFixed(elt.getType().isPOD(ResilienceScope::Component), + elt.completeNonFixed(elt.getType().isPOD(ResilienceExpansion::Maximal), NextNonFixedOffsetIndex); CurSpareBits.clear(); } @@ -337,7 +337,7 @@ void StructLayoutBuilder::addNonFixedSizeElementAtOffsetZero(ElementLayout &elt) assert(isFixedLayout()); assert(!isa(elt.getType())); assert(CurSize.isZero()); - elt.completeInitialNonFixedSize(elt.getType().isPOD(ResilienceScope::Component)); + elt.completeInitialNonFixedSize(elt.getType().isPOD(ResilienceExpansion::Maximal)); CurSpareBits.clear(); } diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h index ff347a9e5ad78..12335a0254a2a 100644 --- a/lib/IRGen/StructLayout.h +++ b/lib/IRGen/StructLayout.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -385,6 +385,49 @@ Size getHeapHeaderSize(IRGenModule &IGM); void addHeapHeaderToLayout(IRGenModule &IGM, Size &size, Alignment &align, SmallVectorImpl &fieldTypes); +/// Different policies for accessing a physical field. +enum class FieldAccess : uint8_t { + /// Instance variable offsets are constant. + ConstantDirect, + + /// Instance variable offsets must be loaded from "direct offset" + /// global variables. + NonConstantDirect, + + /// Instance variable offsets are kept in fields in metadata, but + /// the offsets of those fields within the metadata are constant. + ConstantIndirect, + + /// Instance variable offsets are kept in fields in metadata, and + /// the offsets of those fields within the metadata must be loaded + /// from "indirect offset" global variables. + NonConstantIndirect +}; + +struct ClassLayout { + /// Lazily-initialized array of all fragile stored properties in the class + /// (including superclass stored properties). + ArrayRef AllStoredProperties; + /// Lazily-initialized array of all fragile stored properties inherited from + /// superclasses. + ArrayRef InheritedStoredProperties; + /// Lazily-initialized array of all field access methods. + ArrayRef AllFieldAccesses; + /// Lazily-initialized metadata access method. See the comment in + /// ClassLayoutBuilder. + FieldAccess MetadataAccess; + /// Does the class require a metadata pattern. + bool HasMetadataPattern; + + unsigned getFieldIndex(VarDecl *field) const { + // FIXME: This is algorithmically terrible. + auto found = std::find(AllStoredProperties.begin(), + AllStoredProperties.end(), field); + assert(found != AllStoredProperties.end() && "didn't find field in type?!"); + return found - AllStoredProperties.begin(); + } +}; + } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/StructMetadataLayout.h b/lib/IRGen/StructMetadataLayout.h index fc798adfc6f28..2314696855349 100644 --- a/lib/IRGen/StructMetadataLayout.h +++ b/lib/IRGen/StructMetadataLayout.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp index eff27338c22d6..13b6197d203d0 100644 --- a/lib/IRGen/SwiftTargetInfo.cpp +++ b/lib/IRGen/SwiftTargetInfo.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -92,6 +92,13 @@ static void configureARM(IRGenModule &IGM, const llvm::Triple &triple, "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue"; } +/// Configures target-specific information for powerpc64 platforms. +static void configurePowerPC64(IRGenModule &IGM, const llvm::Triple &triple, + SwiftTargetInfo &target) { + setToMask(target.PointerSpareBits, 64, + SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK); +} + /// Configure a default target. SwiftTargetInfo::SwiftTargetInfo( llvm::Triple::ObjectFormatType outputObjectFormat, @@ -138,6 +145,11 @@ SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) { configureARM64(IGM, triple, target); break; + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + configurePowerPC64(IGM, triple, target); + break; + default: // FIXME: Complain here? Default target info is unlikely to be correct. break; diff --git a/lib/IRGen/SwiftTargetInfo.h b/lib/IRGen/SwiftTargetInfo.h index 5563694f45a5a..f71f0c5186978 100644 --- a/lib/IRGen/SwiftTargetInfo.h +++ b/lib/IRGen/SwiftTargetInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h index 31df850b92f9c..68cf2e2c5900d 100644 --- a/lib/IRGen/TypeInfo.h +++ b/lib/IRGen/TypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,6 +34,9 @@ namespace llvm { } namespace swift { + enum IsTake_t : bool; + class SILType; + namespace irgen { class Address; class ContainedAddress; @@ -107,11 +110,11 @@ class TypeInfo { return static_cast(*this); } +private: /// The LLVM representation of a stored value of this type. For /// non-fixed types, this is really useful only for forming pointers to it. llvm::Type *StorageType; -private: /// The storage alignment of this type in bytes. This is never zero /// for a completely-converted type. Alignment StorageAlignment; @@ -147,15 +150,15 @@ class TypeInfo { bool isComplete() const { return !StorageAlignment.isZero(); } /// Whether this type is known to be empty. - bool isKnownEmpty() const; + bool isKnownEmpty(ResilienceExpansion expansion) const; /// Whether this type is known to be POD, i.e. to not require any /// particular action on copy or destroy. - IsPOD_t isPOD(ResilienceScope scope) const { return IsPOD_t(POD); } + IsPOD_t isPOD(ResilienceExpansion expansion) const { return IsPOD_t(POD); } /// Whether this type is known to be bitwise-takable, i.e. "initializeWithTake" /// is equivalent to a memcpy. - IsBitwiseTakable_t isBitwiseTakable(ResilienceScope scope) const { + IsBitwiseTakable_t isBitwiseTakable(ResilienceExpansion expansion) const { return IsBitwiseTakable_t(BitwiseTakable); } @@ -188,11 +191,11 @@ class TypeInfo { /// Whether this type is known to be fixed-size in the given /// resilience domain. If true, spare bits can be used. - IsFixedSize_t isFixedSize(ResilienceScope scope) const { - switch (scope) { - case ResilienceScope::Component: + IsFixedSize_t isFixedSize(ResilienceExpansion expansion) const { + switch (expansion) { + case ResilienceExpansion::Maximal: return isFixedSize(); - case ResilienceScope::Universal: + case ResilienceExpansion::Minimal: // We can't be universally fixed size if we're not locally // fixed size. assert((isFixedSize() || AlwaysFixedSize == IsNotFixedSize) && @@ -260,6 +263,17 @@ class TypeInfo { virtual void deallocateStack(IRGenFunction &IGF, Address addr, SILType T) const = 0; + /// Destroy the value of a variable of this type, then deallocate its + /// memory. + virtual void destroyStack(IRGenFunction &IGF, Address addr, + SILType T) const = 0; + + /// Copy or take a value out of one address and into another, destroying + /// old value in the destination. Equivalent to either assignWithCopy + /// or assignWithTake depending on the value of isTake. + void assign(IRGenFunction &IGF, Address dest, Address src, IsTake_t isTake, + SILType T) const; + /// Copy a value out of an object and into another, destroying the /// old value in the destination. virtual void assignWithCopy(IRGenFunction &IGF, Address dest, @@ -270,6 +284,13 @@ class TypeInfo { virtual void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T) const = 0; + /// Copy-initialize or take-initialize an uninitialized object + /// with the value from a different object. Equivalent to either + /// initializeWithCopy or initializeWithTake depending on the value + /// of isTake. + void initialize(IRGenFunction &IGF, Address dest, Address src, + IsTake_t isTake, SILType T) const; + /// Perform a "take-initialization" from the given object. A /// take-initialization is like a C++ move-initialization, except that /// the old object is actually no longer permitted to be destroyed. @@ -280,6 +301,16 @@ class TypeInfo { virtual void initializeWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr, SILType T) const = 0; + /// Allocate space for an object of this type within an uninitialized + /// fixed-size buffer. + virtual Address allocateBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const; + + /// Project the address of an object of this type from an initialized + /// fixed-size buffer. + virtual Address projectBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const; + /// Perform a "take-initialization" from the given object into an /// uninitialized fixed-size buffer, allocating the buffer if necessary. /// Returns the address of the value inside the buffer. @@ -310,6 +341,54 @@ class TypeInfo { Address srcAddr, SILType T) const; + /// Perform a copy-initialization from the given fixed-size buffer + /// into an uninitialized fixed-size buffer, allocating the buffer if + /// necessary. Returns the address of the value inside the buffer. + /// + /// This is equivalent to: + /// auto srcAddress = projectBuffer(IGF, srcBuffer, T); + /// initializeBufferWithCopy(IGF, destBuffer, srcAddress, T); + /// but will be more efficient for dynamic types, since it uses a single + /// value witness call. + virtual Address initializeBufferWithCopyOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType T) const; + + /// Perform a take-initialization from the given fixed-size buffer + /// into an uninitialized fixed-size buffer, allocating the buffer if + /// necessary and deallocating the destination buffer. Returns the + /// address of the value inside the destination buffer. + /// + /// This is equivalent to: + /// auto srcAddress = projectBuffer(IGF, srcBuffer, T); + /// initializeBufferWithTake(IGF, destBuffer, srcAddress, T); + /// deallocateBuffer(IGF, srcBuffer, T); + /// but may be able to re-use the buffer from the source buffer, and may + /// be more efficient for dynamic types, since it uses a single + /// value witness call. + virtual Address initializeBufferWithTakeOfBuffer(IRGenFunction &IGF, + Address destBuffer, + Address srcBuffer, + SILType T) const; + + /// Destroy an object of this type within an initialized fixed-size buffer + /// and deallocate the buffer. + /// + /// This is equivalent to: + /// auto valueAddr = projectBuffer(IGF, buffer, T); + /// destroy(IGF, valueAddr, T); + /// deallocateBuffer(IGF, buffer, T); + /// but will be more efficient for dynamic types, since it uses a single + /// value witness call. + virtual void destroyBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const; + + /// Deallocate the space for an object of this type within an initialized + /// fixed-size buffer. + virtual void deallocateBuffer(IRGenFunction &IGF, Address buffer, + SILType T) const; + /// Take-initialize an address from a parameter explosion. virtual void initializeFromParams(IRGenFunction &IGF, Explosion ¶ms, Address src, SILType T) const = 0; @@ -321,7 +400,7 @@ class TypeInfo { /// for this type being a single object pointer? /// /// \return false by default - virtual bool isSingleRetainablePointer(ResilienceScope scope, + virtual bool isSingleRetainablePointer(ResilienceExpansion expansion, ReferenceCounting *refcounting = nullptr) const; @@ -329,9 +408,9 @@ class TypeInfo { /// for this type being a single Swift-retainable object pointer? /// /// \return false by default - bool isSingleSwiftRetainablePointer(ResilienceScope scope) const { + bool isSingleSwiftRetainablePointer(ResilienceExpansion expansion) const { ReferenceCounting refcounting; - return (isSingleRetainablePointer(scope, &refcounting) && + return (isSingleRetainablePointer(expansion, &refcounting) && refcounting == ReferenceCounting::Native); } diff --git a/lib/IRGen/TypeLayoutVerifier.cpp b/lib/IRGen/TypeLayoutVerifier.cpp index f3300d273e392..6f32b966181a6 100644 --- a/lib/IRGen/TypeLayoutVerifier.cpp +++ b/lib/IRGen/TypeLayoutVerifier.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -131,10 +131,10 @@ irgen::emitTypeLayoutVerifier(IRGenFunction &IGF, == FixedPacking::OffsetZero), "is-inline bit"); verify(emitLoadOfIsPOD(IGF, layoutType), - getBoolConstant(fixedTI->isPOD(ResilienceScope::Component)), + getBoolConstant(fixedTI->isPOD(ResilienceExpansion::Maximal)), "is-POD bit"); verify(emitLoadOfIsBitwiseTakable(IGF, layoutType), - getBoolConstant(fixedTI->isBitwiseTakable(ResilienceScope::Component)), + getBoolConstant(fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal)), "is-bitwise-takable bit"); unsigned xiCount = fixedTI->getFixedExtraInhabitantCount(IGF.IGM); verify(emitLoadOfHasExtraInhabitants(IGF, layoutType), @@ -149,8 +149,8 @@ irgen::emitTypeLayoutVerifier(IRGenFunction &IGF, // Verify that the extra inhabitant representations are consistent. - /* TODO: Update for EnumPayload implementation changes. - + // TODO: Update for EnumPayload implementation changes. +#if 0 auto xiBuf = IGF.createAlloca(fixedTI->getStorageType(), fixedTI->getFixedAlignment(), "extra-inhabitant"); @@ -212,7 +212,7 @@ irgen::emitTypeLayoutVerifier(IRGenFunction &IGF, llvm::Twine("extra inhabitant index calculation ") + numberBuf.str()); } - */ +#endif } // TODO: Verify interesting layout properties specific to the kind of type, diff --git a/lib/IRGen/TypeVisitor.h b/lib/IRGen/TypeVisitor.h index dbddd7cbe0df0..8e9c9f2447f5d 100644 --- a/lib/IRGen/TypeVisitor.h +++ b/lib/IRGen/TypeVisitor.h @@ -1,8 +1,8 @@ -//===-- TypeVisitor.h - IR-gen TypeVisitor specialization -------*- C++ -*-===// +//===--- TypeVisitor.h - IR-gen TypeVisitor specialization ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/IRGen/UnimplementedTypeInfo.cpp b/lib/IRGen/UnimplementedTypeInfo.cpp deleted file mode 100644 index 27fe76773cb0c..0000000000000 --- a/lib/IRGen/UnimplementedTypeInfo.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//===--- UnimplementedTypeInfo.cpp - Unimplemented Type Lowering ----------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file implements a stub TypeInfo for unimplemented types. -// -//===----------------------------------------------------------------------===// - -#include "IRGenModule.h" -#include "IRGenFunction.h" -#include "UnimplementedTypeInfo.h" -#include "swift/SIL/SILType.h" - -using namespace swift; -using namespace irgen; - -UnimplementedTypeInfo::UnimplementedTypeInfo(IRGenModule &IGM, - llvm::Type *storageTy) - : TypeInfo(storageTy, - Alignment(1), - IsNotPOD, - IsNotBitwiseTakable, - IsFixedSize, - STIK_Unimplemented) -{} - -static llvm::Constant * -getUndefSize(IRGenModule &IGM) { - return llvm::UndefValue::get(IGM.SizeTy); -} - -static llvm::Constant * -getUndefOpaqueAddressValue(llvm::Type *storageTy) { - return llvm::UndefValue::get(storageTy->getPointerTo()); -} - -static Address -getUndefOpaqueAddress(llvm::Type *storageTy) { - return Address(getUndefOpaqueAddressValue(storageTy), Alignment(1)); -} - -std::pair -UnimplementedTypeInfo::getSizeAndAlignmentMask(IRGenFunction &IGF, SILType T) -const -{ - llvm::Value *undef = getUndefSize(IGF.IGM); - return {undef, undef}; -} - -std::tuple -UnimplementedTypeInfo::getSizeAndAlignmentMaskAndStride(IRGenFunction &IGF, - SILType T) const { - llvm::Value *undef = getUndefSize(IGF.IGM); - return std::make_tuple(undef, undef, undef); -} - -llvm::Value *UnimplementedTypeInfo::getSize(IRGenFunction &IGF, SILType T) -const { - return getUndefSize(IGF.IGM); -} -llvm::Value *UnimplementedTypeInfo::getAlignmentMask(IRGenFunction &IGF, - SILType T) const { - return getUndefSize(IGF.IGM); -} -llvm::Value *UnimplementedTypeInfo::getStride(IRGenFunction &IGF, SILType T) -const { - return getUndefSize(IGF.IGM); -} -llvm::Value *UnimplementedTypeInfo::getIsPOD(IRGenFunction &IGF, SILType T) -const { - return llvm::UndefValue::get(IGF.IGM.Int1Ty); -} -llvm::Constant *UnimplementedTypeInfo::getStaticSize(IRGenModule &IGM) const { - return nullptr; -} -llvm::Constant *UnimplementedTypeInfo::getStaticAlignmentMask(IRGenModule &IGM) -const { - return nullptr; -} -llvm::Constant *UnimplementedTypeInfo::getStaticStride(IRGenModule &IGM) -const { - return nullptr; -} - -void UnimplementedTypeInfo::getSchema(ExplosionSchema &schema) const { -} - -ContainedAddress UnimplementedTypeInfo::allocateStack(IRGenFunction &IGF, - SILType T, - const llvm::Twine &name) -const { - return ContainedAddress(Address(llvm::UndefValue::get(IGF.IGM.getFixedBufferTy()), - IGF.IGM.getPointerAlignment()), - getUndefOpaqueAddress(getStorageType())); -} - -void UnimplementedTypeInfo::deallocateStack(IRGenFunction &IGF, Address addr, - SILType T) const { - -} - -void UnimplementedTypeInfo::assignWithCopy(IRGenFunction &IGF, Address dest, - Address src, SILType T) const { - -} - -void UnimplementedTypeInfo::assignWithTake(IRGenFunction &IGF, Address dest, - Address src, SILType T) const { - -} - -void UnimplementedTypeInfo::initializeWithTake(IRGenFunction &IGF, Address dest, - Address src, SILType T) const { - -} - -void UnimplementedTypeInfo::initializeWithCopy(IRGenFunction &IGF, Address dest, - Address src, SILType T) const { - -} - -void UnimplementedTypeInfo::initializeFromParams(IRGenFunction &IGF, - Explosion ¶ms, - Address src, SILType T) const { - -} - -void UnimplementedTypeInfo::destroy(IRGenFunction &IGF, Address address, - SILType T) const { - -} - -bool UnimplementedTypeInfo::mayHaveExtraInhabitants(IRGenModule &IGM) const { - return false; -} - -llvm::Value *UnimplementedTypeInfo::getExtraInhabitantIndex(IRGenFunction &IGF, - Address src, - SILType T) const { - return llvm::UndefValue::get(IGF.IGM.Int32Ty); -} - -void UnimplementedTypeInfo::storeExtraInhabitant(IRGenFunction &IGF, - llvm::Value *index, - Address dest, - SILType T) const { - -} -void UnimplementedTypeInfo::initializeMetadata(IRGenFunction &IGF, - llvm::Value *metadata, - llvm::Value *vwtable, - SILType T) const { - -} - -llvm::Value *UnimplementedTypeInfo::isDynamicallyPackedInline(IRGenFunction &IGF, - SILType T) const { - return llvm::UndefValue::get(IGF.IGM.Int1Ty); -} diff --git a/lib/IRGen/UnimplementedTypeInfo.h b/lib/IRGen/UnimplementedTypeInfo.h deleted file mode 100644 index 4123ba9d79e1e..0000000000000 --- a/lib/IRGen/UnimplementedTypeInfo.h +++ /dev/null @@ -1,86 +0,0 @@ -//===--- UnimplementedTypeInfo.h - Stub for implemented layout --*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This TypeInfo implementation stubs out all type info operations to -// simply return 'undef'. It is intended to be used to allow recovery from -// unimplemented type layout. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_IRGEN_UNIMPLEMENTEDTYPEINFO_H -#define SWIFT_IRGEN_UNIMPLEMENTEDTYPEINFO_H - -#include "TypeInfo.h" - -namespace swift { -namespace irgen { - -class UnimplementedTypeInfo : public TypeInfo { -public: - UnimplementedTypeInfo(IRGenModule &IGM, llvm::Type *storageTy); - - std::pair - getSizeAndAlignmentMask(IRGenFunction &IGF, SILType T) const override; - - std::tuple - getSizeAndAlignmentMaskAndStride(IRGenFunction &IGF, SILType T) const override; - - llvm::Value *getSize(IRGenFunction &IGF, SILType T) const override; - llvm::Value *getAlignmentMask(IRGenFunction &IGF, SILType T) const override; - llvm::Value *getStride(IRGenFunction &IGF, SILType T) const override; - llvm::Value *getIsPOD(IRGenFunction &IGF, SILType T) const override; - llvm::Constant *getStaticSize(IRGenModule &IGM) const override; - llvm::Constant *getStaticAlignmentMask(IRGenModule &IGM) const override; - llvm::Constant *getStaticStride(IRGenModule &IGM) const override; - void getSchema(ExplosionSchema &schema) const override; - ContainedAddress allocateStack(IRGenFunction &IGF, - SILType T, - const llvm::Twine &name) const override; - void deallocateStack(IRGenFunction &IGF, Address addr, - SILType T) const override; - void assignWithCopy(IRGenFunction &IGF, Address dest, - Address src, SILType T) const override; - void assignWithTake(IRGenFunction &IGF, Address dest, - Address src, SILType T) const override; - void initializeWithTake(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T) const override; - void initializeWithCopy(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T) const override; - void initializeFromParams(IRGenFunction &IGF, Explosion ¶ms, - Address src, SILType T) const override; - void destroy(IRGenFunction &IGF, Address address, SILType T) const override; - bool mayHaveExtraInhabitants(IRGenModule &IGM) const override; - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, - Address src, - SILType T) const override; - void storeExtraInhabitant(IRGenFunction &IGF, - llvm::Value *index, - Address dest, - SILType T) const override; - void initializeMetadata(IRGenFunction &IGF, - llvm::Value *metadata, - llvm::Value *vwtable, - SILType T) const override; - - llvm::Value *isDynamicallyPackedInline(IRGenFunction &IGF, - SILType T) const override; - - static bool classof(const TypeInfo *type) { - return type->getSpecialTypeInfoKind() <= STIK_Unimplemented; - } -}; - -} -} - -#endif - diff --git a/lib/IRGen/ValueWitness.h b/lib/IRGen/ValueWitness.h index 2ebe44c7c1abe..937bfac295836 100644 --- a/lib/IRGen/ValueWitness.h +++ b/lib/IRGen/ValueWitness.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -83,7 +83,7 @@ enum class ValueWitness : unsigned { /// T *(*initializeBufferWithCopyOfBuffer)(B *dest, B *src, M *self); /// Given an invalid buffer, initialize it as a copy of the /// object in the source buffer. This can be decomposed as: - /// initalizeBufferWithCopy(dest, self->projectBuffer(src), self) + /// initializeBufferWithCopy(dest, self->projectBuffer(src), self) InitializeBufferWithCopyOfBuffer, /// T *(*projectBuffer)(B *buffer, M *self); @@ -156,13 +156,13 @@ enum class ValueWitness : unsigned { /// T *(*initializeBufferWithTakeOfBuffer)(B *dest, B *src, M *self); /// Given an invalid buffer, initialize it by taking the value out of /// the source buffer. This can be (inefficiently) decomposed as: - /// initalizeBufferWithTake(dest, self->projectBuffer(src), self) + /// initializeBufferWithTake(dest, self->projectBuffer(src), self) /// deallocateBuffer(src, self) InitializeBufferWithTakeOfBuffer, /// void (*destroyArray)(T *object, size_t n, witness_t *self); /// - /// Given a vaild array of n objects of this type, destroy the object, leaving + /// Given a valid array of n objects of this type, destroy the object, leaving /// the array invalid. This is useful when generically destroying an array of /// objects to avoid calling the scalar 'destroy' witness in a loop. DestroyArray, @@ -282,17 +282,19 @@ enum class ValueWitness : unsigned { /// type is an enum. First_EnumValueWitness, - /// unsigned (*getEnumTag)(T *obj, M *self); + /// int (*getEnumTag)(T *obj, M *self); /// Given a valid object of this enum type, extracts the tag value indicating - /// which case of the enum is inhabited. + /// which case of the enum is inhabited. Returned values are in the range + /// [-ElementsWithPayload..ElementsWithNoPayload-1]. GetEnumTag = First_EnumValueWitness, /// void (*destructiveProjectEnumData)(T *obj, M *self); /// Given a valid object of this enum type, destructively extracts the /// associated payload. DestructiveProjectEnumData, - /// void (*destructiveInjectEnumTag)(T *obj, unsigned tag, M *self); + /// void (*destructiveInjectEnumTag)(T *obj, int tag, M *self); /// Given an enum case tag and a valid object of case's payload type, - /// destructively inserts the tag into the payload. + /// destructively inserts the tag into the payload. The given tag value + /// must be in the range [-ElementsWithPayload..ElementsWithNoPayload-1]. DestructiveInjectEnumTag, Last_EnumValueWitness = DestructiveInjectEnumTag, diff --git a/lib/IRGen/WeakTypeInfo.h b/lib/IRGen/WeakTypeInfo.h index 2b4802f83b3ce..ceea010fd48b4 100644 --- a/lib/IRGen/WeakTypeInfo.h +++ b/lib/IRGen/WeakTypeInfo.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index bb76767f14b05..8d8dcbe845330 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -1,8 +1,8 @@ -//===-- Immediate.cpp - the swift immediate mode --------------------------===// +//===--- Immediate.cpp - the swift immediate mode -------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Immediate/ImmediateImpl.h b/lib/Immediate/ImmediateImpl.h index d3a52877c22c2..5bc40f0b8ff02 100644 --- a/lib/Immediate/ImmediateImpl.h +++ b/lib/Immediate/ImmediateImpl.h @@ -1,8 +1,8 @@ -//===-- ImmediateImpl.h - Support functions for immediate mode -*- C++ -*--===// +//===--- ImmediateImpl.h - Support functions for immediate mode -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp index 1cd2b31fb7833..4723a4f073bfd 100644 --- a/lib/Immediate/REPL.cpp +++ b/lib/Immediate/REPL.cpp @@ -1,8 +1,8 @@ -//===-- REPL.cpp - the integrated REPL ------------------------------------===// +//===--- REPL.cpp - the integrated REPL -----------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,7 +33,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) // FIXME: Support REPL on non-Apple platforms. Ubuntu 14.10's editline does not // include the wide character entry points needed by the REPL yet. #include @@ -130,7 +130,7 @@ class ConvertForWcharSize<4> { using Convert = ConvertForWcharSize; -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) static void convertFromUTF8(llvm::StringRef utf8, llvm::SmallVectorImpl &out) { size_t reserve = out.size() + utf8.size(); @@ -162,7 +162,7 @@ static void convertToUTF8(llvm::ArrayRef wide, } // end anonymous namespace -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) static bool appendToREPLFile(SourceFile &SF, PersistentParserState &PersistentState, @@ -950,8 +950,7 @@ class REPLEnvironment { } tryLoadLibraries(CI.getLinkLibraries(), Ctx.SearchPathOpts, CI.getDiags()); - llvm::EngineBuilder builder( - std::move(std::unique_ptr(Module))); + llvm::EngineBuilder builder{std::unique_ptr{Module}}; std::string ErrorMsg; llvm::TargetOptions TargetOpt; std::string CPU; diff --git a/lib/LLVMPasses/ARCEntryPointBuilder.h b/lib/LLVMPasses/ARCEntryPointBuilder.h index bd778bc8bb820..f68325eb808b6 100644 --- a/lib/LLVMPasses/ARCEntryPointBuilder.h +++ b/lib/LLVMPasses/ARCEntryPointBuilder.h @@ -1,8 +1,8 @@ -//===--- ARCEntryPointBuilder.h ----------------------------*- C++ -*------===// +//===--- ARCEntryPointBuilder.h ---------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,7 +21,7 @@ namespace swift { /// A class for building ARC entry points. It is a composition wrapper around an -/// IRBuilder and a constant Cache. It can not be moved or copied. It is meant +/// IRBuilder and a constant Cache. It cannot be moved or copied. It is meant /// to be created once and passed around by reference. class ARCEntryPointBuilder { using IRBuilder = llvm::IRBuilder<>; diff --git a/lib/LLVMPasses/LLVMARCContract.cpp b/lib/LLVMPasses/LLVMARCContract.cpp index 9b1b3be407180..f384ca2313f82 100644 --- a/lib/LLVMPasses/LLVMARCContract.cpp +++ b/lib/LLVMPasses/LLVMARCContract.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/LLVMPasses/LLVMARCOpts.cpp b/lib/LLVMPasses/LLVMARCOpts.cpp index 0b8ef4760fe23..9cdfaebc837bc 100644 --- a/lib/LLVMPasses/LLVMARCOpts.cpp +++ b/lib/LLVMPasses/LLVMARCOpts.cpp @@ -1,8 +1,8 @@ -//===--- Passes.cpp - LLVM Reference Counting Optimizations ---------------===// +//===--- LLVMARCOpts.cpp - LLVM Reference Counting Optimizations ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -553,8 +553,8 @@ static DtorKind analyzeDestructor(Value *P) { // FIXME: Would like to abstract the dtor slot (#0) out from this to somewhere // unified. - enum { DTorSlotOfHeapMeatadata = 0 }; - Function *DtorFn =dyn_cast(CS->getOperand(DTorSlotOfHeapMeatadata)); + enum { DTorSlotOfHeapMetadata = 0 }; + Function *DtorFn =dyn_cast(CS->getOperand(DTorSlotOfHeapMetadata)); if (DtorFn == 0 || DtorFn->mayBeOverridden() || DtorFn->hasExternalLinkage()) return DtorKind::Unknown; @@ -594,7 +594,7 @@ static DtorKind analyzeDestructor(Value *P) { case RT_BridgeRetain: // x = swift_bridgeRetain(y) case RT_Retain: { // swift_retain(obj) - // Ignore retains of the "self" object, no ressurection is possible. + // Ignore retains of the "self" object, no resurrection is possible. Value *ThisRetainedObject = cast(I).getArgOperand(0); if (ThisRetainedObject->stripPointerCasts() == ThisObject->stripPointerCasts()) @@ -856,7 +856,7 @@ static bool performLocalRetainUnownedOpt(CallInst *Retain, BasicBlock &BB, } /// Removes redundant check_unowned calls if they check the same reference and -/// there is no instruction inbetween which could decrement the reference count. +/// there is no instruction in between which could decrement the reference count. static void performRedundantCheckUnownedRemoval(BasicBlock &BB) { DenseSet checkedValues; for (BasicBlock::iterator BBI = BB.begin(), E = BB.end(); BBI != E; ) { diff --git a/lib/LLVMPasses/LLVMARCOpts.h b/lib/LLVMPasses/LLVMARCOpts.h index 4582a0a839e78..fe84bab856390 100644 --- a/lib/LLVMPasses/LLVMARCOpts.h +++ b/lib/LLVMPasses/LLVMARCOpts.h @@ -1,8 +1,8 @@ -//===- LLVMARCOpts.h - LLVM level ARC Opts Utility Declarations -*- C++ -*-===// +//===--- LLVMARCOpts.h - LLVM level ARC Opts Util. Declarations -*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -62,7 +62,7 @@ enum RT_Kind { /// void swift_unknownRelease_n(%swift.refcounted* %P) RT_UnknownReleaseN, - /// void swift_fixLifetime(%swift.refcounted* %P) + /// void __swift_fixLifetime(%swift.refcounted* %P) RT_FixLifetime, /// void swift_bridgeRetain(%swift.refcounted* %P) @@ -112,7 +112,7 @@ inline RT_Kind classifyInstruction(const llvm::Instruction &I) { .Case("swift_unknownRetain_n", RT_UnknownRetainN) .Case("swift_unknownRelease", RT_UnknownRelease) .Case("swift_unknownRelease_n", RT_UnknownReleaseN) - .Case("swift_fixLifetime", RT_FixLifetime) + .Case("__swift_fixLifetime", RT_FixLifetime) .Default(RT_Unknown); } diff --git a/lib/LLVMPasses/LLVMStackPromotion.cpp b/lib/LLVMPasses/LLVMStackPromotion.cpp index 89c458da58529..2cc89c7f90017 100644 --- a/lib/LLVMPasses/LLVMStackPromotion.cpp +++ b/lib/LLVMPasses/LLVMStackPromotion.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/LLVMPasses/LLVMSwiftAA.cpp b/lib/LLVMPasses/LLVMSwiftAA.cpp index af34283b6abdf..d413ff1391fd3 100644 --- a/lib/LLVMPasses/LLVMSwiftAA.cpp +++ b/lib/LLVMPasses/LLVMSwiftAA.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/LLVMPasses/LLVMSwiftRCIdentity.cpp b/lib/LLVMPasses/LLVMSwiftRCIdentity.cpp index 5487d4a57d281..24e4fb4e0d955 100644 --- a/lib/LLVMPasses/LLVMSwiftRCIdentity.cpp +++ b/lib/LLVMPasses/LLVMSwiftRCIdentity.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Markup/AST.cpp b/lib/Markup/AST.cpp index a8ab20c7c6fa9..c78fa7228c6dc 100644 --- a/lib/Markup/AST.cpp +++ b/lib/Markup/AST.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -62,9 +62,10 @@ Code *Code::create(MarkupContext &MC, StringRef LiteralContent) { return new (Mem) Code(LiteralContent); } -CodeBlock *CodeBlock::create(MarkupContext &MC, StringRef LiteralContent) { +CodeBlock *CodeBlock::create(MarkupContext &MC, StringRef LiteralContent, + StringRef Language) { void *Mem = MC.allocate(sizeof(CodeBlock), alignof(CodeBlock)); - return new (Mem) CodeBlock(LiteralContent); + return new (Mem) CodeBlock(LiteralContent, Language); } List::List(ArrayRef Children, bool IsOrdered) @@ -460,7 +461,10 @@ void llvm::markup::dump(const MarkupASTNode *Node, llvm::raw_ostream &OS, } case llvm::markup::ASTNodeKind::CodeBlock: { auto CB = cast(Node); - OS << "CodeBlock: Content="; + OS << "CodeBlock: "; + OS << "Language="; + simpleEscapingPrint(CB->getLanguage(), OS); + OS << " Content="; simpleEscapingPrint(CB->getLiteralContent(), OS); break; } diff --git a/lib/Markup/LineList.cpp b/lib/Markup/LineList.cpp index b4ccb89f7d692..671855f3d20c4 100644 --- a/lib/Markup/LineList.cpp +++ b/lib/Markup/LineList.cpp @@ -1,8 +1,8 @@ -//===--- LineList.h - Data structures for Markup parsing ------------------===// +//===--- LineList.cpp - Data structures for Markup parsing ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Markup/Markup.cpp b/lib/Markup/Markup.cpp index b49e2a5b98ad1..9e831d5539eca 100644 --- a/lib/Markup/Markup.cpp +++ b/lib/Markup/Markup.cpp @@ -1,8 +1,8 @@ -//===--- Markup.h - Markup ------------------------------------------------===// +//===--- Markup.cpp - Markup ----------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -108,7 +108,16 @@ ParseResult parseCodeBlock(MarkupContext &MC, LineList &LL, ParseState State) { assert(cmark_node_get_type(State.Node) == CMARK_NODE_CODE_BLOCK && State.Event == CMARK_EVENT_ENTER); - return { CodeBlock::create(MC, getLiteralContent(MC, LL, State.Node)), + + StringRef Language("swift"); + + if (auto FenceInfo = cmark_node_get_fence_info(State.Node)) { + StringRef FenceInfoStr(FenceInfo); + if (!FenceInfoStr.empty()) + Language = MC.allocateCopy(FenceInfoStr); + } + return { CodeBlock::create(MC, getLiteralContent(MC, LL, State.Node), + Language), State.next() }; } diff --git a/lib/Option/Options.cpp b/lib/Option/Options.cpp index 19a948fc9f87f..d8a138d9a052d 100644 --- a/lib/Option/Options.cpp +++ b/lib/Option/Options.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index e78cd58bf8e8c..385f38f913b52 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -177,7 +177,15 @@ Lexer::Lexer(const LangOptions &Options, StringRef contents = SM.extractText(SM.getRangeForBuffer(BufferID)); BufferStart = contents.data(); BufferEnd = contents.data() + contents.size(); - CurPtr = BufferStart; + + // Check for Unicode BOM at start of file (Only UTF-8 BOM supported now). + size_t BOMLength = llvm::StringSwitch(contents) + .StartsWith("\xEF\xBB\xBF", 3) + .Default(0); + + // Since the UTF-8 BOM doesn't carry information (UTF-8 has no dependency + // on byte order), throw it away. + CurPtr = BufferStart + BOMLength; // Initialize code completion. if (BufferID == SM.getCodeCompletionBufferID()) { @@ -523,6 +531,18 @@ bool Lexer::isIdentifier(StringRef string) { return p == end; } +/// \brief Determines if the given string is a valid operator identifier, +/// without escaping characters. +bool Lexer::isOperator(StringRef string) { + if (string.empty()) return false; + char const *p = string.data(), *end = string.end(); + if (!advanceIfValidStartOfOperator(p, end)) + return false; + while (p < end && advanceIfValidContinuationOfOperator(p, end)); + return p == end; +} + + tok Lexer::kindOfIdentifier(StringRef Str, bool InSILMode) { tok Kind = llvm::StringSwitch(Str) #define KEYWORD(kw) \ @@ -595,30 +615,23 @@ static bool isRightBound(const char *tokEnd, bool isLeftBound) { /// lexOperatorIdentifier - Match identifiers formed out of punctuation. void Lexer::lexOperatorIdentifier() { const char *TokStart = CurPtr-1; + CurPtr = TokStart; + bool didStart = advanceIfValidStartOfOperator(CurPtr, BufferEnd); + assert(didStart && "unexpected operator start"); + (void) didStart; + + do { + if (CurPtr != BufferEnd && InSILBody && + (*CurPtr == '!' || *CurPtr == '?')) + // When parsing SIL body, '!' and '?' are special token and can't be + // in the middle of an operator. + break; - // We only allow '.' in a series. - if (*TokStart == '.') { - while (*CurPtr == '.') - ++CurPtr; - - // Lex ..< as an identifier. - if (*CurPtr == '<' && CurPtr-TokStart == 2) - ++CurPtr; - - } else { - CurPtr = TokStart; - bool didStart = advanceIfValidStartOfOperator(CurPtr, BufferEnd); - assert(didStart && "unexpected operator start"); - (void) didStart; - - do { - if (CurPtr != BufferEnd && InSILBody && - (*CurPtr == '!' || *CurPtr == '?')) - // When parsing SIL body, '!' and '?' are special token and can't be - // in the middle of an operator. - break; - } while (advanceIfValidContinuationOfOperator(CurPtr, BufferEnd)); - } + // '.' cannot appear in the middle of an operator unless the operator + // started with a '.'. + if (*CurPtr == '.' && *TokStart != '.') + break; + } while (advanceIfValidContinuationOfOperator(CurPtr, BufferEnd)); // Decide between the binary, prefix, and postfix cases. // It's binary if either both sides are bound or both sides are not bound. @@ -631,8 +644,7 @@ void Lexer::lexOperatorIdentifier() { switch (TokStart[0]) { case '=': if (leftBound != rightBound) { - auto d = diagnose(TokStart, diag::lex_unary_equal_is_reserved, - leftBound); + auto d = diagnose(TokStart, diag::lex_unary_equal); if (leftBound) d.fixItInsert(getSourceLoc(TokStart), " "); else @@ -644,14 +656,45 @@ void Lexer::lexOperatorIdentifier() { if (leftBound == rightBound || leftBound) break; return formToken(tok::amp_prefix, TokStart); - case '.': + case '.': { if (leftBound == rightBound) return formToken(tok::period, TokStart); if (rightBound) return formToken(tok::period_prefix, TokStart); - diagnose(TokStart, diag::lex_unary_postfix_dot_is_reserved); - // always emit 'tok::period' to avoid trickle down parse errors - return formToken(tok::period, TokStart); + + // If left bound but not right bound, handle some likely situations. + + // If there is just some horizontal whitespace before the next token, its + // addition is probably incorrect. + const char *AfterHorzWhitespace = CurPtr; + while (*AfterHorzWhitespace == ' ' || *AfterHorzWhitespace == '\t') + ++AfterHorzWhitespace; + + // First, when we are code completing "x.", then make sure to return + // a tok::period, since that is what the user is wanting to know about. + // FIXME: isRightBound should consider this to be right bound. + if (*AfterHorzWhitespace == '\0' && + AfterHorzWhitespace == CodeCompletionPtr) { + diagnose(TokStart, diag::expected_member_name); + return formToken(tok::period, TokStart); + } + + if (isRightBound(AfterHorzWhitespace, leftBound) && + // Don't consider comments to be this. A leading slash is probably + // either // or /* and most likely occurs just in our testsuite for + // expected-error lines. + *AfterHorzWhitespace != '/') { + diagnose(TokStart, diag::extra_whitespace_period) + .fixItRemoveChars(getSourceLoc(CurPtr), + getSourceLoc(AfterHorzWhitespace)); + return formToken(tok::period, TokStart); + } + + // Otherwise, it is probably a missing member. + diagnose(TokStart, diag::expected_member_name); + //return formToken(tok::unknown, TokStart); + return lexImpl(); + } case '?': if (leftBound) return formToken(tok::question_postfix, TokStart); @@ -1429,7 +1472,7 @@ void Lexer::lexImpl() { // Remember the start of the token so we can form the text range. const char *TokStart = CurPtr; - switch (*CurPtr++) { + switch ((signed char)*CurPtr++) { default: { char const *tmp = CurPtr-1; if (advanceIfValidStartOfIdentifier(tmp, BufferEnd)) @@ -1576,6 +1619,11 @@ void Lexer::lexImpl() { return formToken(tok::pound_available, TokStart); } + if (getSubstring(TokStart + 1, 8).equals("selector")) { + CurPtr += 8; + return formToken(tok::pound_selector, TokStart); + } + // Allow a hashbang #! line at the beginning of the file. if (CurPtr - 1 == BufferStart && *CurPtr == '!') { CurPtr--; @@ -1664,15 +1712,15 @@ void Lexer::lexImpl() { } } -SourceLoc Lexer::getLocForEndOfToken(const SourceManager &SM, SourceLoc Loc) { +Token Lexer::getTokenAtLocation(const SourceManager &SM, SourceLoc Loc) { // Don't try to do anything with an invalid location. if (!Loc.isValid()) - return Loc; + return Token(); // Figure out which buffer contains this location. int BufferID = SM.findBufferContainingLoc(Loc); if (BufferID < 0) - return SourceLoc(); + return Token(); // Use fake language options; language options only affect validity // and the exact token produced. @@ -1685,10 +1733,14 @@ SourceLoc Lexer::getLocForEndOfToken(const SourceManager &SM, SourceLoc Loc) { Lexer L(FakeLangOpts, SM, BufferID, nullptr, /*InSILMode=*/ false, CommentRetentionMode::ReturnAsTokens); L.restoreState(State(Loc)); - unsigned Length = L.peekNextToken().getLength(); - return Loc.getAdvancedLoc(Length); + return L.peekNextToken(); } +SourceLoc Lexer::getLocForEndOfToken(const SourceManager &SM, SourceLoc Loc) { + return Loc.getAdvancedLocOrInvalid(getTokenAtLocation(SM, Loc).getLength()); +} + + static SourceLoc getLocForStartOfTokenInBuf(SourceManager &SM, unsigned BufferID, unsigned Offset, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f6563d8aeed68..344a3ab39f052 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,8 +20,9 @@ #include "swift/Subsystems.h" #include "swift/AST/Attr.h" #include "swift/AST/DebuggerClient.h" -#include "swift/AST/Module.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/Module.h" +#include "swift/AST/ParameterList.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Fallthrough.h" #include "llvm/Support/MemoryBuffer.h" @@ -34,12 +35,6 @@ using namespace swift; -/// \brief Build an implicit 'self' parameter for the specified DeclContext. -static Pattern *buildImplicitSelfParameter(SourceLoc Loc, - DeclContext *CurDeclContext) { - return Pattern::buildImplicitSelfParameter(Loc, TypeLoc(), CurDeclContext); -} - namespace { /// A RAII object for deciding whether this DeclKind needs special /// treatment when parsing in the "debugger context", and implementing @@ -1159,6 +1154,106 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, rParenLoc, false)); break; } + + case DAK_Swift3Migration: { + if (Tok.isNot(tok::l_paren)) { + diagnose(Loc, diag::attr_expected_lparen, AttrName, + DeclAttribute::isDeclModifier(DK)); + return false; + } + + SourceLoc lParenLoc = consumeToken(tok::l_paren); + + DeclName renamed; + StringRef message; + bool invalid = false; + do { + // If we see a closing parenthesis, we're done. + if (Tok.is(tok::r_paren)) + break; + + if (Tok.isNot(tok::identifier)) { + diagnose(Tok, diag::attr_swift3_migration_label); + if (Tok.isNot(tok::r_paren)) + skipUntil(tok::r_paren); + consumeIf(tok::r_paren); + invalid = true; + break; + } + + // Consume the identifier. + StringRef name = Tok.getText(); + SourceLoc nameLoc = consumeToken(); + + // If we don't have the '=', complain. + SourceLoc equalLoc; + if (!consumeIf(tok::equal, equalLoc)) { + diagnose(Tok, diag::attr_expected_equal_separator, name, AttrName); + invalid = true; + continue; + } + + // If we don't have a string, complain. + if (Tok.isNot(tok::string_literal)) { + diagnose(Tok, diag::attr_expected_string_literal_arg, name, AttrName); + invalid = true; + break; + } + + // Dig out the string. + auto paramString = getStringLiteralIfNotInterpolated(*this, nameLoc, Tok, + name.str()); + SourceLoc paramLoc = consumeToken(tok::string_literal); + if (!paramString) { + invalid = true; + continue; + } + + if (name == "message") { + if (!message.empty()) + diagnose(nameLoc, diag::attr_duplicate_argument, name); + + message = *paramString; + continue; + } + + if (name == "renamed") { + if (renamed) + diagnose(nameLoc, diag::attr_duplicate_argument, name); + + // Parse the name. + DeclName newName = parseDeclName(Context, *paramString); + if (!newName) { + diagnose(paramLoc, diag::attr_bad_swift_name, *paramString); + continue; + } + + renamed = newName; + continue; + } + + diagnose(nameLoc, diag::warn_attr_swift3_migration_unknown_label); + } while (consumeIf(tok::comma)); + + // Parse the closing ')'. + SourceLoc rParenLoc; + if (invalid && !Tok.is(tok::r_paren)) { + skipUntil(tok::r_paren); + if (Tok.is(tok::r_paren)) { + rParenLoc = consumeToken(); + } else + rParenLoc = Tok.getLoc(); + } else { + parseMatchingToken(tok::r_paren, rParenLoc, + diag::attr_swift3_migration_expected_rparen, + lParenLoc); + } + + Attributes.add(new (Context) Swift3MigrationAttr(AtLoc, Loc, lParenLoc, + renamed, message, + rParenLoc, false)); + break; + } } if (DuplicateAttribute) { @@ -1336,18 +1431,6 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { // Otherwise this is a valid decl attribute so they should have put it on // the decl instead of the type. - auto diagID = diag::decl_attribute_applied_to_type; - if (declAttrID == DAK_AutoClosure) { - // Special case handling of @autoclosure attribute on the type, which - // was supported in Swift 1.0 and 1.1, but removed in Swift 1.2. - diagID = diag::autoclosure_is_decl_attribute; - - // Further special case handling of @autoclosure attribute in - // enumerators in EnumDecl's to produce a nice diagnostic. - if (CurDeclContext && isa(CurDeclContext)) - diagID = diag::autoclosure_not_on_enums; - } - // If this is the first attribute, and if we are on a simple decl, emit a // fixit to move the attribute. Otherwise, we don't have the location of // the @ sign, or we don't have confidence that the fixit will be right. @@ -1355,21 +1438,19 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { StructureMarkers.back().Kind != StructureMarkerKind::Declaration || StructureMarkers.back().Loc.isInvalid() || peekToken().is(tok::equal)) { - diagnose(Tok, diagID); + diagnose(Tok, diag::decl_attribute_applied_to_type); } else { // Otherwise, this is the first type attribute and we know where the // declaration is. Emit the same diagnostic, but include a fixit to // move the attribute. Unfortunately, we don't have enough info to add // the attribute to DeclAttributes. - diagnose(Tok, diagID) + diagnose(Tok, diag::decl_attribute_applied_to_type) .fixItRemove(SourceRange(Attributes.AtLoc, Tok.getLoc())) .fixItInsert(StructureMarkers.back().Loc, "@" + Tok.getText().str()+" "); } } - - // Recover by eating @foo when foo is not known. consumeToken(); @@ -1405,7 +1486,6 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { switch (attr) { default: break; - case TAK_local_storage: case TAK_out: case TAK_in: case TAK_owned: @@ -1427,7 +1507,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { case TAK_sil_unowned: Attributes.clearAttribute(attr); if (!isInSILMode()) { - diagnose(Loc, diag::only_allowed_in_sil, "local_storage"); + diagnose(Loc, diag::only_allowed_in_sil, Text); return false; } @@ -1615,6 +1695,7 @@ static bool isKeywordPossibleDeclStart(const Token &Tok) { case tok::kw_struct: case tok::kw_subscript: case tok::kw_typealias: + case tok::kw_associatedtype: case tok::kw_var: case tok::pound_if: case tok::pound_line: @@ -1915,6 +1996,10 @@ ParserStatus Parser::parseDecl(SmallVectorImpl &Entries, } diagnose(Tok, diag::expected_decl); return makeParserErrorResult(); + + case tok::unknown: + consumeToken(tok::unknown); + continue; // Unambiguous top level decls. case tok::kw_import: @@ -1932,6 +2017,7 @@ ParserStatus Parser::parseDecl(SmallVectorImpl &Entries, StaticLoc = SourceLoc(); // we handled static if present. break; case tok::kw_typealias: + case tok::kw_associatedtype: DeclResult = parseDeclTypeAlias(!(Flags & PD_DisallowTypeAliasDef), Flags.contains(PD_InProtocol), Attributes); @@ -2086,7 +2172,7 @@ void Parser::parseDeclDelayed() { // Ensure that we restore the parser state at exit. ParserPositionRAII PPR(*this); - // Create a lexer that can not go past the end state. + // Create a lexer that cannot go past the end state. Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); // Temporarily swap out the parser's current lexer with our new one. @@ -2183,9 +2269,9 @@ ParserResult Parser::parseDeclImport(ParseDeclOptions Flags, auto BufferId = SourceMgr.getCodeCompletionBufferID(); auto IdEndOffset = SourceMgr.getLocOffsetInBuffer(ImportPath.back().second, BufferId) + ImportPath.back().first.str().size(); - auto CCTokenOffeset = SourceMgr.getLocOffsetInBuffer(SourceMgr. + auto CCTokenOffset = SourceMgr.getLocOffsetInBuffer(SourceMgr. getCodeCompletionLoc(), BufferId); - if (IdEndOffset == CCTokenOffeset) { + if (IdEndOffset == CCTokenOffset) { consumeToken(); } } @@ -2378,9 +2464,17 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { if (Tok.is(tok::kw_where)) { SourceLoc whereLoc; SmallVector requirements; - if (!parseGenericWhereClause(whereLoc, requirements)) { + bool firstTypeInComplete; + auto whereStatus = parseGenericWhereClause(whereLoc, requirements, + firstTypeInComplete); + if (whereStatus.isSuccess()) { trailingWhereClause = TrailingWhereClause::create(Context, whereLoc, requirements); + } else if (whereStatus.hasCodeCompletion()) { + if (CodeCompletion && firstTypeInComplete) { + CodeCompletion->completeGenericParams(extendedType.getPtrOrNull()); + } else + return makeParserCodeCompletionResult(); } } @@ -2411,8 +2505,8 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { return parseDecl(MemberDecls, Options); }); - // Don't propagate the code completion bit from members: we can not help - // code completion inside a member decl, and our callers can not do + // Don't propagate the code completion bit from members: we cannot help + // code completion inside a member decl, and our callers cannot do // anything about it either. But propagate the error bit. if (BodyStatus.isError()) status.setIsParseError(); @@ -2578,7 +2672,22 @@ ParserResult Parser::parseDeclIfConfig(ParseDeclOptions Flags) { ParserResult Parser::parseDeclTypeAlias(bool WantDefinition, bool isAssociatedType, DeclAttributes &Attributes) { - SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias); + SourceLoc TypeAliasLoc; + + if (isAssociatedType) { + if (consumeIf(tok::kw_typealias, TypeAliasLoc)) { + diagnose(TypeAliasLoc, diag::typealias_inside_protocol) + .fixItReplace(TypeAliasLoc, "associatedtype"); + } else { + TypeAliasLoc = consumeToken(tok::kw_associatedtype); + } + } else { + if (consumeIf(tok::kw_associatedtype, TypeAliasLoc)) { + diagnose(TypeAliasLoc, diag::associatedtype_outside_protocol); + return makeParserErrorResult(); + } + TypeAliasLoc = consumeToken(tok::kw_typealias); + } Identifier Id; SourceLoc IdLoc; @@ -2586,7 +2695,7 @@ ParserResult Parser::parseDeclTypeAlias(bool WantDefinition, Status |= parseIdentifierDeclName(*this, Id, IdLoc, tok::colon, tok::equal, - diag::expected_identifier_in_decl, "typealias"); + diag::expected_identifier_in_decl, isAssociatedType ? "associatedtype" : "typealias"); if (Status.isError()) return nullptr; @@ -2600,7 +2709,14 @@ ParserResult Parser::parseDeclTypeAlias(bool WantDefinition, ParserResult UnderlyingTy; if (WantDefinition || Tok.is(tok::equal)) { - if (parseToken(tok::equal, diag::expected_equal_in_typealias)) { + if (Tok.is(tok::colon)) { + // It is a common mistake to write "typealias A : Int" instead of = Int. + // Recognize this and produce a fixit. + diagnose(Tok, diag::expected_equal_in_typealias) + .fixItReplace(Tok.getLoc(), "="); + consumeToken(tok::colon); + + } else if (parseToken(tok::equal, diag::expected_equal_in_typealias)) { Status.setIsParseError(); return Status; } @@ -2635,71 +2751,51 @@ ParserResult Parser::parseDeclTypeAlias(bool WantDefinition, /// This function creates an accessor function (with no body) for a computed /// property or subscript. -static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, - TypedPattern *TypedPattern, +static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, TypeLoc ElementTy, - Pattern *Indices, SourceLoc StaticLoc, + ParameterList *Indices, SourceLoc StaticLoc, Parser::ParseDeclOptions Flags, AccessorKind Kind, AddressorKind addressorKind, Parser *P, SourceLoc AccessorKeywordLoc) { - // First task, set up the value argument pattern. This is the NamePattern + // First task, set up the value argument list. This is the "newValue" name // (for setters) followed by the index list (for subscripts). For // non-subscript getters, this degenerates down to "()". // - // We put the 'value' argument before the subscript index list as a + // We put the 'newValue' argument before the subscript index list as a // micro-optimization for Objective-C thunk generation. - Pattern *ValueArg; + ParameterList *ValueArg; { - SmallVector ValueArgElements; + SmallVector ValueArgElements; SourceLoc StartLoc, EndLoc; - bool ExplicitArgument = TypedPattern && - (!TypedPattern->isImplicit() || - !TypedPattern->getSubPattern()->isImplicit()); - - if (TypedPattern) { - ValueArgElements.push_back(TuplePatternElt(TypedPattern)); - StartLoc = TypedPattern->getStartLoc(); - EndLoc = TypedPattern->getEndLoc(); + if (param) { + assert(param->size() == 1 && + "Should only have a single parameter in the list"); + ValueArgElements.push_back(param->get(0)); + StartLoc = param->getStartLoc(); + EndLoc = param->getEndLoc(); } if (Indices) { - auto clonePattern = [&](const Pattern *p) -> Pattern* { - return p->clone(P->Context, Pattern::Implicit); - }; - - if (auto *PP = dyn_cast(Indices)) { - ValueArgElements.push_back( - TuplePatternElt(clonePattern(PP->getSubPattern()))); - } else { - auto *TP = cast(Indices); - for (const auto &elt : TP->getElements()) { - ValueArgElements.push_back( - TuplePatternElt(elt.getLabel(), elt.getLabelLoc(), - clonePattern(elt.getPattern()), - elt.hasEllipsis())); - } - } - - if (!ExplicitArgument) { + Indices = Indices->clone(P->Context, ParameterList::Implicit); + ValueArgElements.append(Indices->begin(), Indices->end()); + if (StartLoc.isInvalid()) { StartLoc = Indices->getStartLoc(); EndLoc = Indices->getEndLoc(); } } - ValueArg = TuplePattern::create(P->Context, StartLoc, ValueArgElements, - EndLoc); - if (!ExplicitArgument) - ValueArg->setImplicit(); + ValueArg = ParameterList::create(P->Context, StartLoc, ValueArgElements, + EndLoc); } // Create the parameter list(s) for the getter. - SmallVector Params; + SmallVector Params; // Add the implicit 'self' to Params, if needed. if (Flags & Parser::PD_HasContainerType) - Params.push_back(buildImplicitSelfParameter(DeclLoc, P->CurDeclContext)); + Params.push_back(ParameterList::createSelf(DeclLoc, P->CurDeclContext)); // Add the "(value)" and subscript indices parameter clause. Params.push_back(ValueArg); @@ -2807,18 +2903,17 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, case AccessorKind::IsMaterializeForSet: case AccessorKind::NotAccessor: - llvm_unreachable("not parsable accessors"); + llvm_unreachable("not parseable accessors"); } } return D; } -static TypedPattern *createSetterAccessorArgument(SourceLoc nameLoc, - Identifier name, - TypeLoc elementTy, - AccessorKind accessorKind, - Parser &P) { +static ParamDecl * +createSetterAccessorArgument(SourceLoc nameLoc, Identifier name, + TypeLoc elementTy, AccessorKind accessorKind, + Parser &P) { // Add the parameter. If no name was specified, the name defaults to // 'value'. bool isNameImplicit = name.empty(); @@ -2828,22 +2923,23 @@ static TypedPattern *createSetterAccessorArgument(SourceLoc nameLoc, name = P.Context.getIdentifier(implName); } - VarDecl *value = new (P.Context) ParamDecl(/*IsLet*/true, - SourceLoc(), Identifier(), - nameLoc, name, - Type(), P.CurDeclContext); + auto result = new (P.Context) ParamDecl(/*IsLet*/true,SourceLoc(),SourceLoc(), + Identifier(), nameLoc, name, + Type(), P.CurDeclContext); if (isNameImplicit) - value->setImplicit(); + result->setImplicit(); - Pattern *namedPat = new (P.Context) NamedPattern(value, isNameImplicit); - return new (P.Context) TypedPattern(namedPat, elementTy.clone(P.Context), - /*Implicit*/true); + result->getTypeLoc() = elementTy.clone(P.Context); + + // AST Walker shouldn't go into the type recursively. + result->setIsTypeLocImplicit(true); + return result; } /// Parse a "(value)" specifier for "set" or "willSet" if present. Create a -/// pattern to represent the spelled argument or the implicit one if it is -/// missing. -static TypedPattern * +/// parameter list to represent the spelled argument or return null if none is +/// present. +static ParameterList * parseOptionalAccessorArgument(SourceLoc SpecifierLoc, TypeLoc ElementTy, Parser &P, AccessorKind Kind) { // 'set' and 'willSet' have a (value) parameter, 'didSet' takes an (oldValue) @@ -2863,7 +2959,9 @@ parseOptionalAccessorArgument(SourceLoc SpecifierLoc, TypeLoc ElementTy, P.diagnose(P.Tok, diag::expected_accessor_name, (unsigned)Kind); P.skipUntil(tok::r_paren, tok::l_brace); if (P.Tok.is(tok::r_paren)) - P.consumeToken(); + EndLoc = P.consumeToken(); + else + EndLoc = StartLoc; } else { // We have a name. Name = P.Context.getIdentifier(P.Tok.getText()); @@ -2880,7 +2978,8 @@ parseOptionalAccessorArgument(SourceLoc SpecifierLoc, TypeLoc ElementTy, } if (Name.empty()) NameLoc = SpecifierLoc; - return createSetterAccessorArgument(NameLoc, Name, ElementTy, Kind, P); + auto param = createSetterAccessorArgument(NameLoc, Name, ElementTy, Kind, P); + return ParameterList::create(P.Context, StartLoc, param, EndLoc); } static unsigned skipUntilMatchingRBrace(Parser &P) { @@ -3022,7 +3121,7 @@ static void diagnoseRedundantAccessors(Parser &P, SourceLoc loc, /// \brief Parse a get-set clause, optionally containing a getter, setter, /// willSet, and/or didSet clauses. 'Indices' is a paren or tuple pattern, /// specifying the index list for a subscript. -bool Parser::parseGetSetImpl(ParseDeclOptions Flags, Pattern *Indices, +bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc &LastValidLoc, SourceLoc StaticLoc, SourceLoc VarLBLoc, @@ -3092,11 +3191,11 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, Pattern *Indices, if (Tok.is(tok::l_paren)) diagnose(Loc, diag::protocol_setter_name); - auto *ValueNamePattern + auto *ValueNameParams = parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind); // Set up a function declaration. - TheDecl = createAccessorFunc(Loc, ValueNamePattern, ElementTy, Indices, + TheDecl = createAccessorFunc(Loc, ValueNameParams, ElementTy, Indices, StaticLoc, Flags, Kind, addressorKind, this, AccessorKeywordLoc); TheDecl->getAttrs() = Attributes; @@ -3179,7 +3278,7 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, Pattern *Indices, Attributes = DeclAttributes(); } if (!IsFirstAccessor) { - // Can not have an implicit getter after other accessor. + // Cannot have an implicit getter after other accessor. diagnose(Tok, diag::expected_accessor_kw); skipUntil(tok::r_brace); // Don't signal an error since we recovered. @@ -3237,7 +3336,8 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, Pattern *Indices, LastValidLoc = Loc; } else { Scope S(this, ScopeKind::FunctionBody); - addPatternVariablesToScope(TheDecl->getBodyParamPatterns()); + for (auto PL : TheDecl->getParameterLists()) + addParametersToScope(PL); // Establish the new context. ParseFunctionBody CC(*this, TheDecl); @@ -3273,7 +3373,7 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, Pattern *Indices, return false; } -bool Parser::parseGetSet(ParseDeclOptions Flags, Pattern *Indices, +bool Parser::parseGetSet(ParseDeclOptions Flags, ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc StaticLoc, SmallVectorImpl &Decls) { @@ -3310,7 +3410,7 @@ void Parser::parseAccessorBodyDelayed(AbstractFunctionDecl *AFD) { // Ensure that we restore the parser state at exit. ParserPositionRAII PPR(*this); - // Create a lexer that can not go past the end state. + // Create a lexer that cannot go past the end state. Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); // Temporarily swap out the parser's current lexer with our new one. @@ -3332,7 +3432,8 @@ void Parser::parseAccessorBodyDelayed(AbstractFunctionDecl *AFD) { } /// \brief Parse the brace-enclosed getter and setter for a variable. -VarDecl *Parser::parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags, +VarDecl *Parser::parseDeclVarGetSet(Pattern *pattern, + ParseDeclOptions Flags, SourceLoc StaticLoc, bool hasInitializer, const DeclAttributes &Attributes, SmallVectorImpl &Decls) { @@ -3413,7 +3514,7 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, bool invalid, ParseDeclOptions flags, SourceLoc staticLoc, const DeclAttributes &attrs, - TypeLoc elementTy, Pattern *indices, + TypeLoc elementTy, ParameterList *indices, SmallVectorImpl &decls) { auto flagInvalidAccessor = [&](FuncDecl *&func) { if (func) { @@ -3437,10 +3538,10 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, // Create an implicit accessor declaration. auto createImplicitAccessor = [&](AccessorKind kind, AddressorKind addressorKind, - TypedPattern *argPattern) -> FuncDecl* { - auto accessor = createAccessorFunc(SourceLoc(), argPattern, - elementTy, indices, staticLoc, flags, - kind, addressorKind, &P, SourceLoc()); + ParameterList *argList) -> FuncDecl* { + auto accessor = createAccessorFunc(SourceLoc(), argList, elementTy, indices, + staticLoc, flags, kind, addressorKind, + &P, SourceLoc()); accessor->setImplicit(); decls.push_back(accessor); return accessor; @@ -3540,12 +3641,13 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, AddressorKind::NotAddressor, nullptr); auto argFunc = (WillSet ? WillSet : DidSet); - auto argLoc = argFunc->getBodyParamPatterns().back()->getLoc(); + auto argLoc = argFunc->getParameterLists().back()->getStartLoc(); - auto argPattern = createSetterAccessorArgument(argLoc, Identifier(), - elementTy, AccessorKind::IsSetter, P); + auto argument = createSetterAccessorArgument(argLoc, Identifier(),elementTy, + AccessorKind::IsSetter, P); + auto argList = ParameterList::create(P.Context, argument); Set = createImplicitAccessor(AccessorKind::IsSetter, - AddressorKind::NotAddressor, argPattern); + AddressorKind::NotAddressor, argList); storage->setObservingAccessors(Get, Set, nullptr); return; @@ -3562,11 +3664,12 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, // setter and record what we've got. if (MutableAddressor) { assert(Get && !Set); - auto argPattern = + auto argument = createSetterAccessorArgument(MutableAddressor->getLoc(), Identifier(), elementTy, AccessorKind::IsSetter, P); + auto argList = ParameterList::create(P.Context, argument); Set = createImplicitAccessor(AccessorKind::IsSetter, - AddressorKind::NotAddressor, argPattern); + AddressorKind::NotAddressor, argList); storage->makeComputedWithMutableAddress(LBLoc, Get, Set, nullptr, MutableAddressor, RBLoc); @@ -3580,10 +3683,16 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, // purely stored. if (isa(storage)) { if (!invalid) P.diagnose(LBLoc, diag::subscript_without_get); + // Create a getter so we don't break downstream invariants by having a + // setter without a getter. Get = createImplicitAccessor(AccessorKind::IsGetter, AddressorKind::NotAddressor, nullptr); } else if (Set) { if (!invalid) P.diagnose(Set->getLoc(), diag::var_set_without_get); + // Create a getter so we don't break downstream invariants by having a + // setter without a getter. + Get = createImplicitAccessor(AccessorKind::IsGetter, + AddressorKind::NotAddressor, nullptr); } } @@ -3941,9 +4050,10 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, Tok.setKind(tok::oper_prefix); } Identifier SimpleName; + Token NameTok = Tok; SourceLoc NameLoc = Tok.getLoc(); Token NonglobalTok = Tok; - bool NonglobalError = false; + bool NonglobalError = false; if (!(Flags & PD_AllowTopLevel) && !(Flags & PD_InProtocol) && @@ -3975,7 +4085,7 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, Optional GenericsScope; GenericsScope.emplace(this, ScopeKind::Generics); GenericParamList *GenericParams; - + bool GPHasCodeCompletion = false; // If the name is an operator token that ends in '<' and the following token // is an identifier, split the '<' off as a separate token. This allows things // like 'func ==(x:T, y:T) {}' to parse as '==' with generic type variable @@ -3985,12 +4095,25 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SimpleName = Context.getIdentifier(SimpleName.str(). slice(0, SimpleName.str().size() - 1)); SourceLoc LAngleLoc = NameLoc.getAdvancedLoc(SimpleName.str().size()); - GenericParams = parseGenericParameters(LAngleLoc); + auto Result = parseGenericParameters(LAngleLoc); + GenericParams = Result.getPtrOrNull(); + GPHasCodeCompletion |= Result.hasCodeCompletion(); + + auto NameTokText = NameTok.getRawText(); + markSplitToken(tok::identifier, + NameTokText.substr(0, NameTokText.size() - 1)); + markSplitToken(tok::oper_binary_unspaced, + NameTokText.substr(NameTokText.size() - 1)); + } else { - GenericParams = maybeParseGenericParams(); + auto Result = maybeParseGenericParams(); + GenericParams = Result.getPtrOrNull(); + GPHasCodeCompletion |= Result.hasCodeCompletion(); } + if (GPHasCodeCompletion && !CodeCompletion) + return makeParserCodeCompletionStatus(); - SmallVector BodyParams; + SmallVector BodyParams; // If we're within a container, add an implicit first pattern to match the // container type as an element named 'self'. @@ -3999,12 +4122,10 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, // "(inout self: FooTy)->(int)->int", and a static function // "(int)->int" on FooTy into "(self: FooTy.Type)->(int)->int". // Note that we can't actually compute the type here until Sema. - if (HasContainerType) { - Pattern *SelfPattern = buildImplicitSelfParameter(NameLoc, CurDeclContext); - BodyParams.push_back(SelfPattern); - } + if (HasContainerType) + BodyParams.push_back(ParameterList::createSelf(NameLoc, CurDeclContext)); - DefaultArgumentInfo DefaultArgs; + DefaultArgumentInfo DefaultArgs(HasContainerType); TypeRepr *FuncRetTy = nullptr; DeclName FullName; SourceLoc throwsLoc; @@ -4045,13 +4166,18 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, // Add the attributes here so if we need them while parsing the body // they are available. FD->getAttrs() = Attributes; - + + // Code completion for the generic type params. + if (GPHasCodeCompletion) + CodeCompletion->setDelayedParsedDecl(FD); + // Pass the function signature to code completion. if (SignatureStatus.hasCodeCompletion()) CodeCompletion->setDelayedParsedDecl(FD); DefaultArgs.setFunctionContext(FD); - addPatternVariablesToScope(FD->getBodyParamPatterns()); + for (auto PL : FD->getParameterLists()) + addParametersToScope(PL); setLocalDiscriminator(FD); // Establish the new context. @@ -4111,7 +4237,7 @@ bool Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { // Ensure that we restore the parser state at exit. ParserPositionRAII PPR(*this); - // Create a lexer that can not go past the end state. + // Create a lexer that cannot go past the end state. Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); // Temporarily swap out the parser's current lexer with our new one. @@ -4167,7 +4293,10 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, GenericParamList *GenericParams = nullptr; { Scope S(this, ScopeKind::Generics); - GenericParams = maybeParseGenericParams(); + auto Result = maybeParseGenericParams(); + GenericParams = Result.getPtrOrNull(); + if (Result.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); } EnumDecl *UD = new (Context) EnumDecl(EnumLoc, EnumName, EnumNameLoc, @@ -4299,7 +4428,16 @@ ParserStatus Parser::parseDeclEnumCase(ParseDeclOptions Flags, { CodeCompletionCallbacks::InEnumElementRawValueRAII InEnumElementRawValue(CodeCompletion); - RawValueExpr = parseExpr(diag::expected_expr_enum_case_raw_value); + if (!CurLocalContext) { + // A local context is needed for parsing closures. We want to parse + // them anyways for proper diagnosis. + LocalContext tempContext{}; + CurLocalContext = &tempContext; + RawValueExpr = parseExpr(diag::expected_expr_enum_case_raw_value); + CurLocalContext = nullptr; + } else { + RawValueExpr = parseExpr(diag::expected_expr_enum_case_raw_value); + } } if (RawValueExpr.hasCodeCompletion()) { Status.setHasCodeCompletion(); @@ -4379,7 +4517,7 @@ bool Parser::parseNominalDeclMembers(SmallVectorImpl &memberDecls, /*AllowSepAfterLast=*/false, ErrorDiag, [&]() -> ParserStatus { // If the previous declaration didn't have a semicolon and this new // declaration doesn't start a line, complain. - if (!previousHadSemi && !Tok.isAtStartOfLine()) { + if (!previousHadSemi && !Tok.isAtStartOfLine() && !Tok.is(tok::unknown)) { SourceLoc endOfPrevious = getEndOfPreviousLoc(); diagnose(endOfPrevious, diag::declaration_same_line_without_semi) .fixItInsert(endOfPrevious, ";"); @@ -4433,7 +4571,10 @@ ParserResult Parser::parseDeclStruct(ParseDeclOptions Flags, GenericParamList *GenericParams = nullptr; { Scope S(this, ScopeKind::Generics); - GenericParams = maybeParseGenericParams(); + auto Result = maybeParseGenericParams(); + GenericParams = Result.getPtrOrNull(); + if (Result.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); } StructDecl *SD = new (Context) StructDecl(StructLoc, StructName, @@ -4513,7 +4654,10 @@ ParserResult Parser::parseDeclClass(SourceLoc ClassLoc, GenericParamList *GenericParams = nullptr; { Scope S(this, ScopeKind::Generics); - GenericParams = maybeParseGenericParams(); + auto Result = maybeParseGenericParams(); + GenericParams = Result.getPtrOrNull(); + if (Result.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); } // Create the class. @@ -4695,7 +4839,7 @@ ParserStatus Parser::parseDeclSubscript(ParseDeclOptions Flags, } SmallVector argumentNames; - ParserResult Indices + ParserResult Indices = parseSingleParameterClause(ParameterContextKind::Subscript, &argumentNames); if (Indices.isNull() || Indices.hasCodeCompletion()) @@ -4731,7 +4875,11 @@ ParserStatus Parser::parseDeclSubscript(ParseDeclOptions Flags, if (Tok.isNot(tok::l_brace)) { // Subscript declarations must always have at least a getter, so they need // to be followed by a {. - diagnose(Tok, diag::expected_lbrace_subscript); + if (Flags.contains(PD_InProtocol)) + diagnose(Tok, diag::expected_lbrace_subscript_protocol) + .fixItInsertAfter(ElementTy.get()->getEndLoc(), " { get set }"); + else + diagnose(Tok, diag::expected_lbrace_subscript); Status.setIsParseError(); } else { if (parseGetSet(Flags, Indices.get(), ElementTy.get(), @@ -4786,12 +4934,15 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { // Parse the generic-params, if present. Scope S(this, ScopeKind::Generics); - GenericParamList *GenericParams = maybeParseGenericParams(); + auto GPResult = maybeParseGenericParams(); + GenericParamList *GenericParams = GPResult.getPtrOrNull(); + if (GPResult.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); // Parse the parameters. // FIXME: handle code completion in Arguments. - DefaultArgumentInfo DefaultArgs; - Pattern *BodyPattern; + DefaultArgumentInfo DefaultArgs(/*hasSelf*/true); + ParameterList *BodyPattern; DeclName FullName; ParserStatus SignatureStatus = parseConstructorArguments(FullName, BodyPattern, DefaultArgs); @@ -4815,12 +4966,12 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { Attributes.add(new (Context) RethrowsAttr(throwsLoc)); } - auto *SelfPattern = buildImplicitSelfParameter(ConstructorLoc,CurDeclContext); + auto *SelfDecl = ParamDecl::createSelf(ConstructorLoc, CurDeclContext); Scope S2(this, ScopeKind::ConstructorBody); auto *CD = new (Context) ConstructorDecl(FullName, ConstructorLoc, Failability, FailabilityLoc, - SelfPattern, BodyPattern, + SelfDecl, BodyPattern, GenericParams, throwsLoc, CurDeclContext); @@ -4841,7 +4992,9 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { // Tell the type checker not to touch this constructor. CD->setInvalid(); } - addPatternVariablesToScope(ArrayRef{SelfPattern, BodyPattern} ); + + addToScope(SelfDecl); + addParametersToScope(BodyPattern); // '{' if (Tok.is(tok::l_brace)) { @@ -4908,11 +5061,11 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) { } } - auto *SelfPattern = buildImplicitSelfParameter(DestructorLoc, CurDeclContext); + auto *SelfDecl = ParamDecl::createSelf(DestructorLoc, CurDeclContext); Scope S(this, ScopeKind::DestructorBody); auto *DD = new (Context) DestructorDecl(Context.Id_deinit, DestructorLoc, - SelfPattern, CurDeclContext); + SelfDecl, CurDeclContext); // Parse the body. if (Tok.is(tok::l_brace)) { @@ -4951,7 +5104,23 @@ Parser::parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes) { bool AllowTopLevel = Flags.contains(PD_AllowTopLevel); if (!Tok.isAnyOperator() && !Tok.is(tok::exclaim_postfix)) { - diagnose(Tok, diag::expected_operator_name_after_operator); + // A common error is to try to define an operator with something in the + // unicode plane considered to be an operator, or to try to define an + // operator like "not". Diagnose this specifically. + if (Tok.is(tok::identifier)) + diagnose(Tok, diag::identifier_when_expecting_operator, + Context.getIdentifier(Tok.getText())); + else + diagnose(Tok, diag::expected_operator_name_after_operator); + + // To improve recovery, check to see if we have a { right after this token. + // If so, swallow until the end } to avoid tripping over the body of the + // malformed operator decl. + if (peekToken().is(tok::l_brace)) { + consumeToken(); + skipSingle(); + } + return nullptr; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index b30e3bda5468e..01d6f688cadee 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,6 +22,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "swift/Basic/Fallthrough.h" +#include "swift/Basic/StringExtras.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" @@ -39,8 +40,10 @@ static Expr *createArgWithTrailingClosure(ASTContext &context, // If there are no elements, just build a parenthesized expression around // the closure. if (elementsIn.empty()) { - return new (context) ParenExpr(leftParen, closure, rightParen, - /*hasTrailingClosure=*/true); + auto PE = new (context) ParenExpr(leftParen, closure, rightParen, + /*hasTrailingClosure=*/true); + PE->setImplicit(); + return PE; } // Create the list of elements, and add the trailing closure to the end. @@ -400,6 +403,25 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, trySuffix->getLoc())); break; default: + // If this is a simple "try expr" situation, where the expr is a closure + // literal, and the next token is a 'catch', then the user wrote + // try/catch instead of do/catch. Emit a fixit hint to rewrite to the + // correct do/catch construct. + if (Tok.is(tok::kw_catch) && isa(sub.get())) { + diagnose(tryLoc, diag::docatch_not_trycatch) + .fixItReplace(tryLoc, "do"); + + // Eat all of the catch clauses, so we don't trip over them in error + // recovery. + while (Tok.is(tok::kw_catch)) { + ParserResult clause = parseStmtCatch(); + if (clause.hasCodeCompletion() && clause.isNull()) + break; + } + + return makeParserResult(new (Context) ErrorExpr(tryLoc)); + } + sub = makeParserResult(new (Context) TryExpr(tryLoc, sub.get())); break; } @@ -414,6 +436,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, /// expr-postfix(Mode) /// operator-prefix expr-unary(Mode) /// '&' expr-unary(Mode) +/// expr-selector /// ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { UnresolvedDeclRefExpr *Operator; @@ -434,9 +457,12 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { new (Context) InOutExpr(Loc, SubExpr.get(), Type())); } + case tok::pound_selector: + return parseExprSelector(); + case tok::oper_postfix: // Postfix operators cannot start a subexpression, but can happen - // syntactically because the operator may just follow whatever preceeds this + // syntactically because the operator may just follow whatever precedes this // expression (and that may not always be an expression). diagnose(Tok, diag::invalid_postfix_operator); Tok.setKind(tok::oper_prefix); @@ -466,10 +492,10 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { if (SubExpr.isNull()) return nullptr; - // Check if we have an unary '-' with number literal sub-expression, for + // Check if we have a unary '-' with number literal sub-expression, for // example, "-42" or "-1.25". if (auto *LE = dyn_cast(SubExpr.get())) { - if (Operator->hasName() && Operator->getName().str() == "-") { + if (Operator->hasName() && Operator->getName().getBaseName().str() == "-") { LE->setNegative(Operator->getLoc()); return makeParserResult(LE); } @@ -479,6 +505,50 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { new (Context) PrefixUnaryExpr(Operator, SubExpr.get())); } +/// parseExprSelector +/// +/// expr-selector: +/// '#selector' '(' expr ')' +/// +ParserResult Parser::parseExprSelector() { + // Consume '#selector'. + SourceLoc keywordLoc = consumeToken(tok::pound_selector); + + // Parse the leading '('. + if (!Tok.is(tok::l_paren)) { + diagnose(Tok, diag::expr_selector_expected_lparen); + return makeParserError(); + } + SourceLoc lParenLoc = consumeToken(tok::l_paren); + + // Parse the subexpression. + ParserResult subExpr = parseExpr(diag::expr_selector_expected_expr); + if (subExpr.hasCodeCompletion()) + return subExpr; + + // Parse the closing ')' + SourceLoc rParenLoc; + if (subExpr.isParseError()) { + skipUntilDeclStmtRBrace(tok::r_paren); + if (Tok.is(tok::r_paren)) + rParenLoc = consumeToken(); + else + rParenLoc = Tok.getLoc(); + } else { + parseMatchingToken(tok::r_paren, rParenLoc, + diag::expr_selector_expected_rparen, lParenLoc); + } + + // If the subexpression was in error, just propagate the error. + if (subExpr.isParseError()) + return makeParserResult( + new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); + + return makeParserResult( + new (Context) ObjCSelectorExpr(keywordLoc, lParenLoc, subExpr.get(), + rParenLoc)); +} + static DeclRefKind getDeclRefKindForOperator(tok kind) { switch (kind) { case tok::oper_binary_spaced: @@ -500,7 +570,7 @@ UnresolvedDeclRefExpr *Parser::parseExprOperator() { consumeToken(); // Bypass local lookup. - return new (Context) UnresolvedDeclRefExpr(name, refKind, loc); + return new (Context) UnresolvedDeclRefExpr(name, refKind, DeclNameLoc(loc)); } static VarDecl *getImplicitSelfDeclForSuperContext(Parser &P, @@ -557,41 +627,31 @@ ParserResult Parser::parseExprSuper() { SourceLoc dotLoc = consumeToken(tok::period); - // FIXME: This code is copy-paste from the general handling for kw_init. - if (Tok.is(tok::kw_init)) { - - if (ErrorOccurred) - return makeParserError(); - - // super.init - SourceLoc ctorLoc = consumeToken(); - - // The constructor decl will be resolved by sema. - Expr *result = new (Context) UnresolvedConstructorExpr(superRef, - dotLoc, ctorLoc, - /*Implicit=*/false); - return makeParserResult(result); - } else if (Tok.is(tok::code_complete)) { + if (Tok.is(tok::code_complete)) { if (CodeCompletion) { if (auto *SRE = dyn_cast(superRef)) CodeCompletion->completeExprSuperDot(SRE); } + // Eat the code completion token because we handled it. consumeToken(tok::code_complete); return makeParserCodeCompletionResult(superRef); - } else { - // super.foo - SourceLoc nameLoc; - Identifier name; - if (parseIdentifier(name, nameLoc, - diag::expected_identifier_after_super_dot_expr)) - return nullptr; - - return makeParserResult(new (Context) UnresolvedDotExpr(superRef, dotLoc, - name, nameLoc, - /*Implicit=*/false)); } - } else if (Tok.isFollowingLSquare()) { + + DeclNameLoc nameLoc; + DeclName name = parseUnqualifiedDeclName( + /*allowInit=*/true, + nameLoc, + diag::expected_identifier_after_super_dot_expr); + if (!name) + return nullptr; + + return makeParserResult( + new (Context) UnresolvedDotExpr(superRef, dotLoc, name, nameLoc, + /*Implicit=*/false)); + } + + if (Tok.isFollowingLSquare()) { // super[expr] ParserResult idx = parseExprList(tok::l_square, tok::r_square); if (idx.hasCodeCompletion()) @@ -600,6 +660,7 @@ ParserResult Parser::parseExprSuper() { return nullptr; return makeParserResult(new (Context) SubscriptExpr(superRef, idx.get())); } + if (Tok.is(tok::code_complete)) { if (CodeCompletion) { if (auto *SRE = dyn_cast(superRef)) @@ -609,6 +670,10 @@ ParserResult Parser::parseExprSuper() { consumeToken(tok::code_complete); return makeParserCodeCompletionResult(superRef); } + + if (consumeIf(tok::unknown)) + return nullptr; + diagnose(Tok, diag::expected_dot_or_subscript_after_super); return nullptr; } @@ -630,14 +695,14 @@ static StringRef copyAndStripUnderscores(ASTContext &C, StringRef orig) { /// the start of a trailing closure, or start the variable accessor block. /// /// Check to see if the '{' is followed by a 'didSet' or a 'willSet' label, -/// possibly preceeded by attributes. If so, we disambiguate the parse as the +/// possibly preceded by attributes. If so, we disambiguate the parse as the /// start of a get-set block in a variable definition (not as a trailing /// closure). static bool isStartOfGetSetAccessor(Parser &P) { assert(P.Tok.is(tok::l_brace) && "not checking a brace?"); // The only case this can happen is if the accessor label is immediately after - // a brace (possibly preceeded by attributes). "get" is implicit, so it can't + // a brace (possibly preceded by attributes). "get" is implicit, so it can't // be checked for. Conveniently however, get/set properties are not allowed // to have initializers, so we don't have an ambiguity, we just have to check // for observing accessors. @@ -649,7 +714,7 @@ static bool isStartOfGetSetAccessor(Parser &P) { NextToken.isContextualKeyword("willSet")) return true; - // If we don't have attributes, then it can not be an accessor block. + // If we don't have attributes, then it cannot be an accessor block. if (NextToken.isNot(tok::at_sign)) return false; @@ -881,12 +946,14 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { break; } - Identifier Name; - SourceLoc NameLoc; + DeclName Name; + DeclNameLoc NameLoc; if (Tok.is(tok::code_complete)) { - auto Expr = new (Context) UnresolvedMemberExpr(DotLoc, - DotLoc.getAdvancedLoc(1), Context.getIdentifier("_"), nullptr); + auto Expr = new (Context) UnresolvedMemberExpr( + DotLoc, + DeclNameLoc(DotLoc.getAdvancedLoc(1)), + Context.getIdentifier("_"), nullptr); Result = makeParserResult(Expr); if (CodeCompletion) { std::vector Identifiers; @@ -913,13 +980,9 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { return Result; } - if (Tok.is(tok::kw_init)) { - Name = Context.Id_init; - NameLoc = consumeToken(tok::kw_init); - } else if (parseIdentifier(Name, NameLoc, - diag::expected_identifier_after_dot_expr)) { - return nullptr; - } + Name = parseUnqualifiedDeclName(/*allowInit=*/true, NameLoc, + diag::expected_identifier_after_dot_expr); + if (!Name) return nullptr; ParserResult Arg; @@ -1010,7 +1073,8 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { SourceLoc TokLoc = Tok.getLoc(); if (consumeIf(tok::period) || consumeIf(tok::period_prefix)) { // Non-identifier cases. - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::integer_literal)) { + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::integer_literal) && + Tok.isNot(tok::kw_init)) { // A metatype expr. if (Tok.is(tok::kw_dynamicType)) { Result = makeParserResult( @@ -1032,24 +1096,11 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { Identifier Name = Context.getIdentifier(Tok.getText()); Result = makeParserResult( new (Context) UnresolvedDotExpr(Result.get(), TokLoc, - Name, Tok.getLoc(), + Name, DeclNameLoc(Tok.getLoc()), /*Implicit=*/false)); consumeToken(); } - // expr-init ::= expr-postfix '.' 'init'. - if (Tok.is(tok::kw_init)) { - // Form the reference to the constructor. - Expr *initRef = new (Context) UnresolvedConstructorExpr( - Result.get(), - TokLoc, - Tok.getLoc(), - /*Implicit=*/false); - consumeToken(tok::kw_init); - Result = makeParserResult(initRef); - continue; - } - if (Tok.is(tok::code_complete)) { if (CodeCompletion && Result.isNonNull()) CodeCompletion->completeDotExpr(Result.get(), /*DotLoc=*/TokLoc); @@ -1077,50 +1128,18 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { if (Result.isParseError()) continue; - Identifier Name = Context.getIdentifier(Tok.getText()); - SourceLoc NameLoc = Tok.getLoc(); - if (Tok.is(tok::identifier)) { - consumeToken(tok::identifier); - - // If this is a selector reference, collect the selector pieces. - bool IsSelector = false; - if (Tok.is(tok::colon) && peekToken().isIdentifierOrUnderscore()) { - BacktrackingScope BS(*this); - - consumeToken(); // ':' - consumeToken(); // identifier or '_' - IsSelector = consumeIf(tok::colon); - } - - if (IsSelector) { - // Collect the selector pieces. - SmallVector Locs; - SmallVector ArgumentNames; + if (Tok.isAny(tok::identifier, tok::kw_init)) { + DeclNameLoc NameLoc; + DeclName Name = parseUnqualifiedDeclName(/*allowInit=*/true, + NameLoc, + diag::expected_member_name); + if (!Name) return nullptr; + + Result = makeParserResult( + new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, + NameLoc, + /*Implicit=*/false)); - Locs.push_back({NameLoc, consumeToken(tok::colon)}); - - // Add entry for the unwritten first argument name. - Locs.push_back({SourceLoc(), SourceLoc()}); - ArgumentNames.push_back(Identifier()); - while (Tok.isIdentifierOrUnderscore() && peekToken().is(tok::colon)) { - Identifier SelName; - if (Tok.is(tok::identifier)) - SelName = Context.getIdentifier(Tok.getText()); - SourceLoc SelLoc = consumeToken(); - SourceLoc ColonLoc = consumeToken(tok::colon); - Locs.push_back({SelLoc, ColonLoc}); - ArgumentNames.push_back(SelName); - } - auto FullName = DeclName(Context, Name, ArgumentNames); - Result = makeParserResult( - UnresolvedSelectorExpr::create(Context, Result.get(), TokLoc, - FullName, Locs)); - } else { - Result = makeParserResult( - new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, NameLoc, - /*Implicit=*/false)); - } - if (canParseAsGenericArgumentList()) { SmallVector args; SourceLoc LAngleLoc, RAngleLoc; @@ -1132,22 +1151,22 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { for (auto ty : args) locArgs.push_back(ty); Result = makeParserResult(new (Context) UnresolvedSpecializeExpr( - Result.get(), LAngleLoc, Context.AllocateCopy(locArgs), - RAngleLoc)); - } - - // If there is an expr-call-suffix, parse it and form a call. - if (Tok.isFollowingLParen()) { - Result = parseExprCallSuffix(Result); - continue; + Result.get(), LAngleLoc, Context.AllocateCopy(locArgs), + RAngleLoc)); } } else { + DeclName name = Context.getIdentifier(Tok.getText()); + SourceLoc nameLoc = consumeToken(tok::integer_literal); Result = makeParserResult( - new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name, NameLoc, + new (Context) UnresolvedDotExpr(Result.get(), TokLoc, name, + DeclNameLoc(nameLoc), /*Implicit=*/false)); - consumeToken(tok::integer_literal); } + // If there is an expr-call-suffix, parse it and form a call. + if (Tok.isFollowingLParen()) + Result = parseExprCallSuffix(Result); + continue; } @@ -1225,9 +1244,10 @@ ParserResult Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) { Expr *arg = createArgWithTrailingClosure(Context, SourceLoc(), { }, { }, { }, SourceLoc(), closure.get()); + // The call node should still be marked as explicit Result = makeParserResult( ParserStatus(closure), - new (Context) CallExpr(Result.get(), arg, /*Implicit=*/true)); + new (Context) CallExpr(Result.get(), arg, /*Implicit=*/false)); } if (Result.hasCodeCompletion()) @@ -1385,16 +1405,118 @@ Expr *Parser::parseExprStringLiteral() { return new (Context) InterpolatedStringLiteralExpr(Loc, Context.AllocateCopy(Exprs)); } - + +void Parser::diagnoseEscapedArgumentLabel(const Token &tok) { + assert(tok.isEscapedIdentifier() && "Only for escaped identifiers"); + if (!canBeArgumentLabel(tok.getText())) return; + + SourceLoc start = tok.getLoc(); + SourceLoc end = start.getAdvancedLoc(tok.getLength()); + diagnose(tok, diag::escaped_parameter_name, tok.getText()) + .fixItRemoveChars(start, start.getAdvancedLoc(1)) + .fixItRemoveChars(end.getAdvancedLoc(-1), end); +} + +DeclName Parser::parseUnqualifiedDeclName(bool allowInit, + DeclNameLoc &loc, + const Diagnostic &diag) { + // Consume the base name. + Identifier baseName; + SourceLoc baseNameLoc; + if (Tok.is(tok::kw_init) && allowInit) { + baseName = Context.Id_init; + baseNameLoc = consumeToken(tok::kw_init); + } else if (Tok.is(tok::identifier) || Tok.is(tok::kw_Self) || + Tok.is(tok::kw_self)) { + baseNameLoc = consumeIdentifier(&baseName); + } else { + checkForInputIncomplete(); + diagnose(Tok, diag); + return DeclName(); + } + + // If the next token isn't a following '(', we don't have a compound name. + if (!Tok.isFollowingLParen()) { + loc = DeclNameLoc(baseNameLoc); + return baseName; + } + + // If the token after that isn't an argument label or ':', we don't have a + // compound name. + if ((!peekToken().canBeArgumentLabel() && !peekToken().is(tok::colon)) || + Identifier::isEditorPlaceholder(peekToken().getText())) { + loc = DeclNameLoc(baseNameLoc); + return baseName; + } + + // Try to parse a compound name. + BacktrackingScope backtrack(*this); + + SmallVector argumentLabels; + SmallVector argumentLabelLocs; + SourceLoc lparenLoc = consumeToken(tok::l_paren); + SourceLoc rparenLoc; + while (true) { + // Terminate at ')'. + if (Tok.is(tok::r_paren)) { + rparenLoc = consumeToken(tok::r_paren); + break; + } + + // If we see a ':', the user forgot the '_'; + if (Tok.is(tok::colon)) { + diagnose(Tok, diag::empty_arg_label_underscore) + .fixItInsert(Tok.getLoc(), "_"); + argumentLabels.push_back(Identifier()); + argumentLabelLocs.push_back(consumeToken(tok::colon)); + } + + // If we see a potential argument label followed by a ':', consume + // it. + if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) { + // If this was an escaped identifier that need not have been escaped, + // say so. + if (Tok.isEscapedIdentifier()) + diagnoseEscapedArgumentLabel(Tok); + + if (Tok.is(tok::kw__)) + argumentLabels.push_back(Identifier()); + else + argumentLabels.push_back(Context.getIdentifier(Tok.getText())); + argumentLabelLocs.push_back(consumeToken()); + (void)consumeToken(tok::colon); + continue; + } + + // This is not a compound name. + // FIXME: Could recover better if we "know" it's a compound name. + loc = DeclNameLoc(baseNameLoc); + return baseName; + } + + assert(!argumentLabels.empty() && "Logic above should prevent this"); + assert(argumentLabels.size() == argumentLabelLocs.size()); + + // We have a compound name. Cancel backtracking and build that name. + backtrack.cancelBacktrack(); + loc = DeclNameLoc(Context, baseNameLoc, lparenLoc, argumentLabelLocs, + rparenLoc); + return DeclName(Context, baseName, argumentLabels); +} + /// expr-identifier: -/// identifier generic-args? +/// unqualified-decl-name generic-args? Expr *Parser::parseExprIdentifier() { assert(Tok.is(tok::identifier) || Tok.is(tok::kw_self) || Tok.is(tok::kw_Self)); Token IdentTok = Tok; - Identifier name; - SourceLoc loc = consumeIdentifier(&name); + + // Parse the unqualified-decl-name. + DeclNameLoc loc; + DeclName name = parseUnqualifiedDeclName(/*allowInit=*/false, loc, + diag::expected_expr); + SmallVector args; SourceLoc LAngleLoc, RAngleLoc; bool hasGenericArgumentList = false; @@ -1407,35 +1529,37 @@ Expr *Parser::parseExprIdentifier() { /// period_following comma semicolon /// if (canParseAsGenericArgumentList()) { - hasGenericArgumentList = true; if (parseGenericArguments(args, LAngleLoc, RAngleLoc)) { diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket); } + + // The result can be empty in error cases. + hasGenericArgumentList = !args.empty(); } - ValueDecl *D = lookupInScope(name); + ValueDecl *D = lookupInScope(name.getBaseName()); // FIXME: We want this to work: "var x = { x() }", but for now it's better // to disallow it than to crash. if (D) { for (auto activeVar : DisabledVars) { if (activeVar == D) { - diagnose(loc, DisabledVarReason); - return new (Context) ErrorExpr(loc); + diagnose(loc.getBaseNameLoc(), DisabledVarReason); + return new (Context) ErrorExpr(loc.getSourceRange()); } } } else { for (auto activeVar : DisabledVars) { - if (activeVar->getName() == name) { - diagnose(loc, DisabledVarReason); - return new (Context) ErrorExpr(loc); + if (activeVar->getFullName() == name) { + diagnose(loc.getBaseNameLoc(), DisabledVarReason); + return new (Context) ErrorExpr(loc.getSourceRange()); } } } Expr *E; if (D == 0) { - if (name.isEditorPlaceholder()) - return parseExprEditorPlaceholder(IdentTok, name); + if (name.getBaseName().isEditorPlaceholder()) + return parseExprEditorPlaceholder(IdentTok, name.getBaseName()); auto refKind = DeclRefKind::Ordinary; auto unresolved = new (Context) UnresolvedDeclRefExpr(name, refKind, loc); @@ -1443,9 +1567,9 @@ Expr *Parser::parseExprIdentifier() { E = unresolved; } else if (auto TD = dyn_cast(D)) { if (!hasGenericArgumentList) - E = TypeExpr::createForDecl(loc, TD); + E = TypeExpr::createForDecl(loc.getBaseNameLoc(), TD, /*implicit*/false); else - E = TypeExpr::createForSpecializedDecl(loc, TD, + E = TypeExpr::createForSpecializedDecl(loc.getBaseNameLoc(), TD, Context.AllocateCopy(args), SourceRange(LAngleLoc, RAngleLoc)); @@ -1520,7 +1644,7 @@ Expr *Parser::parseExprEditorPlaceholder(Token PlaceholderTok, bool Parser:: parseClosureSignatureIfPresent(SmallVectorImpl &captureList, - Pattern *¶ms, SourceLoc &throwsLoc, + ParameterList *¶ms, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeRepr *&explicitResultType, SourceLoc &inLoc){ // Clear out result parameters. @@ -1707,33 +1831,26 @@ parseClosureSignatureIfPresent(SmallVectorImpl &captureList, invalid = true; } else { // Parse identifier (',' identifier)* - SmallVector elements; + SmallVector elements; do { - if (Tok.is(tok::identifier) || Tok.is(tok::kw__)) { - Identifier name = Tok.is(tok::identifier) ? - Context.getIdentifier(Tok.getText()) : Identifier(); - auto var = new (Context) ParamDecl(/*IsLet*/ true, - SourceLoc(), Identifier(), - Tok.getLoc(), - name, - Type(), nullptr); - elements.push_back(TuplePatternElt(new (Context) NamedPattern(var))); - consumeToken(); - } else { + if (Tok.isNot(tok::identifier, tok::kw__)) { diagnose(Tok, diag::expected_closure_parameter_name); invalid = true; break; } + Identifier name = Tok.is(tok::identifier) ? + Context.getIdentifier(Tok.getText()) : Identifier(); + auto var = new (Context) ParamDecl(/*IsLet*/ true, SourceLoc(), + SourceLoc(), Identifier(), + Tok.getLoc(), name, Type(), nullptr); + elements.push_back(var); + consumeToken(); + // Consume a comma to continue. - if (consumeIf(tok::comma)) { - continue; - } + } while (consumeIf(tok::comma)); - break; - } while (true); - - params = TuplePattern::create(Context, SourceLoc(), elements,SourceLoc()); + params = ParameterList::create(Context, elements); } if (Tok.is(tok::kw_throws)) { @@ -1806,7 +1923,7 @@ ParserResult Parser::parseExprClosure() { SourceLoc leftBrace = consumeToken(); // Parse the closure-signature, if present. - Pattern *params = nullptr; + ParameterList *params = nullptr; SourceLoc throwsLoc; SourceLoc arrowLoc; TypeRepr *explicitResultType; @@ -1838,7 +1955,7 @@ ParserResult Parser::parseExprClosure() { // Handle parameters. if (params) { // Add the parameters into scope. - addPatternVariablesToScope(params); + addParametersToScope(params); } else { // There are no parameters; allow anonymous closure variables. // FIXME: We could do this all the time, and then provide Fix-Its @@ -1866,18 +1983,17 @@ ParserResult Parser::parseExprClosure() { if (!params) { // Create a parameter pattern containing the anonymous variables. auto &anonVars = AnonClosureVars.back().second; - SmallVector elements; - for (auto anonVar : anonVars) { - elements.push_back(TuplePatternElt(new (Context) NamedPattern(anonVar))); - } - params = TuplePattern::createSimple(Context, leftBrace, elements, - leftBrace, /*implicit*/true); + SmallVector elements; + for (auto anonVar : anonVars) + elements.push_back(anonVar); + + params = ParameterList::create(Context, leftBrace, elements, leftBrace); // Pop out of the anonymous closure variables scope. AnonClosureVars.pop_back(); // Attach the parameters to the closure. - closure->setParams(params); + closure->setParameterList(params); closure->setHasAnonymousClosureVars(); } @@ -1953,7 +2069,7 @@ Expr *Parser::parseExprAnonClosureArg() { // generate the anonymous variables we need. auto closure = dyn_cast_or_null( dyn_cast(CurDeclContext)); - if (!closure || closure->getParams()) { + if (!closure || closure->getParameters()) { // FIXME: specialize diagnostic when there were closure parameters. // We can be fairly smart here. diagnose(Loc, closure ? diag::anon_closure_arg_in_closure_with_args @@ -1969,13 +2085,15 @@ Expr *Parser::parseExprAnonClosureArg() { StringRef varName = ("$" + Twine(nextIdx)).toStringRef(StrBuf); Identifier ident = Context.getIdentifier(varName); SourceLoc varLoc = leftBraceLoc; - VarDecl *var = new (Context) ParamDecl(/*IsLet*/ true, - SourceLoc(), Identifier(), - varLoc, ident, Type(), closure); + auto *var = new (Context) ParamDecl(/*IsLet*/ true, SourceLoc(),SourceLoc(), + Identifier(), varLoc, ident, Type(), + closure); + var->setImplicit(); decls.push_back(var); } - return new (Context) DeclRefExpr(decls[ArgNo], Loc, /*Implicit=*/false); + return new (Context) DeclRefExpr(decls[ArgNo], DeclNameLoc(Loc), + /*Implicit=*/false); } @@ -2009,13 +2127,16 @@ ParserResult Parser::parseExprList(tok LeftTok, tok RightTok) { Identifier FieldName; SourceLoc FieldNameLoc; - // Check to see if there is a field specifier - if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) { - FieldNameLoc = Tok.getLoc(); - if (parseIdentifier(FieldName, - diag::expected_field_spec_name_tuple_expr)) { - return makeParserError(); - } + // Check to see if there is an argument label. + if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) { + // If this was an escaped identifier that need not have been escaped, + // say so. + if (Tok.isEscapedIdentifier()) + diagnoseEscapedArgumentLabel(Tok); + + if (!Tok.is(tok::kw__)) + FieldName = Context.getIdentifier(Tok.getText()); + FieldNameLoc = consumeToken(); consumeToken(tok::colon); } @@ -2035,7 +2156,7 @@ ParserResult Parser::parseExprList(tok LeftTok, tok RightTok) { // context. SubExpr = new(Context) UnresolvedDeclRefExpr(OperName, DeclRefKind::Ordinary, - Loc); + DeclNameLoc(Loc)); } else { ParserResult ParsedSubExpr = parseExpr(diag::expected_expr_in_expr_list); @@ -2342,6 +2463,13 @@ void Parser::addPatternVariablesToScope(ArrayRef Patterns) { } } +void Parser::addParametersToScope(ParameterList *PL) { + for (auto param : *PL) + if (param->hasName()) + addToScope(param); +} + + /// Parse availability query specification. /// diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index b92ce1d4acc91..3893ec385db9b 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -32,21 +32,33 @@ using namespace swift; /// /// When parsing the generic parameters, this routine establishes a new scope /// and adds those parameters to the scope. -GenericParamList *Parser::parseGenericParameters() { +ParserResult Parser::parseGenericParameters() { // Parse the opening '<'. assert(startsWithLess(Tok) && "Generic parameter list must start with '<'"); return parseGenericParameters(consumeStartingLess()); } -GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { +ParserResult Parser::parseGenericParameters(SourceLoc LAngleLoc) { // Parse the generic parameter list. SmallVector GenericParams; bool Invalid = false; do { + // Note that we're parsing a declaration. + StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), + StructureMarkerKind::Declaration); + + // Parse attributes. + DeclAttributes attributes; + if (Tok.hasComment()) + attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); + bool foundCCTokenInAttr; + parseDeclAttributeList(attributes, foundCCTokenInAttr); + // Parse the name of the parameter. Identifier Name; SourceLoc NameLoc; - if (parseIdentifier(Name, NameLoc, diag::expected_generics_parameter_name)) { + if (parseIdentifier(Name, NameLoc, + diag::expected_generics_parameter_name)) { Invalid = true; break; } @@ -56,7 +68,8 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { if (Tok.is(tok::colon)) { (void)consumeToken(); ParserResult Ty; - if (Tok.getKind() == tok::identifier) { + if (Tok.getKind() == tok::identifier || + Tok.getKind() == tok::code_complete) { Ty = parseTypeIdentifier(); } else if (Tok.getKind() == tok::kw_protocol) { Ty = parseTypeComposition(); @@ -65,7 +78,9 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { Invalid = true; } - // FIXME: code completion not handled. + if (Ty.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); + if (Ty.isNonNull()) Inherited.push_back(Ty.get()); } @@ -80,6 +95,9 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { Param->setInherited(Context.AllocateCopy(Inherited)); GenericParams.push_back(Param); + // Attach attributes. + Param->getAttrs() = attributes; + // Add this parameter to the scope. addToScope(Param); @@ -89,8 +107,9 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { // Parse the optional where-clause. SourceLoc WhereLoc; SmallVector Requirements; + bool FirstTypeInComplete; if (Tok.is(tok::kw_where) && - parseGenericWhereClause(WhereLoc, Requirements)) { + parseGenericWhereClause(WhereLoc, Requirements, FirstTypeInComplete).isError()) { Invalid = true; } @@ -117,11 +136,12 @@ GenericParamList *Parser::parseGenericParameters(SourceLoc LAngleLoc) { if (GenericParams.empty()) return nullptr; - return GenericParamList::create(Context, LAngleLoc, GenericParams, - WhereLoc, Requirements, RAngleLoc); + return makeParserResult(GenericParamList::create(Context, LAngleLoc, + GenericParams, WhereLoc, + Requirements, RAngleLoc)); } -GenericParamList *Parser::maybeParseGenericParams() { +ParserResult Parser::maybeParseGenericParams() { if (!startsWithLess(Tok)) return nullptr; @@ -132,7 +152,7 @@ GenericParamList *Parser::maybeParseGenericParams() { // first one being the outmost generic parameter list. GenericParamList *gpl = nullptr, *outer_gpl = nullptr; do { - gpl = parseGenericParameters(); + gpl = parseGenericParameters().getPtrOrNull(); if (!gpl) return nullptr; @@ -140,7 +160,7 @@ GenericParamList *Parser::maybeParseGenericParams() { gpl->setOuterParameters(outer_gpl); outer_gpl = gpl; } while(startsWithLess(Tok)); - return gpl; + return makeParserResult(gpl); } /// parseGenericWhereClause - Parse a 'where' clause, which places additional @@ -159,17 +179,23 @@ GenericParamList *Parser::maybeParseGenericParams() { /// /// same-type-requirement: /// type-identifier '==' type -bool Parser::parseGenericWhereClause( +ParserStatus Parser::parseGenericWhereClause( SourceLoc &WhereLoc, - SmallVectorImpl &Requirements) { + SmallVectorImpl &Requirements, + bool &FirstTypeInComplete) { + ParserStatus Status; // Parse the 'where'. WhereLoc = consumeToken(tok::kw_where); - bool Invalid = false; + FirstTypeInComplete = false; do { // Parse the leading type-identifier. ParserResult FirstType = parseTypeIdentifier(); - if (FirstType.isNull() || FirstType.hasCodeCompletion()) { - Invalid = true; + if (FirstType.isNull()) { + Status.setIsParseError(); + if (FirstType.hasCodeCompletion()) { + Status.setHasCodeCompletion(); + FirstTypeInComplete = true; + } break; } @@ -184,15 +210,16 @@ bool Parser::parseGenericWhereClause( } else { Protocol = parseTypeIdentifier(); } - if (Protocol.isNull() || Protocol.hasCodeCompletion()) { - Invalid = true; + if (Protocol.isNull()) { + Status.setIsParseError(); + if (Protocol.hasCodeCompletion()) + Status.setHasCodeCompletion(); break; } // Add the requirement. - Requirements.push_back(RequirementRepr::getConformance(FirstType.get(), - ColonLoc, - Protocol.get())); + Requirements.push_back(RequirementRepr::getTypeConstraint(FirstType.get(), + ColonLoc, Protocol.get())); } else if ((Tok.isAnyOperator() && Tok.getText() == "==") || Tok.is(tok::equal)) { // A same-type-requirement @@ -204,8 +231,10 @@ bool Parser::parseGenericWhereClause( // Parse the second type. ParserResult SecondType = parseType(); - if (SecondType.isNull() || SecondType.hasCodeCompletion()) { - Invalid = true; + if (SecondType.isNull()) { + Status.setIsParseError(); + if (SecondType.hasCodeCompletion()) + Status.setHasCodeCompletion(); break; } @@ -215,11 +244,11 @@ bool Parser::parseGenericWhereClause( SecondType.get())); } else { diagnose(Tok, diag::expected_requirement_delim); - Invalid = true; + Status.setIsParseError(); break; } // If there's a comma, keep parsing the list. } while (consumeIf(tok::comma)); - return Invalid; + return Status; } diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 14f09fc7400e3..08b7acc4e50f8 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -67,7 +67,8 @@ void Parser::DefaultArgumentInfo::setFunctionContext(DeclContext *DC) { static ParserStatus parseDefaultArgument(Parser &P, Parser::DefaultArgumentInfo *defaultArgs, unsigned argIndex, - ExprHandle *&init) { + ExprHandle *&init, + Parser::ParameterContextKind paramContext) { SourceLoc equalLoc = P.consumeToken(tok::equal); // Enter a fresh default-argument context with a meaningless parent. @@ -89,8 +90,31 @@ static ParserStatus parseDefaultArgument(Parser &P, defaultArgs->ParsedContexts.push_back(initDC); } - if (!defaultArgs) { - auto inFlight = P.diagnose(equalLoc, diag::non_func_decl_pattern_init); + Diag<> diagID = { DiagID() }; + switch (paramContext) { + case Parser::ParameterContextKind::Function: + case Parser::ParameterContextKind::Operator: + case Parser::ParameterContextKind::Initializer: + break; + case Parser::ParameterContextKind::Closure: + diagID = diag::no_default_arg_closure; + break; + case Parser::ParameterContextKind::Subscript: + diagID = diag::no_default_arg_subscript; + break; + case Parser::ParameterContextKind::Curried: + diagID = diag::no_default_arg_curried; + break; + } + + assert(((diagID.ID != DiagID()) == !defaultArgs || + // Sometimes curried method parameter lists get default arg info. + // Remove this when they go away. + paramContext == Parser::ParameterContextKind::Curried) && + "Default arguments specified for an unexpected parameter list kind"); + + if (diagID.ID != DiagID()) { + auto inFlight = P.diagnose(equalLoc, diagID); if (initR.isNonNull()) inFlight.fixItRemove(SourceRange(equalLoc, initR.get()->getEndLoc())); return ParserStatus(); @@ -119,11 +143,12 @@ static bool startsParameterName(Parser &parser, bool isClosure) { return true; // To have a parameter name here, we need a name. - if (!parser.Tok.is(tok::identifier)) + if (!parser.Tok.canBeArgumentLabel()) return false; - // If the next token is another identifier, '_', or ':', this is a name. - if (parser.peekToken().isAny(tok::identifier, tok::kw__, tok::colon)) + // If the next token can be an argument label or is ':', this is a name. + const auto &nextTok = parser.peekToken(); + if (nextTok.is(tok::colon) || nextTok.canBeArgumentLabel()) return true; // The identifier could be a name or it could be a type. In a closure, we @@ -179,15 +204,15 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, param.LetVarInOutLoc = consumeToken(); param.SpecifierKind = ParsedParameter::InOut; } else if (Tok.is(tok::kw_let)) { - diagnose(Tok.getLoc(), diag::var_not_allowed_in_pattern, + diagnose(Tok.getLoc(), diag::let_on_param_is_redundant, Tok.is(tok::kw_let)).fixItRemove(Tok.getLoc()); param.LetVarInOutLoc = consumeToken(); param.SpecifierKind = ParsedParameter::Let; } else if (Tok.is(tok::kw_var)) { - diagnose(Tok.getLoc(), diag::var_not_allowed_in_pattern, - Tok.is(tok::kw_let)).fixItRemove(Tok.getLoc()); + diagnose(Tok.getLoc(), diag::var_not_allowed_in_pattern) + .fixItRemove(Tok.getLoc()); param.LetVarInOutLoc = consumeToken(); - param.SpecifierKind = ParsedParameter::Var; + param.SpecifierKind = ParsedParameter::Let; } // Redundant specifiers are fairly common, recognize, reject, and recover @@ -198,54 +223,31 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, consumeToken(); } - // '#'? - if (Tok.is(tok::pound)) - param.PoundLoc = consumeToken(tok::pound); - - if (param.PoundLoc.isValid() || startsParameterName(*this, isClosure)) { + if (startsParameterName(*this, isClosure)) { // identifier-or-none for the first name - if (Tok.is(tok::identifier)) { - param.FirstName = Context.getIdentifier(Tok.getText()); - param.FirstNameLoc = consumeToken(); - - // Operators can not have API names. - if (paramContext == ParameterContextKind::Operator && - param.PoundLoc.isValid()) { - diagnose(param.PoundLoc, - diag::parameter_operator_keyword_argument) - .fixItRemove(param.PoundLoc); - param.PoundLoc = SourceLoc(); - } - } else if (Tok.is(tok::kw__)) { - // A back-tick cannot precede an empty name marker. - if (param.PoundLoc.isValid()) { - diagnose(Tok, diag::parameter_backtick_empty_name) - .fixItRemove(param.PoundLoc); - param.PoundLoc = SourceLoc(); - } - + if (Tok.is(tok::kw__)) { param.FirstNameLoc = consumeToken(); } else { - assert(param.PoundLoc.isValid() && "startsParameterName() lied"); - diagnose(Tok, diag::parameter_backtick_missing_name); - param.FirstNameLoc = param.PoundLoc; - param.PoundLoc = SourceLoc(); + assert(Tok.canBeArgumentLabel() && "startsParameterName() lied"); + param.FirstName = Context.getIdentifier(Tok.getText()); + param.FirstNameLoc = consumeToken(); } // identifier-or-none? for the second name - if (Tok.is(tok::identifier)) { - param.SecondName = Context.getIdentifier(Tok.getText()); - param.SecondNameLoc = consumeToken(); - } else if (Tok.is(tok::kw__)) { + if (Tok.canBeArgumentLabel()) { + if (!Tok.is(tok::kw__)) + param.SecondName = Context.getIdentifier(Tok.getText()); + param.SecondNameLoc = consumeToken(); } - // Operators can not have API names. - if (paramContext == ParameterContextKind::Operator && + // Operators and closures cannot have API names. + if ((paramContext == ParameterContextKind::Operator || + paramContext == ParameterContextKind::Closure) && !param.FirstName.empty() && param.SecondNameLoc.isValid()) { - diagnose(param.FirstNameLoc, - diag::parameter_operator_keyword_argument) + diagnose(param.FirstNameLoc, diag::parameter_operator_keyword_argument, + isClosure) .fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc); param.FirstName = param.SecondName; param.FirstNameLoc = param.SecondNameLoc; @@ -253,31 +255,10 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, param.SecondNameLoc = SourceLoc(); } - // Cannot have a pound and two names. - if (param.PoundLoc.isValid() && param.SecondNameLoc.isValid()) { - diagnose(param.PoundLoc, diag::parameter_backtick_two_names) - .fixItRemove(param.PoundLoc); - param.PoundLoc = SourceLoc(); - } - // (':' type)? if (Tok.is(tok::colon)) { param.ColonLoc = consumeToken(); - // Special case handling of @autoclosure attribute on the type, which - // was supported in Swift 1.0 and 1.1, but removed in Swift 1.2 (moved - // to a decl attribute). - if (Tok.is(tok::at_sign) && - peekToken().isContextualKeyword("autoclosure")) { - SourceLoc AtLoc = consumeToken(tok::at_sign); - SourceLoc ACLoc = consumeToken(tok::identifier); - diagnose(AtLoc, diag::autoclosure_is_decl_attribute) - .fixItRemove(SourceRange(AtLoc, ACLoc)) - .fixItInsert(StartLoc, "@autoclosure "); - param.Attrs.add(new (Context) AutoClosureAttr(AtLoc, ACLoc, - /*escaping=*/false)); - } - auto type = parseType(diag::expected_parameter_type); status |= type; param.Type = type.getPtrOrNull(); @@ -313,7 +294,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, if (Tok.is(tok::equal)) { param.EqualLoc = Tok.getLoc(); status |= parseDefaultArgument(*this, defaultArgs, defaultArgIndex, - param.DefaultArg); + param.DefaultArg, paramContext); if (param.EllipsisLoc.isValid()) { // The range of the complete default argument. @@ -339,10 +320,8 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc, }); } -/// Map parsed parameters to argument and body patterns. -/// -/// \returns the pattern describing the parsed parameters. -static Pattern* +/// Map parsed parameters to a ParameterList. +static ParameterList * mapParsedParameters(Parser &parser, SourceLoc leftParenLoc, MutableArrayRef params, @@ -353,53 +332,51 @@ mapParsedParameters(Parser &parser, auto &ctx = parser.Context; // Local function to create a pattern for a single parameter. - auto createParamPattern = [&](SourceLoc &letVarInOutLoc, - Parser::ParsedParameter::SpecifierKindTy &specifierKind, - Identifier argName, SourceLoc argNameLoc, - Identifier paramName, SourceLoc paramNameLoc, - TypeRepr *type, - const DeclAttributes &Attrs) -> Pattern * { - // Create the parameter based on the name. - Pattern *param; - ParamDecl *var = nullptr; - // Create a variable to capture this. - var = new (ctx) ParamDecl(specifierKind == Parser::ParsedParameter::Let, - argNameLoc, argName, - paramNameLoc, paramName, Type(), - parser.CurDeclContext); - var->getAttrs() = Attrs; + auto createParam = [&](Parser::ParsedParameter ¶mInfo, + Identifier argName, SourceLoc argNameLoc, + Identifier paramName, SourceLoc paramNameLoc) + -> ParamDecl * { + auto specifierKind = paramInfo.SpecifierKind; + bool isLet = specifierKind == Parser::ParsedParameter::Let; + auto param = new (ctx) ParamDecl(isLet, paramInfo.LetVarInOutLoc, + argNameLoc, argName, + paramNameLoc, paramName, Type(), + parser.CurDeclContext); + param->getAttrs() = paramInfo.Attrs; + if (argNameLoc.isInvalid() && paramNameLoc.isInvalid()) - var->setImplicit(); - param = new (ctx) NamedPattern(var); + param->setImplicit(); - // If a type was provided, create the typed pattern. - if (type) { + // If we parsed a colon but have no type, then we already diagnosed this + // as a parse error. + if (paramInfo.ColonLoc.isValid() && !paramInfo.Type) + param->setInvalid(); + + // If a type was provided, create the type for the parameter. + if (auto type = paramInfo.Type) { // If 'inout' was specified, turn the type into an in-out type. if (specifierKind == Parser::ParsedParameter::InOut) - type = new (ctx) InOutTypeRepr(type, letVarInOutLoc); + type = new (ctx) InOutTypeRepr(type, paramInfo.LetVarInOutLoc); - param = new (ctx) TypedPattern(param, type); + param->getTypeLoc() = TypeLoc(type); + } else if (paramContext != Parser::ParameterContextKind::Closure) { + // Non-closure parameters require a type. + if (!param->isInvalid()) + parser.diagnose(param->getLoc(), diag::missing_parameter_type); + + param->getTypeLoc() = TypeLoc::withoutLoc(ErrorType::get(ctx)); + param->setInvalid(); } else if (specifierKind == Parser::ParsedParameter::InOut) { - parser.diagnose(letVarInOutLoc, diag::inout_must_have_type); - letVarInOutLoc = SourceLoc(); + parser.diagnose(paramInfo.LetVarInOutLoc, diag::inout_must_have_type); + paramInfo.LetVarInOutLoc = SourceLoc(); specifierKind = Parser::ParsedParameter::Let; } - - // If 'var' or 'let' was specified explicitly, create a pattern for it. - if (specifierKind != Parser::ParsedParameter::InOut && - letVarInOutLoc.isValid()) { - bool isLet = specifierKind == Parser::ParsedParameter::Let; - param = new (ctx) VarPattern(letVarInOutLoc, isLet, param); - } - - if (var) - var->setParamParentPattern(param); return param; }; // Collect the elements of the tuple patterns for argument and body // parameters. - SmallVector elements; + SmallVector elements; SourceLoc ellipsisLoc; bool isFirstParameter = true; for (auto ¶m : params) { @@ -427,7 +404,7 @@ mapParsedParameters(Parser &parser, } // Create the pattern. - Pattern *pattern; + ParamDecl *result = nullptr; Identifier argName; Identifier paramName; if (param.SecondNameLoc.isValid()) { @@ -435,10 +412,8 @@ mapParsedParameters(Parser &parser, paramName = param.SecondName; // Both names were provided, so pass them in directly. - pattern = createParamPattern(param.LetVarInOutLoc, param.SpecifierKind, - argName, param.FirstNameLoc, - paramName, param.SecondNameLoc, - param.Type, param.Attrs); + result = createParam(param, argName, param.FirstNameLoc, + paramName, param.SecondNameLoc); // If the first name is empty and this parameter would not have been // an API name by default, complain. @@ -461,31 +436,12 @@ mapParsedParameters(Parser &parser, .fixItRemoveChars(param.FirstNameLoc, param.SecondNameLoc); } } else { - // If it's an API name by default, or there was a pound, we have an - // API name. - if (isKeywordArgumentByDefault || param.PoundLoc.isValid()) { + if (isKeywordArgumentByDefault) argName = param.FirstName; - - // THe pound is going away. Complain. - if (param.PoundLoc.isValid()) { - if (isKeywordArgumentByDefault) { - parser.diagnose(param.PoundLoc, diag::parameter_extraneous_pound, - argName) - .fixItRemove(param.PoundLoc); - } else { - parser.diagnose(param.PoundLoc, diag::parameter_pound_double_up, - argName.str()) - .fixItReplace(param.PoundLoc, (argName.str() + " ").str()); - } - } - } - paramName = param.FirstName; - pattern = createParamPattern(param.LetVarInOutLoc, param.SpecifierKind, - argName, SourceLoc(), - param.FirstName, param.FirstNameLoc, - param.Type, param.Attrs); + result = createParam(param, argName, SourceLoc(), + param.FirstName, param.FirstNameLoc); } // If this parameter had an ellipsis, check whether it's the last parameter. @@ -496,29 +452,25 @@ mapParsedParameters(Parser &parser, .fixItRemove(param.EllipsisLoc); param.EllipsisLoc = SourceLoc(); - } else if (!isa(pattern)) { + } else if (!result->getTypeLoc().getTypeRepr()) { parser.diagnose(param.EllipsisLoc, diag::untyped_pattern_ellipsis) - .highlight(pattern->getSourceRange()); + .highlight(result->getSourceRange()); param.EllipsisLoc = SourceLoc(); } else { ellipsisLoc = param.EllipsisLoc; + result->setVariadic(); } } - // Default arguments are only permitted on the first parameter clause. - if (param.DefaultArg && !isFirstParameterClause) { - parser.diagnose(param.EqualLoc, diag::non_func_decl_pattern_init) - .fixItRemove(SourceRange(param.EqualLoc, - param.DefaultArg->getExpr()->getEndLoc())); + if (param.DefaultArg) { + assert(isFirstParameterClause && + "Default arguments are only permitted on the first param clause"); + result->setDefaultArgumentKind(getDefaultArgKind(param.DefaultArg)); + result->setDefaultValue(param.DefaultArg); } - // Create the tuple pattern elements. - auto defArgKind = getDefaultArgKind(param.DefaultArg); - elements.push_back(TuplePatternElt(argName, param.FirstNameLoc, pattern, - param.EllipsisLoc.isValid(), - param.EllipsisLoc, param.DefaultArg, - defArgKind)); + elements.push_back(result); if (argNames) argNames->push_back(argName); @@ -526,11 +478,11 @@ mapParsedParameters(Parser &parser, isFirstParameter = false; } - return TuplePattern::createSimple(ctx, leftParenLoc, elements, rightParenLoc); + return ParameterList::create(ctx, leftParenLoc, elements, rightParenLoc); } /// Parse a single parameter-clause. -ParserResult Parser::parseSingleParameterClause( +ParserResult Parser::parseSingleParameterClause( ParameterContextKind paramContext, SmallVectorImpl *namePieces) { ParserStatus status; @@ -542,11 +494,11 @@ ParserResult Parser::parseSingleParameterClause( /*defaultArgs=*/nullptr, paramContext); // Turn the parameter clause into argument and body patterns. - auto pattern = mapParsedParameters(*this, leftParenLoc, params, + auto paramList = mapParsedParameters(*this, leftParenLoc, params, rightParenLoc, true, namePieces, paramContext); - return makeParserResult(status, pattern); + return makeParserResult(status, paramList); } /// Parse function arguments. @@ -561,13 +513,13 @@ ParserResult Parser::parseSingleParameterClause( /// ParserStatus Parser::parseFunctionArguments(SmallVectorImpl &NamePieces, - SmallVectorImpl &BodyPatterns, + SmallVectorImpl &BodyParams, ParameterContextKind paramContext, DefaultArgumentInfo &DefaultArgs) { // Parse parameter-clauses. ParserStatus status; bool isFirstParameterClause = true; - unsigned FirstBodyPatternIndex = BodyPatterns.size(); + unsigned FirstBodyPatternIndex = BodyParams.size(); while (Tok.is(tok::l_paren)) { SmallVector params; SourceLoc leftParenLoc, rightParenLoc; @@ -583,39 +535,34 @@ Parser::parseFunctionArguments(SmallVectorImpl &NamePieces, isFirstParameterClause ? &NamePieces : nullptr, paramContext); - BodyPatterns.push_back(pattern); + BodyParams.push_back(pattern); isFirstParameterClause = false; paramContext = ParameterContextKind::Curried; } - // If the decl uses currying syntax, warn that that syntax is going away. - if (BodyPatterns.size() - FirstBodyPatternIndex > 1) { + // If the decl uses currying syntax, complain that that syntax has gone away. + if (BodyParams.size() - FirstBodyPatternIndex > 1) { SourceRange allPatternsRange( - BodyPatterns[FirstBodyPatternIndex]->getStartLoc(), - BodyPatterns.back()->getEndLoc()); + BodyParams[FirstBodyPatternIndex]->getStartLoc(), + BodyParams.back()->getEndLoc()); auto diag = diagnose(allPatternsRange.Start, diag::parameter_curry_syntax_removed); diag.highlight(allPatternsRange); bool seenArg = false; - auto isEmptyPattern = [](Pattern *pattern) -> bool { - auto *tuplePattern = dyn_cast(pattern); - return tuplePattern && tuplePattern->getNumElements() == 0; - }; - for (unsigned i = FirstBodyPatternIndex; i < BodyPatterns.size() - 1; i++) { + for (unsigned i = FirstBodyPatternIndex; i < BodyParams.size() - 1; i++) { // Replace ")(" with ", ", so "(x: Int)(y: Int)" becomes // "(x: Int, y: Int)". But just delete them if they're not actually // separating any arguments, e.g. in "()(y: Int)". StringRef replacement(", "); - Pattern *leftPattern = BodyPatterns[i]; - Pattern *rightPattern = BodyPatterns[i + 1]; - if (!isEmptyPattern(leftPattern)) { + auto *leftParamList = BodyParams[i]; + auto *rightParamList = BodyParams[i + 1]; + if (leftParamList->size() != 0) seenArg = true; - } - if (!seenArg || isEmptyPattern(rightPattern)) { + if (!seenArg || rightParamList->size() == 0) replacement = ""; - } - diag.fixItReplace(SourceRange(leftPattern->getEndLoc(), - rightPattern->getStartLoc()), + + diag.fixItReplace(SourceRange(leftParamList->getEndLoc(), + rightParamList->getStartLoc()), replacement); } } @@ -633,7 +580,7 @@ Parser::parseFunctionArguments(SmallVectorImpl &NamePieces, ParserStatus Parser::parseFunctionSignature(Identifier SimpleName, DeclName &FullName, - SmallVectorImpl &bodyPatterns, + SmallVectorImpl &bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throwsLoc, bool &rethrows, @@ -651,28 +598,26 @@ Parser::parseFunctionSignature(Identifier SimpleName, else paramContext = ParameterContextKind::Function; - Status = parseFunctionArguments(NamePieces, bodyPatterns, paramContext, + Status = parseFunctionArguments(NamePieces, bodyParams, paramContext, defaultArgs); FullName = DeclName(Context, SimpleName, llvm::makeArrayRef(NamePieces.begin() + 1, NamePieces.end())); - if (bodyPatterns.empty()) { + if (bodyParams.empty()) { // If we didn't get anything, add a () pattern to avoid breaking // invariants. assert(Status.hasCodeCompletion() || Status.isError()); - bodyPatterns.push_back(TuplePattern::create(Context, Tok.getLoc(), - {}, Tok.getLoc())); + bodyParams.push_back(ParameterList::createEmpty(Context)); } } else { diagnose(Tok, diag::func_decl_without_paren); Status = makeParserError(); // Recover by creating a '() -> ?' signature. - auto *EmptyTuplePattern = - TuplePattern::create(Context, PreviousLoc, {}, PreviousLoc); - bodyPatterns.push_back(EmptyTuplePattern); - FullName = DeclName(Context, SimpleName, { }); + bodyParams.push_back(ParameterList::createEmpty(Context, PreviousLoc, + PreviousLoc)); + FullName = DeclName(Context, SimpleName, bodyParams.back()); } // Check for the 'throws' keyword. @@ -739,7 +684,8 @@ Parser::parseFunctionSignature(Identifier SimpleName, } ParserStatus -Parser::parseConstructorArguments(DeclName &FullName, Pattern *&BodyPattern, +Parser::parseConstructorArguments(DeclName &FullName, + ParameterList *&BodyParams, DefaultArgumentInfo &DefaultArgs) { // If we don't have the leading '(', complain. if (!Tok.is(tok::l_paren)) { @@ -750,10 +696,9 @@ Parser::parseConstructorArguments(DeclName &FullName, Pattern *&BodyPattern, diag.fixItInsert(Tok.getLoc(), "() "); } - // Create an empty tuple to recover. - BodyPattern = TuplePattern::createSimple(Context, PreviousLoc, {}, - PreviousLoc, true); - FullName = DeclName(Context, Context.Id_init, { }); + // Create an empty parameter list to recover. + BodyParams = ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc); + FullName = DeclName(Context, Context.Id_init, BodyParams); return makeParserError(); } @@ -768,11 +713,11 @@ Parser::parseConstructorArguments(DeclName &FullName, Pattern *&BodyPattern, // Turn the parameter clause into argument and body patterns. llvm::SmallVector namePieces; - BodyPattern = mapParsedParameters(*this, leftParenLoc, params, - rightParenLoc, - /*isFirstParameterClause=*/true, - &namePieces, - ParameterContextKind::Initializer); + BodyParams = mapParsedParameters(*this, leftParenLoc, params, + rightParenLoc, + /*isFirstParameterClause=*/true, + &namePieces, + ParameterContextKind::Initializer); FullName = DeclName(Context, Context.Id_init, namePieces); return status; @@ -855,8 +800,8 @@ ParserResult Parser::parsePattern() { } else { // In an always immutable context, `var` is not allowed. if (alwaysImmutable) - diagnose(varLoc, diag::var_not_allowed_in_pattern, isLetKeyword) - .fixItRemove(varLoc); + diagnose(varLoc, diag::var_not_allowed_in_pattern) + .fixItRemove(varLoc); } // In our recursive parse, remember that we're in a var/let pattern. @@ -890,8 +835,8 @@ Pattern *Parser::createBindingFromPattern(SourceLoc loc, Identifier name, bool isLet) { VarDecl *var; if (ArgumentIsParameter) { - var = new (Context) ParamDecl(isLet, loc, name, loc, name, Type(), - CurDeclContext); + var = new (Context) ParamDecl(isLet, SourceLoc(), loc, name, loc, name, + Type(), CurDeclContext); } else { var = new (Context) VarDecl(/*static*/ false, /*IsLet*/ isLet, loc, name, Type(), CurDeclContext); @@ -922,14 +867,7 @@ Parser::parsePatternTupleElement() { if (pattern.isNull()) return std::make_pair(makeParserError(), None); - // Consume the '...'. - SourceLoc ellipsisLoc; - if (Tok.isEllipsis()) - ellipsisLoc = consumeToken(); - auto Elt = TuplePatternElt(Label, LabelLoc, pattern.get(), - ellipsisLoc.isValid(), ellipsisLoc, - nullptr, DefaultArgumentKind::None); - + auto Elt = TuplePatternElt(Label, LabelLoc, pattern.get()); return std::make_pair(makeParserSuccess(), Elt); } @@ -1067,7 +1005,7 @@ ParserResult Parser::parseMatchingPatternAsLetOrVar(bool isLet, diagnose(varLoc, diag::let_pattern_in_immutable_context); if (!isLet && InVarOrLetPattern == IVOLP_AlwaysImmutable) - diagnose(varLoc, diag::var_not_allowed_in_pattern, isLet) + diagnose(varLoc, diag::var_not_allowed_in_pattern) .fixItReplace(varLoc, "let"); // In our recursive parse, remember that we're in a var/let pattern. diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index 5ee6810d40bb3..e780218bb5d93 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -71,7 +71,6 @@ SILParserTUState::~SILParserTUState() { namespace { struct ParsedSubstitution { SourceLoc loc; - Identifier name; Type replacement; }; @@ -92,7 +91,6 @@ namespace { /// Data structures used to perform name lookup for local values. llvm::StringMap LocalValues; - llvm::StringMap> ForwardMRVLocalValues; llvm::StringMap ForwardRefLocalValues; bool performTypeLocChecking(TypeLoc &T, bool IsSIL = true); @@ -134,10 +132,8 @@ namespace { struct UnresolvedValueName { StringRef Name; SourceLoc NameLoc; - unsigned ResultVal; bool isUndef() const { return Name == "undef"; } - bool isMRV() const { return ResultVal != ~0U; } }; /// getLocalValue - Get a reference to a local value with the specified name @@ -337,7 +333,7 @@ bool SILParser::parseVerbatim(StringRef name) { bool SILParser::diagnoseProblems() { // Check for any uses of basic blocks that were not defined. if (!UndefinedBlocks.empty()) { - // FIXME: These are going to come out in nondeterminstic order. + // FIXME: These are going to come out in nondeterministic order. for (auto Entry : UndefinedBlocks) P.diagnose(Entry.second.first, diag::sil_undefined_basicblock_use, Entry.second.second); @@ -346,7 +342,7 @@ bool SILParser::diagnoseProblems() { } if (!ForwardRefLocalValues.empty()) { - // FIXME: These are going to come out in nondeterminstic order. + // FIXME: These are going to come out in nondeterministic order. for (auto &Entry : ForwardRefLocalValues) P.diagnose(Entry.second, diag::sil_use_of_undefined_value, Entry.first()); @@ -506,20 +502,7 @@ SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type, if (Entry) { // If this value is already defined, check it to make sure types match. - SILType EntryTy; - - // If this is a reference to something with multiple results, get the right - // one. - if (Name.isMRV()) { - if (Name.ResultVal >= Entry->getTypes().size()) { - HadError = true; - P.diagnose(Name.NameLoc, diag::invalid_sil_value_name_result_number); - // Make sure to return something of the requested type. - return new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); - } - } - - EntryTy = Entry->getType(Name.isMRV() ? Name.ResultVal : 0); + SILType EntryTy = Entry->getType(); if (EntryTy != Type) { HadError = true; @@ -529,27 +512,15 @@ SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type, return new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); } - return SILValue(Entry, Name.isMRV() ? Name.ResultVal : 0); + return SILValue(Entry); } // Otherwise, this is a forward reference. Create a dummy node to represent // it until we see a real definition. ForwardRefLocalValues[Name.Name] = Name.NameLoc; - if (!Name.isMRV()) { - Entry = new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); - return Entry; - } - - // If we have multiple results, track them through ForwardMRVLocalValues. - std::vector &Placeholders = ForwardMRVLocalValues[Name.Name]; - if (Placeholders.size() <= Name.ResultVal) - Placeholders.resize(Name.ResultVal+1); - - if (!Placeholders[Name.ResultVal]) - Placeholders[Name.ResultVal] = - new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); - return Placeholders[Name.ResultVal]; + Entry = new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); + return Entry; } /// setLocalValue - When an instruction or block argument is defined, this @@ -568,15 +539,14 @@ void SILParser::setLocalValue(ValueBase *Value, StringRef Name, } // If the forward reference was of the wrong type, diagnose this now. - if (Entry->getTypes() != Value->getTypes()) { - // FIXME: report correct entry + if (Entry->getType() != Value->getType()) { P.diagnose(NameLoc, diag::sil_value_def_type_mismatch, Name, - Entry->getType(0).getSwiftRValueType(), - Value->getType(0).getSwiftRValueType()); + Entry->getType().getSwiftRValueType(), + Value->getType().getSwiftRValueType()); HadError = true; } else { // Forward references only live here if they have a single result. - SILValue(Entry).replaceAllUsesWith(SILValue(Value)); + Entry->replaceAllUsesWith(Value); } Entry = Value; return; @@ -584,45 +554,6 @@ void SILParser::setLocalValue(ValueBase *Value, StringRef Name, // Otherwise, just store it in our map. Entry = Value; - - // If Entry has multiple values, it may be forward referenced. - if (Entry->getTypes().size() > 1) { - auto It = ForwardMRVLocalValues.find(Name); - if (It != ForwardMRVLocalValues.end()) { - // Take the information about the forward ref out of the maps. - std::vector Entries(std::move(It->second)); - SourceLoc Loc = ForwardRefLocalValues[Name]; - - // Remove the entries from the maps. - ForwardRefLocalValues.erase(Name); - ForwardMRVLocalValues.erase(It); - - // Verify that any forward-referenced values line up. - if (Entries.size() > Value->getTypes().size()) { - P.diagnose(Loc, diag::sil_value_def_type_mismatch, Name, - Entry->getType(0).getSwiftRValueType(), - Value->getType(0).getSwiftRValueType()); - HadError = true; - return; - } - - // Validate that any forward-referenced elements have the right type, and - // RAUW them. - for (unsigned i = 0, e = Entries.size(); i != e; ++i) { - if (!Entries[i]) continue; - - if (Entries[i]->getType(0) != Value->getType(i)) { - P.diagnose(Loc, diag::sil_value_def_type_mismatch, Name, - Entry->getType(0).getSwiftRValueType(), - Value->getType(i).getSwiftRValueType()); - HadError = true; - return; - } - - Entries[i].replaceAllUsesWith(SILValue(Value, i)); - } - } - } } @@ -711,10 +642,9 @@ static bool parseSILOptional(bool &Result, SILParser &SP, StringRef Expected) { static bool parseDeclSILOptional(bool *isTransparent, bool *isFragile, IsThunk_t *isThunk, bool *isGlobalInit, - Inline_t *inlineStrategy, - bool *isLet, - std::string *Semantics, EffectsKind *MRK, - Parser &P) { + Inline_t *inlineStrategy, bool *isLet, + SmallVectorImpl *Semantics, + EffectsKind *MRK, Parser &P) { while (P.consumeIf(tok::l_square)) { if (isLet && P.Tok.is(tok::kw_let)) { *isLet = true; @@ -754,7 +684,7 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isFragile, // Drop the double quotes. StringRef rawString = P.Tok.getText().drop_front().drop_back(); - *Semantics = rawString; + Semantics->push_back(rawString); P.consumeToken(tok::string_literal); P.parseToken(tok::r_square, diag::expected_in_attribute_list); @@ -918,16 +848,6 @@ bool SILParser::parseSILType(SILType &Result, GenericParamList *&GenericParams, attrs.setAttr(TAK_convention, P.PreviousLoc); attrs.convention = "thin"; } - - // Handle @local_storage, which changes the SIL value category. - if (attrs.has(TAK_local_storage)) { - // Require '*' on local_storage values. - if (category != SILValueCategory::Address) - P.diagnose(attrs.getLoc(TAK_local_storage), - diag::sil_local_storage_non_address); - category = SILValueCategory::LocalStorage; - attrs.clearAttribute(TAK_local_storage); - } return parseSILTypeWithoutQualifiers(Result, category, attrs, GenericParams, IsFuncDecl); } @@ -1106,7 +1026,7 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Result, /// parseValueName - Parse a value name without a type available yet. /// /// sil-value-name: -/// sil-local-name ('#' integer_literal)? +/// sil-local-name /// 'undef' /// bool SILParser::parseValueName(UnresolvedValueName &Result) { @@ -1114,7 +1034,6 @@ bool SILParser::parseValueName(UnresolvedValueName &Result) { if (P.Tok.is(tok::kw_undef)) { Result.NameLoc = P.consumeToken(tok::kw_undef); - Result.ResultVal = ~1U; return false; } @@ -1123,21 +1042,6 @@ bool SILParser::parseValueName(UnresolvedValueName &Result) { diag::expected_sil_value_name)) return true; - // If the result value specifier is present, parse it. - if (P.consumeIf(tok::pound)) { - unsigned Value = 0; - if (P.Tok.isNot(tok::integer_literal) || - P.Tok.getText().getAsInteger(10, Value)) { - P.diagnose(P.Tok, diag::expected_sil_value_name_result_number); - return true; - } - - P.consumeToken(tok::integer_literal); - Result.ResultVal = Value; - } else { - Result.ResultVal = ~0U; - } - return false; } @@ -1258,6 +1162,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc, .Case("pointer_to_thin_function", ValueKind::PointerToThinFunctionInst) .Case("project_block_storage", ValueKind::ProjectBlockStorageInst) .Case("project_box", ValueKind::ProjectBoxInst) + .Case("project_existential_box", ValueKind::ProjectExistentialBoxInst) .Case("project_value_buffer", ValueKind::ProjectValueBufferInst) .Case("existential_metatype", ValueKind::ExistentialMetatypeInst) .Case("raw_pointer_to_ref", ValueKind::RawPointerToRefInst) @@ -1267,6 +1172,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc, .Case("ref_to_unmanaged", ValueKind::RefToUnmanagedInst) .Case("ref_to_unowned", ValueKind::RefToUnownedInst) .Case("retain_value", ValueKind::RetainValueInst) + .Case("alloc_global", ValueKind::AllocGlobalInst) .Case("global_addr", ValueKind::GlobalAddrInst) .Case("strong_pin", ValueKind::StrongPinInst) .Case("strong_release", ValueKind::StrongReleaseInst) @@ -1392,10 +1298,6 @@ bool SILParser::parseApplySubstitutions( // Parse a list of Substitutions. do { SourceLoc Loc = P.Tok.getLoc(); - Substitution Sub; - SILType Replace; - Identifier ArcheId; - TypeAttributes emptyAttrs; // Parse substitution as AST type. ParserResult TyR = P.parseType(); @@ -1404,7 +1306,7 @@ bool SILParser::parseApplySubstitutions( TypeLoc Ty = TyR.get(); if (performTypeLocChecking(Ty, false)) return true; - parsed.push_back({Loc, ArcheId, Ty.getType()}); + parsed.push_back({Loc, Ty.getType()}); } while (P.consumeIf(tok::comma)); // Consume the closing '>'. @@ -1426,61 +1328,62 @@ getConformanceOfReplacement(Parser &P, Type subReplacement, return conformance.getPointer(); } -/// Return true if B is derived from A. -static bool isDerivedFrom(ArchetypeType *A, ArchetypeType *B) { - if (A == B) - return true; - auto *p = B; - while ((p = p->getParent())) { - if (p == A) +static bool isImpliedBy(ProtocolDecl *proto, ArrayRef derived) { + for (auto derivedProto : derived) { + if (derivedProto == proto || derivedProto->inheritsFrom(proto)) return true; } return false; } +static bool allowAbstractConformance(Parser &P, Type subReplacement, + ProtocolDecl *proto) { + if (!subReplacement->hasDependentProtocolConformances()) + return false; + + // AnyObject is implicitly conformed to by anything with a class bound. + if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject) && + subReplacement->isAnyClassReferenceType()) { + return true; + } + + if (auto archetype = subReplacement->getAs()) { + return isImpliedBy(proto, archetype->getConformsTo()); + } + + SmallVector existentialProtos; + if (subReplacement->isExistentialType(existentialProtos)) { + return isImpliedBy(proto, existentialProtos); + } + + return false; +} + /// Collect conformances by looking up the conformance from replacement /// type and protocol decl in GenericParamList. static bool getConformancesForSubstitution(Parser &P, GenericParamList *gp, ArchetypeType *subArchetype, Type subReplacement, SourceLoc loc, - SmallVectorImpl &conformances) { - for (auto params = gp; params; params = params->getOuterParameters()) { - for (auto param : *params) { - if (param->getInherited().empty()) - continue; - - auto *pArch = param->getArchetype(); - if (!pArch || !isDerivedFrom(pArch, subArchetype)) - continue; - - // If subArchetype is C.Index and we have C inherits from P, we - // need to find the protocol conformance to P.Index. For now, we - // check if the replacement type conforms to subArchetype->getConformsTo. - for (auto *proto : subArchetype->getConformsTo()) - if (auto *pConform = - getConformanceOfReplacement(P, subReplacement, proto)) - conformances.push_back(pConform); + SmallVectorImpl &conformances) { + for (auto proto : subArchetype->getConformsTo()) { + // Try looking up a concrete conformance. + if (auto conformance = + getConformanceOfReplacement(P, subReplacement, proto)) { + conformances.push_back(ProtocolConformanceRef(conformance)); + continue; } - for (const auto &req : params->getRequirements()) { - if (req.getKind() != RequirementKind::Conformance) - continue; - - if (req.getSubject().getPointer() != subArchetype) - continue; - - if (auto *protoTy = req.getConstraint()->getAs()) - if (auto *pConform = - getConformanceOfReplacement(P, subReplacement, protoTy->getDecl())) - conformances.push_back(pConform); + // If the replacement type has dependent conformances, we might be + // able to use an abstract conformance. + if (allowAbstractConformance(P, subReplacement, proto)) { + conformances.push_back(ProtocolConformanceRef(proto)); + continue; } - } - if (subArchetype && !subReplacement->hasDependentProtocolConformances() && - conformances.size() != subArchetype->getConformsTo().size()) { P.diagnose(loc, diag::sil_substitution_mismatch); return true; } + return false; } @@ -1500,13 +1403,13 @@ bool getApplySubstitutionsFromParsed( auto parsed = parses.front(); parses = parses.slice(1); - SmallVector conformances; + SmallVector conformances; if (getConformancesForSubstitution(SP.P, gp, subArchetype, parsed.replacement, parsed.loc, conformances)) return true; - subs.push_back({subArchetype, parsed.replacement, + subs.push_back({parsed.replacement, SP.P.Context.AllocateCopy(conformances)}); } if (!parses.empty()) { @@ -1516,8 +1419,8 @@ bool getApplySubstitutionsFromParsed( return false; } -// FIXME: we work around canonicalization of PolymorphicFunctionType -// by generating GenericSignature and transforming the input, output +// FIXME: We work around the canonicalization of PolymorphicFunctionType +// by generating a GenericSignature and transforming the input, output // types. static GenericSignature *canonicalPolymorphicFunctionType( PolymorphicFunctionType *Ty, @@ -1610,7 +1513,7 @@ static bool checkFunctionType(FunctionType *Ty, FunctionType *Ty2, Ty2->getResult()->getCanonicalType(), Context, 1)); } -static ArrayRef +static ArrayRef collectExistentialConformances(Parser &P, CanType conformingType, CanType protocolType) { SmallVector protocols; @@ -1620,12 +1523,13 @@ collectExistentialConformances(Parser &P, if (protocols.empty()) return {}; - MutableArrayRef conformances = - P.Context.Allocate(protocols.size()); + MutableArrayRef conformances = + P.Context.AllocateUninitialized(protocols.size()); for (unsigned i : indices(protocols)) { - conformances[i] - = getConformanceOfReplacement(P, conformingType, protocols[i]); + auto proto = protocols[i]; + auto conformance = getConformanceOfReplacement(P, conformingType, proto); + conformances[i] = ProtocolConformanceRef(proto, conformance); } return conformances; @@ -1785,6 +1689,8 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { encoding = StringLiteralInst::Encoding::UTF8; } else if (P.Tok.getText() == "utf16") { encoding = StringLiteralInst::Encoding::UTF16; + } else if (P.Tok.getText() == "objc_selector") { + encoding = StringLiteralInst::Encoding::ObjCSelector; } else { P.diagnose(P.Tok, diag::sil_string_invalid_encoding, P.Tok.getText()); return true; @@ -1842,6 +1748,16 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { break; } + case ValueKind::ProjectExistentialBoxInst: { + SILType Ty; + if (parseSILType(Ty) || + parseVerbatim("in") || + parseTypedValueRef(Val, B)) + return true; + ResultVal = B.createProjectExistentialBox(InstLoc, Ty, Val); + break; + } + case ValueKind::FunctionRefInst: if (parseSILFunctionRef(InstLoc, B, ResultVal)) return true; @@ -2008,14 +1924,14 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { return true; if (Opcode == ValueKind::LoadUnownedInst) { - if (!Val.getType().is()) { + if (!Val->getType().is()) { P.diagnose(addrLoc, diag::sil_operand_not_unowned_address, "source", OpcodeName); } ResultVal = B.createLoadUnowned(InstLoc, Val, IsTake_t(isTake)); } else { - if (!Val.getType().is()) { + if (!Val->getType().is()) { P.diagnose(addrLoc, diag::sil_operand_not_weak_address, "source", OpcodeName); } @@ -2229,8 +2145,8 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { case ValueKind::CheckedCastBranchInst: { SILType ty; SILValue destVal; - Identifier kindToken, toToken; - SourceLoc kindLoc, toLoc; + Identifier toToken; + SourceLoc toLoc; bool isExact = false; if (Opcode == ValueKind::CheckedCastBranchInst && @@ -2336,14 +2252,14 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { return true; } - if (!addrVal.getType().isAddress()) { + if (!addrVal->getType().isAddress()) { P.diagnose(addrLoc, diag::sil_operand_not_address, "destination", OpcodeName); return true; } if (Opcode == ValueKind::StoreUnownedInst) { - auto refType = addrVal.getType().getAs(); + auto refType = addrVal->getType().getAs(); if (!refType) { P.diagnose(addrLoc, diag::sil_operand_not_unowned_address, "destination", OpcodeName); @@ -2357,7 +2273,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { } if (Opcode == ValueKind::StoreWeakInst) { - auto refType = addrVal.getType().getAs(); + auto refType = addrVal->getType().getAs(); if (!refType) { P.diagnose(addrLoc, diag::sil_operand_not_weak_address, "destination", OpcodeName); @@ -2370,7 +2286,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { break; } - SILType ValType = addrVal.getType().getObjectType(); + SILType ValType = addrVal->getType().getObjectType(); if (Opcode == ValueKind::StoreInst) { ResultVal = B.createStore(InstLoc, @@ -2512,7 +2428,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { do { if (parseTypedValueRef(Val, B)) return true; OpList.push_back(Val); - TypeElts.push_back(Val.getType().getSwiftRValueType()); + TypeElts.push_back(Val->getType().getSwiftRValueType()); } while (P.consumeIf(tok::comma)); } HadError |= P.parseToken(tok::r_paren, @@ -2550,7 +2466,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { SILFileLocation(P.Tok.getLoc()), B)) return true; OpList.push_back(Val); - TypeElts.push_back(Val.getType().getSwiftRValueType()); + TypeElts.push_back(Val->getType().getSwiftRValueType()); } while (P.consumeIf(tok::comma)); } HadError |= P.parseToken(tok::r_paren, @@ -2595,7 +2511,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { return true; EnumElementDecl *Elt = cast(EltRef.getDecl()); - auto ResultTy = Operand.getType().getEnumElementType(Elt, SILMod); + auto ResultTy = Operand->getType().getEnumElementType(Elt, SILMod); switch (Opcode) { case swift::ValueKind::InitEnumDataAddrInst: @@ -2627,14 +2543,13 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { } case ValueKind::TupleElementAddrInst: case ValueKind::TupleExtractInst: { - Identifier ElemId; SourceLoc NameLoc; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; unsigned Field = 0; - TupleType *TT = Val.getType().getAs(); + TupleType *TT = Val->getType().getAs(); if (P.Tok.isNot(tok::integer_literal) || P.Tok.getText().getAsInteger(10, Field) || Field >= TT->getNumElements()) { @@ -2824,7 +2739,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { P.diagnose(TyLoc, diag::sil_witness_method_not_protocol); return true; } - ProtocolConformance *Conformance = nullptr; + ProtocolConformanceRef Conformance(proto); if (!isa(LookupTy)) { auto lookup = P.SF.getParentModule()->lookupConformance( LookupTy, proto, nullptr); @@ -2832,7 +2747,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { P.diagnose(TyLoc, diag::sil_witness_method_type_does_not_conform); return true; } - Conformance = lookup.getPointer(); + Conformance = ProtocolConformanceRef(lookup.getPointer()); } ResultVal = B.createWitnessMethod(InstLoc, LookupTy, Conformance, Member, @@ -2857,12 +2772,12 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { return true; } - if (!DestLVal.getType().isAddress()) { + if (!DestLVal->getType().isAddress()) { P.diagnose(DestLoc, diag::sil_invalid_instr_operands); return true; } - SILValue SrcLVal = getLocalValue(SrcLName, DestLVal.getType(), InstLoc, B); + SILValue SrcLVal = getLocalValue(SrcLName, DestLVal->getType(), InstLoc, B); ResultVal = B.createCopyAddr(InstLoc, SrcLVal, DestLVal, IsTake_t(IsTake), IsInitialization_t(IsInit)); @@ -2904,7 +2819,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { // FIXME: substitution means this type should be explicit to improve // performance. - auto ResultTy = Val.getType().getFieldType(Field, SILMod); + auto ResultTy = Val->getType().getFieldType(Field, SILMod); if (Opcode == ValueKind::StructElementAddrInst) ResultVal = B.createStructElementAddr(InstLoc, Val, Field, ResultTy.getAddressType()); @@ -2925,7 +2840,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { return true; } VarDecl *Field = cast(FieldV); - auto ResultTy = Val.getType().getFieldType(Field, SILMod); + auto ResultTy = Val->getType().getFieldType(Field, SILMod); ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy); break; } @@ -2975,6 +2890,23 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { ResultVal = B.createObjCProtocol(InstLoc, cast(VD), Ty); break; } + case ValueKind::AllocGlobalInst: { + Identifier GlobalName; + SourceLoc IdLoc; + if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) || + parseSILIdentifier(GlobalName, IdLoc, diag::expected_sil_value_name)) + return true; + + // Go through list of global variables in the SILModule. + SILGlobalVariable *global = SILMod.lookUpGlobalVariable(GlobalName.str()); + if (!global) { + P.diagnose(IdLoc, diag::sil_global_variable_not_found, GlobalName); + return true; + } + + ResultVal = B.createAllocGlobal(InstLoc, global); + break; + } case ValueKind::GlobalAddrInst: { Identifier GlobalName; SourceLoc IdLoc; @@ -3123,14 +3055,14 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { // Parse 'case' value-ref ':' sil-identifier. if (P.consumeIf(tok::kw_case)) { - if (parseValueRef(CaseVal, Val.getType(), + if (parseValueRef(CaseVal, Val->getType(), SILFileLocation(P.Tok.getLoc()), B)) { // TODO: Issue a proper error message here P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "reference to a value"); return true; } - auto intTy = Val.getType().getAs(); - auto functionTy = Val.getType().getAs(); + auto intTy = Val->getType().getAs(); + auto functionTy = Val->getType().getAs(); if (!intTy && !functionTy) { P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); return true; @@ -3138,32 +3070,36 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { if (intTy) { // If it is a switch on an integer type, check that all case values - // are integer literals. - auto *IL = dyn_cast(CaseVal); - if (!IL) { - P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); - return true; - } - APInt CaseValue = IL->getValue(); + // are integer literals or undef. + if (!isa(CaseVal)) { + auto *IL = dyn_cast(CaseVal); + if (!IL) { + P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); + return true; + } + APInt CaseValue = IL->getValue(); - if (CaseValue.getBitWidth() != intTy->getGreatestWidth()) - CaseVal = B.createIntegerLiteral( - IL->getLoc(), Val.getType(), - CaseValue.zextOrTrunc(intTy->getGreatestWidth())); + if (CaseValue.getBitWidth() != intTy->getGreatestWidth()) + CaseVal = B.createIntegerLiteral( + IL->getLoc(), Val->getType(), + CaseValue.zextOrTrunc(intTy->getGreatestWidth())); + } } if (functionTy) { // If it is a switch on a function type, check that all case values - // are function references. - auto *FR = dyn_cast(CaseVal); - if (!FR) { - if (auto *CF = dyn_cast(CaseVal)) { - FR = dyn_cast(CF->getOperand()); + // are function references or undef. + if (!isa(CaseVal)) { + auto *FR = dyn_cast(CaseVal); + if (!FR) { + if (auto *CF = dyn_cast(CaseVal)) { + FR = dyn_cast(CF->getOperand()); + } + } + if (!FR) { + P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); + return true; } - } - if (!FR) { - P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); - return true; } } @@ -3230,7 +3166,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { SILValue DefaultValue; if (DefaultResultName) DefaultValue = getLocalValue(*DefaultResultName, ResultType, InstLoc, B); - SILType ValType = Val.getType(); + SILType ValType = Val->getType(); for (auto &caseName : CaseValueAndResultNames) CaseValues.push_back(std::make_pair( getLocalValue(caseName.first, ValType, InstLoc, B), @@ -3256,7 +3192,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { // Lower the type at the abstraction level of the existential. auto archetype - = ArchetypeType::getOpened(Val.getType().getSwiftRValueType()) + = ArchetypeType::getOpened(Val->getType().getSwiftRValueType()) ->getCanonicalType(); SILType LoweredTy = SILMod.Types.getLoweredType( @@ -3264,9 +3200,9 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { .getAddressType(); // Collect conformances for the type. - ArrayRef conformances + ArrayRef conformances = collectExistentialConformances(P, Ty, - Val.getType().getSwiftRValueType()); + Val->getType().getSwiftRValueType()); ResultVal = B.createInitExistentialAddr(InstLoc, Val, Ty, LoweredTy, conformances); @@ -3282,22 +3218,13 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { parseASTType(ConcreteFormalTy)) return true; - // Lower the type at the abstraction level of the existential. - auto archetype - = ArchetypeType::getOpened(ExistentialTy.getSwiftRValueType()) - ->getCanonicalType(); - - SILType LoweredTy = SILMod.Types.getLoweredType( - Lowering::AbstractionPattern(archetype), ConcreteFormalTy) - .getAddressType(); - // Collect conformances for the type. - ArrayRef conformances + ArrayRef conformances = collectExistentialConformances(P, ConcreteFormalTy, ExistentialTy.getSwiftRValueType()); ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy, - ConcreteFormalTy, LoweredTy, conformances); + ConcreteFormalTy, conformances); break; } @@ -3312,7 +3239,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { parseSILType(ExistentialTy)) return true; - ArrayRef conformances + ArrayRef conformances = collectExistentialConformances(P, FormalConcreteTy, ExistentialTy.getSwiftRValueType()); @@ -3329,10 +3256,21 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(ExistentialTy)) return true; + + auto baseExType = ExistentialTy.getSwiftRValueType(); + auto formalConcreteType = Val->getType().getSwiftRValueType(); + while (auto instExType = dyn_cast(baseExType)) { + baseExType = instExType.getInstanceType(); + formalConcreteType = + cast(formalConcreteType).getInstanceType(); + } + + ArrayRef conformances + = collectExistentialConformances(P, formalConcreteType, + ExistentialTy.getSwiftRValueType()); - // FIXME: We should be parsing conformances here. ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy, - ArrayRef()); + conformances); break; } case ValueKind::DynamicMethodBranchInst: { @@ -3366,7 +3304,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { Identifier invoke, type; SourceLoc invokeLoc, typeLoc; - SILValue invokeVal, invokeValLoc; + SILValue invokeVal; SILType blockType; @@ -3455,7 +3393,7 @@ bool SILParser::parseCallInstruction(SILLocation InstLoc, SILValue FnVal = getLocalValue(FnName, Ty, InstLoc, B); - SILType FnTy = FnVal.getType(); + SILType FnTy = FnVal->getType(); CanSILFunctionType substFTI = FTI; if (!subs.empty()) { auto silFnTy = FnTy.castTo(); @@ -3659,7 +3597,7 @@ bool Parser::parseDeclSIL() { IsThunk_t isThunk = IsNotThunk; bool isGlobalInit = false; Inline_t inlineStrategy = InlineDefault; - std::string Semantics; + SmallVector Semantics; EffectsKind MRK = EffectsKind::Unspecified; if (parseSILLinkage(FnLinkage, *this) || parseDeclSILOptional(&isTransparent, &isFragile, &isThunk, &isGlobalInit, @@ -3690,8 +3628,9 @@ bool Parser::parseDeclSIL() { FunctionState.F->setGlobalInit(isGlobalInit); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setEffectsKind(MRK); - if (!Semantics.empty()) - FunctionState.F->setSemanticsAttr(Semantics); + for (auto &Attr : Semantics) { + FunctionState.F->addSemanticsAttr(Attr); + } // Now that we have a SILFunction parse the body, if present. @@ -3722,7 +3661,7 @@ bool Parser::parseDeclSIL() { if (FunctionState.diagnoseProblems()) return true; - // If SIL prsing succeeded, verify the generated SIL. + // If SIL parsing succeeded, verify the generated SIL. if (!FunctionState.P.Diags.hadAnyError()) FunctionState.F->verify(); @@ -3994,25 +3933,6 @@ bool SILParser::parseSpecConformanceSubstitutions( // Parse a list of Substitutions: Archetype = Replacement. do { SourceLoc Loc = P.Tok.getLoc(); - Substitution Sub; - Identifier ArcheId; - std::string ArcheStr; - bool FirstToken = true; - - // It is possible to have Base.Element as the Archetype name. - do { - Identifier TmpId; - if (parseSILIdentifier(TmpId, diag::expected_sil_type)) - return true; - if (!FirstToken) - ArcheStr += "."; - ArcheStr += TmpId.str(); - FirstToken = false; - } while (P.consumeIf(tok::period)); - ArcheId = P.Context.getIdentifier(ArcheStr); - - if (P.parseToken(tok::equal, diag::expected_tok_in_sil_instr, "=")) - return true; // Parse substitution as AST type. ParserResult TyR = P.parseType(); @@ -4021,7 +3941,7 @@ bool SILParser::parseSpecConformanceSubstitutions( TypeLoc Ty = TyR.get(); if (performTypeLocChecking(Ty, false)) return true; - parsed.push_back({Loc, ArcheId, Ty.getType()}); + parsed.push_back({Loc, Ty.getType()}); } while (P.consumeIf(tok::comma)); // Consume the closing '>'. @@ -4033,38 +3953,6 @@ bool SILParser::parseSpecConformanceSubstitutions( return false; } -/// Reconstruct AST substitutions from parsed substitutions using archetypes -/// from a BoundGenericType. -static bool getSpecConformanceSubstitutionsFromParsed( - Parser &P, - GenericParamList *gp, - ArrayRef parses, - SmallVectorImpl &subs) { - for (auto &parsed : parses) { - ArchetypeType *subArchetype = nullptr; - Type subReplacement; - // Find the corresponding ArchetypeType. - for (auto archetype : gp->getAllNestedArchetypes()) - if (archetype->getFullName() == parsed.name.str()) { - subArchetype = archetype; - break; - } - if (!subArchetype) { - P.diagnose(parsed.loc, diag::sil_witness_archetype_not_found); - return true; - } - subReplacement = parsed.replacement; - SmallVector conformances; - if (getConformancesForSubstitution(P, gp, subArchetype, subReplacement, - parsed.loc, conformances)) - return true; - - subs.push_back({subArchetype, subReplacement, - P.Context.AllocateCopy(conformances)}); - } - return false; -} - ProtocolConformance *SILParser::parseProtocolConformance( ProtocolDecl *&proto, GenericParamList *&generics, ArchetypeBuilder &builder, bool localScope) { @@ -4074,7 +3962,7 @@ ProtocolConformance *SILParser::parseProtocolConformance( if (localScope) GenericsScope.emplace(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams(); + generics = P.maybeParseGenericParams().getPtrOrNull(); if (generics) { generics->setBuilder(&builder); SmallVector builders(1, &builder); @@ -4138,7 +4026,7 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper( return nullptr; SmallVector subs; - if (getSpecConformanceSubstitutionsFromParsed(P, gp, parsedSubs, subs)) + if (getApplySubstitutionsFromParsed(*this, gp, parsedSubs, subs)) return nullptr; auto result = P.Context.getSpecializedConformance( @@ -4280,18 +4168,19 @@ bool Parser::parseSILWitnessTable() { parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; - ProtocolConformance *conform = nullptr; + ProtocolConformanceRef conformance(proto); if (Tok.getText() != "dependent") { ArchetypeBuilder builder(*SF.getParentModule(), Diags); - conform = WitnessState.parseProtocolConformance(builder); - if (!conform) // Ignore this witness entry for now. + auto concrete = WitnessState.parseProtocolConformance(builder); + if (!concrete) // Ignore this witness entry for now. continue; + conformance = ProtocolConformanceRef(concrete); } else { consumeToken(); } witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{ - assoc, proto, conform + assoc, proto, ProtocolConformanceRef(conformance) }); continue; } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index f4446086d4e9f..704b7df4663cd 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -258,6 +258,10 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, skipExtraTopLevelRBraces()) continue; + // Eat invalid tokens instead of allowing them to produce downstream errors. + if (consumeIf(tok::unknown)) + continue; + bool NeedParseErrorRecovery = false; ASTNode Result; @@ -453,7 +457,7 @@ void Parser::parseTopLevelCodeDeclDelayed() { // Ensure that we restore the parser state at exit. ParserPositionRAII PPR(*this); - // Create a lexer that can not go past the end state. + // Create a lexer that cannot go past the end state. Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); // Temporarily swap out the parser's current lexer with our new one. @@ -700,7 +704,7 @@ ParserResult Parser::parseStmtReturn(SourceLoc tryLoc) { ParserResult Result = parseExpr(diag::expected_expr_return); if (Result.isNull()) { // Create an ErrorExpr to tell the type checker that this return - // statement had an expression argument in the source. This supresses + // statement had an expression argument in the source. This suppresses // the error about missing return value in a non-void function. Result = makeParserErrorResult(new (Context) ErrorExpr(ExprLoc)); } @@ -780,8 +784,8 @@ ParserResult Parser::parseStmtDefer() { // // As such, the body of the 'defer' is actually type checked within the // closure's DeclContext. - auto params = TuplePattern::create(Context, SourceLoc(), {}, SourceLoc()); - DeclName name(Context, Context.getIdentifier("$defer"), {}); + auto params = ParameterList::createEmpty(Context); + DeclName name(Context, Context.getIdentifier("$defer"), params); auto tempDecl = FuncDecl::create(Context, /*static*/ SourceLoc(), @@ -815,7 +819,8 @@ ParserResult Parser::parseStmtDefer() { // Form the call, which will be emitted on any path that needs to run the // code. - auto DRE = new (Context) DeclRefExpr(tempDecl, loc, /*Implicit*/true, + auto DRE = new (Context) DeclRefExpr(tempDecl, DeclNameLoc(loc), + /*Implicit*/true, AccessSemantics::DirectToStorage); auto args = TupleExpr::createEmpty(Context, loc, loc, true); auto call = new (Context) CallExpr(DRE, args, /*implicit*/true); @@ -1525,17 +1530,11 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { while (iOperand < numElements) { if (auto *UDREOp = dyn_cast(elements[iOperator])) { - auto name = UDREOp->getName().str(); + auto name = UDREOp->getName().getBaseName().str(); if (name.equals("||") || name.equals("&&")) { auto rhs = evaluateConfigConditionExpr(elements[iOperand]); - if (result.getKind() == ConfigExprKind::CompilerVersion - || rhs.getKind() == ConfigExprKind::CompilerVersion) { - diagnose(UDREOp->getLoc(), diag::cannot_combine_compiler_version); - return ConfigParserState::error(); - } - if (name.equals("||")) { result = result || rhs; if (result.isConditionActive()) @@ -1563,7 +1562,7 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { // Evaluate a named reference expression. if (auto *UDRE = dyn_cast(configExpr)) { - auto name = UDRE->getName().str(); + auto name = UDRE->getName().getBaseName().str(); return ConfigParserState(Context.LangOpts.hasBuildConfigOption(name), ConfigExprKind::DeclRef); } @@ -1576,7 +1575,8 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { // Evaluate a negation (unary "!") expression. if (auto *PUE = dyn_cast(configExpr)) { // If the PUE is not a negation expression, return false - auto name = cast(PUE->getFn())->getName().str(); + auto name = + cast(PUE->getFn())->getName().getBaseName().str(); if (name != "!") { diagnose(PUE->getLoc(), diag::unsupported_build_config_unary_expression); return ConfigParserState::error(); @@ -1589,18 +1589,25 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { if (auto *CE = dyn_cast(configExpr)) { // look up target config, and compare value auto fnNameExpr = dyn_cast(CE->getFn()); - + // Get the arg, which should be in a paren expression. - auto *PE = dyn_cast(CE->getArg()); - if (!fnNameExpr || !PE) { + if (!fnNameExpr) { diagnose(CE->getLoc(), diag::unsupported_target_config_expression); return ConfigParserState::error(); } - auto fnName = fnNameExpr->getName().str(); + auto fnName = fnNameExpr->getName().getBaseName().str(); + + auto *PE = dyn_cast(CE->getArg()); + if (!PE) { + auto diag = diagnose(CE->getLoc(), + diag::target_config_expected_one_argument); + return ConfigParserState::error(); + } if (!fnName.equals("arch") && !fnName.equals("os") && !fnName.equals("_runtime") && + !fnName.equals("swift") && !fnName.equals("_compiler_version")) { diagnose(CE->getLoc(), diag::unsupported_target_config_expression); return ConfigParserState::error(); @@ -1609,7 +1616,7 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { if (fnName.equals("_compiler_version")) { if (auto SLE = dyn_cast(PE->getSubExpr())) { if (SLE->getValue().empty()) { - diagnose(CE->getLoc(), diag::empty_compiler_version_string); + diagnose(CE->getLoc(), diag::empty_version_string); return ConfigParserState::error(); } auto versionRequirement = @@ -1625,11 +1632,49 @@ ConfigParserState Parser::evaluateConfigConditionExpr(Expr *configExpr) { "string literal"); return ConfigParserState::error(); } + } else if(fnName.equals("swift")) { + auto PUE = dyn_cast(PE->getSubExpr()); + if (!PUE) { + diagnose(PE->getSubExpr()->getLoc(), + diag::unsupported_target_config_argument, + "a unary comparison, such as '>=2.2'"); + return ConfigParserState::error(); + } + + auto prefix = dyn_cast(PUE->getFn()); + auto versionArg = PUE->getArg(); + auto versionStartLoc = versionArg->getStartLoc(); + auto endLoc = Lexer::getLocForEndOfToken(SourceMgr, + versionArg->getSourceRange().End); + CharSourceRange versionCharRange(SourceMgr, versionStartLoc, + endLoc); + auto versionString = SourceMgr.extractText(versionCharRange); + + auto versionRequirement = + version::Version::parseVersionString(versionString, + versionStartLoc, + &Diags); + + if (!versionRequirement.hasValue()) + return ConfigParserState::error(); + + auto thisVersion = version::Version::getCurrentLanguageVersion(); + + if (!prefix->getName().getBaseName().str().equals(">=")) { + diagnose(PUE->getFn()->getLoc(), + diag::unexpected_version_comparison_operator) + .fixItReplace(PUE->getFn()->getLoc(), ">="); + return ConfigParserState::error(); + } + + auto VersionNewEnough = thisVersion >= versionRequirement.getValue(); + return ConfigParserState(VersionNewEnough, + ConfigExprKind::LanguageVersion); } else { if (auto UDRE = dyn_cast(PE->getSubExpr())) { // The sub expression should be an UnresolvedDeclRefExpr (we won't // tolerate extra parens). - auto argument = UDRE->getName().str(); + auto argument = UDRE->getName().getBaseName().str(); // Error for values that don't make sense if there's a clear definition // of the possible values (as there is for _runtime). @@ -1808,10 +1853,9 @@ ParserResult Parser::parseStmtRepeat(LabeledStmtInfo labelInfo) { SourceLoc whileLoc; if (!consumeIf(tok::kw_while, whileLoc)) { - diagnose(whileLoc, diag::expected_while_after_repeat_body); - if (body.isNonNull()) - return body; - return makeParserError(); + diagnose(body.getPtrOrNull()->getEndLoc(), + diag::expected_while_after_repeat_body); + return body; } ParserResult condition; @@ -2010,9 +2054,7 @@ static BraceStmt *ConvertClosureToBraceStmt(Expr *E, ASTContext &Ctx) { // doesn't "look" like the body of a control flow statement, it looks like a // closure. if (CE->getInLoc().isValid() || CE->hasExplicitResultType() || - !CE->getParams()->isImplicit() || - !isa(CE->getParams()) || - cast(CE->getParams())->getNumElements() != 0) + CE->getParameters()->size() != 0) return nullptr; // Silence downstream errors by giving it type ()->(), to match up with the diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 1c7f7d22f3854..772623897163c 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -156,7 +156,7 @@ ParserResult Parser::parseType(Diag<> MessageID, // body. GenericParamList *generics = nullptr; if (isInSILMode()) { - generics = maybeParseGenericParams(); + generics = maybeParseGenericParams().getPtrOrNull(); } ParserResult ty = parseTypeSimple(MessageID, HandleCodeCompletion); @@ -260,9 +260,7 @@ bool Parser::parseGenericArguments(SmallVectorImpl &Args, ParserResult Ty = parseType(diag::expected_type); if (Ty.isNull() || Ty.hasCodeCompletion()) { // Skip until we hit the '>'. - skipUntilGreaterInTypeList(); - if (startsWithGreater(Tok)) - consumeStartingGreater(); + RAngleLoc = skipUntilGreaterInTypeList(); return true; } @@ -276,9 +274,7 @@ bool Parser::parseGenericArguments(SmallVectorImpl &Args, diagnose(LAngleLoc, diag::opening_angle); // Skip until we hit the '>'. - skipUntilGreaterInTypeList(); - if (startsWithGreater(Tok)) - RAngleLoc = consumeStartingGreater(); + RAngleLoc = skipUntilGreaterInTypeList(); return true; } else { RAngleLoc = consumeStartingGreater(); @@ -315,7 +311,7 @@ ParserResult Parser::parseTypeIdentifier() { if (Tok.is(tok::kw_Self)) { Loc = consumeIdentifier(&Name); } else { - // FIXME: specialize diagnostic for 'Type': type can not start with + // FIXME: specialize diagnostic for 'Type': type cannot start with // 'metatype' // FIXME: offer a fixit: 'self' -> 'Self' if (parseIdentifier(Name, Loc, diag::expected_identifier_in_dotted_type)) @@ -427,7 +423,9 @@ ParserResult Parser::parseTypeComposition() { // Check for the terminating '>'. SourceLoc EndLoc = PreviousLoc; - if (!startsWithGreater(Tok)) { + if (startsWithGreater(Tok)) { + EndLoc = consumeStartingGreater(); + } else { if (Status.isSuccess()) { diagnose(Tok, diag::expected_rangle_protocol); diagnose(LAngleLoc, diag::opening_angle); @@ -435,11 +433,7 @@ ParserResult Parser::parseTypeComposition() { } // Skip until we hit the '>'. - skipUntilGreaterInTypeList(/*protocolComposition=*/true); - if (startsWithGreater(Tok)) - EndLoc = consumeStartingGreater(); - } else { - EndLoc = consumeStartingGreater(); + EndLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true); } return makeParserResult(Status, ProtocolCompositionTypeRepr::create( @@ -473,7 +467,7 @@ ParserResult Parser::parseTypeTupleBody() { // If the tuple element starts with "ident :", then // the identifier is an element tag, and it is followed by a type // annotation. - if (Tok.isIdentifierOrUnderscore() && peekToken().is(tok::colon)) { + if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) { // Consume the name Identifier name; if (!Tok.is(tok::kw__)) @@ -561,93 +555,39 @@ ParserResult Parser::parseTypeTupleBody() { /// type-array '[' ']' /// type-array '[' expr ']' /// -ParserResult Parser::parseTypeArray(TypeRepr *Base) { +ParserResult Parser::parseTypeArray(TypeRepr *Base) { assert(Tok.isFollowingLSquare()); Parser::StructureMarkerRAII ParsingArrayBound(*this, Tok); SourceLoc lsquareLoc = consumeToken(); - ParserResult NestedType = makeParserResult(Base); ArrayTypeRepr *ATR = nullptr; - // Handle the [] production, meaning an array slice. - if (Tok.is(tok::r_square)) { - SourceLoc rsquareLoc = consumeToken(tok::r_square); - - - // If we're starting another square-bracket clause, recur. - if (Tok.isFollowingLSquare()) { - NestedType = parseTypeArray(Base); - if (NestedType.hasCodeCompletion()) - return makeParserCodeCompletionResult(); - if (NestedType.isNull()) { - // We could not parse the rest of the type, but we still have the base - // type. - NestedType = makeParserErrorResult(Base); - } - } - - // Just build a normal array slice type. - ATR = new (Context) ArrayTypeRepr(NestedType.get(), nullptr, - SourceRange(lsquareLoc, rsquareLoc), - /*OldSyntax=*/true); - - if (NestedType.isParseError()) - return makeParserErrorResult(ATR); - else { - diagnose(lsquareLoc, diag::new_array_syntax) - .fixItInsert(Base->getStartLoc(), "[") - .fixItRemove(lsquareLoc); - - return makeParserResult(ATR); - } - } - - SourceLoc rsquareLoc; - - // We currently only accept an integer literal as the inner expression. - // FIXME: Should we decide to support integer constant expressions in the - // future, we will need to remove this check to accept any compositional - // expressions - ParserResult sizeEx = parseExprBasic(diag::expected_expr_array_type); + // Handle a postfix [] production, a common typo for a C-like array. - parseMatchingToken(tok::r_square, rsquareLoc, - diag::expected_rbracket_array_type, lsquareLoc); - - if (!sizeEx.isNull() && isa(sizeEx.get())) { + // If we have something that might be an array size expression, parse it as + // such, for better error recovery. + if (Tok.isNot(tok::r_square)) { + auto sizeEx = parseExprBasic(diag::expected_expr); if (sizeEx.hasCodeCompletion()) return makeParserCodeCompletionStatus(); - - NestedType = makeParserErrorResult(Base); - - // FIXME: We don't supported fixed-length arrays yet. - diagnose(lsquareLoc, diag::unsupported_fixed_length_array) - .highlight(sizeEx.get()->getSourceRange()); - - ATR = new (Context) ArrayTypeRepr(NestedType.get(), - nullptr, - SourceRange(lsquareLoc, - getEndOfPreviousLoc()), - /*OldSyntax=*/true); - return makeParserErrorResult(ATR); - } - - // If the size expression is null, we would have raised the - // expected_expr_array_type error above when the token stream failed to - // parse as an expression - if (!sizeEx.isNull()) { - diagnose(lsquareLoc, diag::expected_expr_array_type) - .highlight(sizeEx.get()->getSourceRange()); - } else { - // Skip until the next decl, statement or block - skipUntilDeclStmtRBrace(tok::l_brace); + if (sizeEx.isNull()) + return makeParserErrorResult(Base); } - - // Create an array slice type for the malformed array type specification - NestedType = makeParserErrorResult(Base); - ATR = new (Context) ArrayTypeRepr(NestedType.get(), nullptr, - SourceRange(lsquareLoc, - PreviousLoc), - /*OldSyntax=*/true); - return makeParserErrorResult(ATR); + + SourceLoc rsquareLoc; + if (parseMatchingToken(tok::r_square, rsquareLoc, + diag::expected_rbracket_array_type, lsquareLoc)) + return makeParserErrorResult(Base); + + // If we parsed something valid, diagnose it with a fixit to rewrite it to + // Swift syntax. + diagnose(lsquareLoc, diag::new_array_syntax) + .fixItInsert(Base->getStartLoc(), "[") + .fixItRemove(lsquareLoc); + + // Build a normal array slice type for recovery. + ATR = new (Context) ArrayTypeRepr(Base, + SourceRange(Base->getStartLoc(), rsquareLoc)); + return makeParserResult(ATR); } ParserResult Parser::parseTypeCollection() { @@ -693,9 +633,7 @@ ParserResult Parser::parseTypeCollection() { // Form the array type. return makeParserResult(firstTy, new (Context) ArrayTypeRepr(firstTy.get(), - nullptr, - brackets, - /*OldSyntax=*/false)); + brackets)); } bool Parser::isOptionalToken(const Token &T) const { @@ -755,9 +693,9 @@ Parser::parseTypeImplicitlyUnwrappedOptional(TypeRepr *base) { base, exclamationLoc)); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Speculative type list parsing -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// static bool isGenericTypeDisambiguatingToken(Parser &P) { auto &tok = P.Tok; @@ -991,8 +929,8 @@ bool Parser::canParseTypeTupleBody() { // If the tuple element starts with "ident :", then it is followed // by a type annotation. - if (Tok.is(tok::identifier) && peekToken().is(tok::colon)) { - consumeToken(tok::identifier); + if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) { + consumeToken(); consumeToken(tok::colon); // Parse attributes then a type. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a87769e2e08fc..d508232e8d595 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,7 @@ #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/Basic/SourceManager.h" +#include "swift/Basic/Timer.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/DelayedParsingCallbacks.h" @@ -136,6 +137,7 @@ bool swift::parseIntoSourceFile(SourceFile &SF, SILParserState *SIL, PersistentParserState *PersistentState, DelayedParsingCallbacks *DelayedParseCB) { + SharedTimer timer("Parsing"); Parser P(BufferID, SF, SIL, PersistentState); PrettyStackTraceParser StackTrace(P); @@ -153,6 +155,7 @@ bool swift::parseIntoSourceFile(SourceFile &SF, void swift::performDelayedParsing( DeclContext *DC, PersistentParserState &PersistentState, CodeCompletionCallbacksFactory *CodeCompletionFactory) { + SharedTimer timer("Parsing"); ParseDelayedFunctionBodies Walker(PersistentState, CodeCompletionFactory); DC->walkContext(Walker); @@ -225,7 +228,8 @@ std::vector swift::tokenize(const LangOptions &LangOpts, const SourceManager &SM, unsigned BufferID, unsigned Offset, unsigned EndOffset, bool KeepComments, - bool TokenizeInterpolatedString) { + bool TokenizeInterpolatedString, + ArrayRef SplitTokens) { if (Offset == 0 && EndOffset == 0) EndOffset = SM.getRangeForBuffer(BufferID).getByteLength(); @@ -233,10 +237,34 @@ std::vector swift::tokenize(const LangOptions &LangOpts, KeepComments ? CommentRetentionMode::ReturnAsTokens : CommentRetentionMode::AttachToNextToken, Offset, EndOffset); + + auto TokComp = [&] (const Token &A, const Token &B) { + return SM.isBeforeInBuffer(A.getLoc(), B.getLoc()); + }; + + std::set ResetTokens(TokComp); + for (auto C = SplitTokens.begin(), E = SplitTokens.end(); C != E; ++C) { + ResetTokens.insert(*C); + } + std::vector Tokens; do { Tokens.emplace_back(); L.lex(Tokens.back()); + + // If the token has the same location as a reset location, + // reset the token stream + auto F = ResetTokens.find(Tokens.back()); + if (F != ResetTokens.end()) { + Tokens.back() = *F; + assert(Tokens.back().isNot(tok::string_literal)); + + auto NewState = L.getStateForBeginningOfTokenLoc( + F->getLoc().getAdvancedLoc(F->getLength())); + L.restoreState(NewState); + continue; + } + if (Tokens.back().is(tok::string_literal) && TokenizeInterpolatedString) { Token StrTok = Tokens.back(); Tokens.pop_back(); @@ -332,12 +360,19 @@ SourceLoc Parser::consumeStartingCharacterOfCurrentToken() { return consumeToken(); } + markSplitToken(tok::oper_binary_unspaced, Tok.getText().substr(0, 1)); + // ... or a multi-character token with the first character being the one that // we want to consume as a separate token. restoreParserPosition(getParserPositionAfterFirstCharacter(Tok)); return PreviousLoc; } +void Parser::markSplitToken(tok Kind, StringRef Txt) { + SplitTokens.emplace_back(); + SplitTokens.back().setToken(Kind, Txt); +} + SourceLoc Parser::consumeStartingLess() { assert(startsWithLess(Tok) && "Token does not start with '<'"); return consumeStartingCharacterOfCurrentToken(); @@ -397,13 +432,18 @@ void Parser::skipUntilAnyOperator() { skipSingle(); } -void Parser::skipUntilGreaterInTypeList(bool protocolComposition) { +/// \brief Skip until a token that starts with '>', and consume it if found. +/// Applies heuristics that are suitable when trying to find the end of a list +/// of generic parameters, generic arguments, or list of types in a protocol +/// composition. +SourceLoc Parser::skipUntilGreaterInTypeList(bool protocolComposition) { + SourceLoc lastLoc = Tok.getLoc(); while (true) { switch (Tok.getKind()) { case tok::eof: case tok::l_brace: case tok::r_brace: - return; + return lastLoc; #define KEYWORD(X) case tok::kw_##X: #include "swift/Parse/Tokens.def" @@ -411,7 +451,7 @@ void Parser::skipUntilGreaterInTypeList(bool protocolComposition) { if (Tok.is(tok::kw_Self)) break; if (isStartOfStmt() || isStartOfDecl()) - return; + return lastLoc; break; case tok::l_paren: @@ -421,14 +461,16 @@ void Parser::skipUntilGreaterInTypeList(bool protocolComposition) { // In generic type parameter list, skip '[' ']' '(' ')', because they // can appear in types. if (protocolComposition) - return; + return lastLoc; break; default: if (Tok.isAnyOperator() && startsWithGreater(Tok)) - return; + return consumeStartingGreater(); + break; } + lastLoc = Tok.getLoc(); skipSingle(); } } @@ -612,7 +654,7 @@ Parser::parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc, // If the lexer stopped with an EOF token whose spelling is ")", then this // is actually the tuple that is a string literal interpolation context. // Just accept the ")" and build the tuple as we usually do. - if (Tok.is(tok::eof) && Tok.getText() == ")") { + if (Tok.is(tok::eof) && Tok.getText() == ")" && RightK == tok::r_paren) { RightLoc = Tok.getLoc(); return Status; } @@ -623,11 +665,21 @@ Parser::parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc, continue; } if (!OptionalSep) { + // If we're in a comma-separated list and the next token starts a new + // declaration at the beginning of a new line, skip until the end. + if (SeparatorK == tok::comma && Tok.isAtStartOfLine() && + isStartOfDecl() && Tok.getLoc() != StartLoc) { + skipUntilDeclRBrace(RightK, SeparatorK); + break; + } + StringRef Separator = (SeparatorK == tok::comma ? "," : ";"); diagnose(Tok, diag::expected_separator, Separator) .fixItInsertAfter(PreviousLoc, Separator); Status.setIsParseError(); } + + // If we haven't made progress, skip ahead if (Tok.getLoc() == StartLoc) { skipUntilDeclRBrace(RightK, SeparatorK); @@ -741,3 +793,90 @@ ConfigParserState swift::operator||(ConfigParserState lhs, ConfigParserState swift::operator!(ConfigParserState Result) { return ConfigParserState(!Result.isConditionActive(), Result.getKind()); } + +/// Parse a stringified Swift declaration name, e.g. "init(frame:)". +StringRef swift::parseDeclName(StringRef name, + SmallVectorImpl &argumentLabels, + bool &isFunctionName) { + if (name.empty()) return ""; + + if (name.back() != ')') { + isFunctionName = false; + if (Lexer::isIdentifier(name) && name != "_") + return name; + + return ""; + } + + isFunctionName = true; + + StringRef BaseName, Parameters; + std::tie(BaseName, Parameters) = name.split('('); + if (!Lexer::isIdentifier(BaseName) || BaseName == "_") + return ""; + + if (Parameters.empty()) + return ""; + Parameters = Parameters.drop_back(); // ')' + + if (Parameters.empty()) + return BaseName; + + if (Parameters.back() != ':') + return ""; + + do { + StringRef NextParam; + std::tie(NextParam, Parameters) = Parameters.split(':'); + + if (!Lexer::isIdentifier(NextParam)) + return ""; + if (NextParam == "_") + argumentLabels.push_back(""); + else + argumentLabels.push_back(NextParam); + } while (!Parameters.empty()); + + return BaseName; +} + +DeclName swift::formDeclName(ASTContext &ctx, + StringRef baseName, + ArrayRef argumentLabels, + bool isFunctionName) { + // We cannot import when the base name is not an identifier. + if (baseName.empty() || !Lexer::isIdentifier(baseName)) + return DeclName(); + + // Get the identifier for the base name. + Identifier baseNameId = ctx.getIdentifier(baseName); + + // For non-functions, just use the base name. + if (!isFunctionName) return baseNameId; + + // For functions, we need to form a complete name. + + // Convert the argument names. + SmallVector argumentLabelIds; + for (auto argName : argumentLabels) { + if (argumentLabels.empty() || !Lexer::isIdentifier(argName)) { + argumentLabelIds.push_back(Identifier()); + continue; + } + + argumentLabelIds.push_back(ctx.getIdentifier(argName)); + } + + // Build the result. + return DeclName(ctx, baseNameId, argumentLabelIds); +} + +DeclName swift::parseDeclName(ASTContext &ctx, StringRef name) { + // Parse the name string. + SmallVector argumentLabels; + bool isFunctionName; + StringRef baseName = parseDeclName(name, argumentLabels, isFunctionName); + + // Form the result. + return formDeclName(ctx, baseName, argumentLabels, isFunctionName); +} diff --git a/lib/Parse/PersistentParserState.cpp b/lib/Parse/PersistentParserState.cpp index 96a6e311f910e..6f70a8f1afb16 100644 --- a/lib/Parse/PersistentParserState.cpp +++ b/lib/Parse/PersistentParserState.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Parse/Scope.cpp b/lib/Parse/Scope.cpp index 9fdc7da5c93dd..4cf02f307cdc4 100644 --- a/lib/Parse/Scope.cpp +++ b/lib/Parse/Scope.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index ea67313eb90ec..503d5a4c80272 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -1,8 +1,8 @@ -//===-- PrintAsObjC.cpp - Emit a header file for a Swift AST --------------===// +//===--- PrintAsObjC.cpp - Emit a header file for a Swift AST -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,7 +37,8 @@ using namespace swift; static bool isNSObject(ASTContext &ctx, Type type) { if (auto classDecl = type->getClassOrBoundGenericClass()) { - return classDecl->getName() == ctx.Id_NSObject && + return classDecl->getName() + == ctx.getSwiftId(KnownFoundationEntity::NSObject) && classDecl->getModuleContext()->getName() == ctx.Id_ObjectiveC; } @@ -71,18 +72,18 @@ namespace { }; } -static Identifier getNameForObjC(const NominalTypeDecl *NTD, +static Identifier getNameForObjC(const ValueDecl *VD, CustomNamesOnly_t customNamesOnly = Normal) { - // FIXME: Should we support renaming for enums too? - assert(isa(NTD) || isa(NTD)); - if (auto objc = NTD->getAttrs().getAttribute()) { + assert(isa(VD) || isa(VD) + || isa(VD) || isa(VD)); + if (auto objc = VD->getAttrs().getAttribute()) { if (auto name = objc->getName()) { assert(name->getNumSelectorPieces() == 1); return name->getSelectorPieces().front(); } } - return customNamesOnly ? Identifier() : NTD->getName(); + return customNamesOnly ? Identifier() : VD->getName(); } @@ -235,16 +236,39 @@ class ObjCPrinter : private DeclVisitor, void visitEnumDecl(EnumDecl *ED) { printDocumentationComment(ED); - llvm::SmallString<32> scratch; - os << "typedef SWIFT_ENUM("; + os << "typedef "; + Identifier customName = getNameForObjC(ED, CustomNamesOnly); + if (customName.empty()) { + os << "SWIFT_ENUM("; + } else { + os << "SWIFT_ENUM_NAMED("; + } print(ED->getRawType(), OTK_None); - os << ", " << ED->getName() << ") {\n"; + if (customName.empty()) { + os << ", " << ED->getName(); + } else { + os << ", " << customName + << ", \"" << ED->getName() << "\""; + } + os << ") {\n"; for (auto Elt : ED->getAllElements()) { printDocumentationComment(Elt); // Print the cases as the concatenation of the enum name with the case // name. - os << " " << ED->getName() << Elt->getName(); + os << " "; + Identifier customEltName = getNameForObjC(Elt, CustomNamesOnly); + if (customEltName.empty()) { + if (customName.empty()) { + os << ED->getName(); + } else { + os << customName; + } + os << Elt->getName(); + } else { + os << customEltName + << " SWIFT_COMPILE_NAME(\"" << Elt->getName() << "\")"; + } if (auto ILE = cast_or_null(Elt->getRawValueExpr())) { os << " = "; @@ -258,7 +282,7 @@ class ObjCPrinter : private DeclVisitor, } void printSingleMethodParam(StringRef selectorPiece, - const Pattern *param, + const ParamDecl *param, const clang::ParmVarDecl *clangParam, bool isNSUIntegerSubscript, bool isLastPiece) { @@ -267,14 +291,14 @@ class ObjCPrinter : private DeclVisitor, (clangParam && isNSUInteger(clangParam->getType()))) { os << "NSUInteger"; } else { - this->print(param->getType(), OTK_None); + print(param->getType(), OTK_None); } os << ")"; - if (isa(param)) { + if (!param->hasName()) { os << "_"; } else { - Identifier name = cast(param)->getBodyName(); + Identifier name = param->getName(); os << name; if (isClangKeyword(name)) os << "_"; @@ -378,17 +402,13 @@ class ObjCPrinter : private DeclVisitor, os << ")"; - auto bodyPatterns = AFD->getBodyParamPatterns(); - assert(bodyPatterns.size() == 2 && "not an ObjC-compatible method"); + auto paramLists = AFD->getParameterLists(); + assert(paramLists.size() == 2 && "not an ObjC-compatible method"); - llvm::SmallString<128> selectorBuf; ArrayRef selectorPieces = AFD->getObjCSelector().getSelectorPieces(); - const TuplePattern *paramTuple - = dyn_cast(bodyPatterns.back()); - const ParenPattern *paramParen - = dyn_cast(bodyPatterns.back()); - assert((paramTuple || paramParen) && "Bad body parameters?"); + + const auto ¶ms = paramLists[1]->getArray(); unsigned paramIndex = 0; for (unsigned i = 0, n = selectorPieces.size(); i != n; ++i) { if (i > 0) os << ' '; @@ -413,37 +433,21 @@ class ObjCPrinter : private DeclVisitor, continue; } - // Single-parameter methods. - if (paramParen) { - assert(paramIndex == 0); - auto clangParam = clangMethod ? clangMethod->parameters()[0] : nullptr; - printSingleMethodParam(piece, - paramParen->getSemanticsProvidingPattern(), - clangParam, - isNSUIntegerSubscript, - i == n-1); - paramIndex = 1; - continue; - } - // Zero-parameter methods. - if (paramTuple->getNumElements() == 0) { + if (params.size() == 0) { assert(paramIndex == 0); os << piece; paramIndex = 1; continue; } - // Multi-parameter methods. const clang::ParmVarDecl *clangParam = nullptr; if (clangMethod) clangParam = clangMethod->parameters()[paramIndex]; - const TuplePatternElt ¶m = paramTuple->getElements()[paramIndex]; - auto pattern = param.getPattern()->getSemanticsProvidingPattern(); - printSingleMethodParam(piece, pattern, clangParam, - isNSUIntegerSubscript, - i == n-1); + // Single-parameter methods. + printSingleMethodParam(piece, params[paramIndex], clangParam, + isNSUIntegerSubscript, i == n-1); ++paramIndex; } @@ -752,7 +756,9 @@ class ObjCPrinter : private DeclVisitor, = { "BOOL", false}; specialNames[{ID_ObjectiveC, ctx.getIdentifier("Selector")}] = { "SEL", true }; - specialNames[{ID_ObjectiveC, ctx.getIdentifier("NSZone")}] + specialNames[{ID_ObjectiveC, + ctx.getIdentifier( + ctx.getSwiftName(KnownFoundationEntity::NSZone))}] = { "struct _NSZone *", true }; specialNames[{ctx.Id_Darwin, ctx.getIdentifier("DarwinBoolean")}] @@ -1614,7 +1620,7 @@ class ModuleWriter { "#endif\n" "#if !defined(SWIFT_CLASS)\n" "# if defined(__has_attribute) && " - "__has_attribute(objc_subclassing_restricted) \n" + "__has_attribute(objc_subclassing_restricted)\n" "# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) " "__attribute__((objc_subclassing_restricted)) " "SWIFT_CLASS_EXTRA\n" @@ -1656,6 +1662,15 @@ class ModuleWriter { "# define SWIFT_ENUM(_type, _name) " "enum _name : _type _name; " "enum SWIFT_ENUM_EXTRA _name : _type\n" + "# if defined(__has_feature) && " + "__has_feature(generalized_swift_name)\n" + "# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) " + "enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); " + "enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type\n" + "# else\n" + "# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) " + "SWIFT_ENUM(_type, _name)\n" + "# endif\n" "#endif\n" ; static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4, diff --git a/lib/SIL/AbstractionPattern.cpp b/lib/SIL/AbstractionPattern.cpp index fa01c67ea23d9..cc1e00119afdd 100644 --- a/lib/SIL/AbstractionPattern.cpp +++ b/lib/SIL/AbstractionPattern.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,21 +45,12 @@ AbstractionPattern TypeConverter::getAbstractionPattern(SubscriptDecl *decl) { AbstractionPattern TypeConverter::getIndicesAbstractionPattern(SubscriptDecl *decl) { - // TODO: use interface types - return AbstractionPattern(decl->getIndicesType()); -} - -bool AbstractionPattern::isOpaqueType(CanGenericSignature signature, - CanGenericTypeParamType type) { - // Enormous hack! We need to be asking the signature about this - // in a more principled way. - for (auto &reqt : signature->getRequirements()) { - if (reqt.getKind() != RequirementKind::Conformance) continue; - if (CanType(reqt.getFirstType()) != type) continue; - if (reqt.getSecondType()->isClassExistentialType()) - return false; - } - return true; + CanGenericSignature genericSig; + if (auto sig = decl->getGenericSignatureOfContext()) + genericSig = sig->getCanonicalSignature(); + return AbstractionPattern(genericSig, + decl->getIndicesInterfaceType() + ->getCanonicalType()); } static const clang::Type *getClangType(const clang::Decl *decl) { @@ -93,7 +84,13 @@ AbstractionPattern TypeConverter::getAbstractionPattern(VarDecl *var) { AbstractionPattern TypeConverter::getAbstractionPattern(EnumElementDecl *decl) { assert(decl->hasArgumentType()); assert(!decl->hasClangNode()); - return AbstractionPattern(decl->getArgumentType()); + + CanGenericSignature genericSig; + if (auto sig = decl->getParentEnum()->getGenericSignatureOfContext()) + genericSig = sig->getCanonicalSignature(); + return AbstractionPattern(genericSig, + decl->getArgumentInterfaceType() + ->getCanonicalType()); } AbstractionPattern::EncodedForeignErrorInfo @@ -171,6 +168,8 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) { case Kind::ClangFunctionParamTupleType: case Kind::ClangType: case Kind::Type: + if (isTypeParameter()) + return true; auto tuple = dyn_cast(getType()); return (tuple && tuple->getNumElements() == substType->getNumElements()); } @@ -230,6 +229,8 @@ AbstractionPattern::getTupleElementType(unsigned index) const { cast(getType()).getElementType(index), getClangArrayElementType(getClangType(), index)); case Kind::Type: + if (isTypeParameter()) + return AbstractionPattern::getOpaque(); return AbstractionPattern(getGenericSignature(), cast(getType()).getElementType(index)); case Kind::ClangFunctionParamTupleType: @@ -427,6 +428,8 @@ AbstractionPattern AbstractionPattern::dropLastTupleElement() const { case Kind::ObjCMethodFormalParamTupleType: llvm_unreachable("operation is not needed on method abstraction patterns"); case Kind::Type: + if (isTypeParameter()) + return AbstractionPattern::getOpaque(); return AbstractionPattern(getGenericSignature(), dropLastElement(getType())); @@ -488,6 +491,8 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const { case Kind::Opaque: return *this; case Kind::Type: + if (isTypeParameter()) + return AbstractionPattern::getOpaque(); return AbstractionPattern(getGenericSignatureForFunctionComponent(), getResultType(getType())); case Kind::ClangType: { @@ -523,6 +528,8 @@ AbstractionPattern AbstractionPattern::getFunctionInputType() const { case Kind::Opaque: return *this; case Kind::Type: + if (isTypeParameter()) + return AbstractionPattern::getOpaque(); return AbstractionPattern(getGenericSignatureForFunctionComponent(), cast(getType()).getInput()); case Kind::ClangType: { diff --git a/lib/SIL/Bridging.cpp b/lib/SIL/Bridging.cpp index 9c39041e829b5..f838c673055b3 100644 --- a/lib/SIL/Bridging.cpp +++ b/lib/SIL/Bridging.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,9 +30,8 @@ using namespace swift::Lowering; SILType TypeConverter::getLoweredTypeOfGlobal(VarDecl *var) { AbstractionPattern origType = getAbstractionPattern(var); - CanType swiftType = (origType.isOpaque() ? var->getType()->getCanonicalType() - : origType.getType()); - return getLoweredType(origType, swiftType).getObjectType(); + assert(!origType.isTypeParameter()); + return getLoweredType(origType, origType.getType()).getObjectType(); } CanType TypeConverter::getBridgedInputType(SILFunctionTypeRepresentation rep, diff --git a/lib/SIL/CMakeLists.txt b/lib/SIL/CMakeLists.txt index d31ed5a0de87b..120b3c5bef0ca 100644 --- a/lib/SIL/CMakeLists.txt +++ b/lib/SIL/CMakeLists.txt @@ -4,6 +4,7 @@ add_swift_library(swiftSIL Dominance.cpp DynamicCasts.cpp PrettyStackTrace.cpp + InstructionUtils.cpp SIL.cpp SILArgument.cpp SILBasicBlock.cpp @@ -18,10 +19,10 @@ add_swift_library(swiftSIL SILModule.cpp SILPrinter.cpp SILSuccessor.cpp + SILVerifier.cpp SILVTable.cpp SILWitnessTable.cpp TypeLowering.cpp - Verifier.cpp SILType.cpp SILValue.cpp SILDeclRef.cpp diff --git a/lib/SIL/Dominance.cpp b/lib/SIL/Dominance.cpp index 7fab6ea3f6b3d..78101df7faa7c 100644 --- a/lib/SIL/Dominance.cpp +++ b/lib/SIL/Dominance.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,10 +40,13 @@ bool DominanceInfo::properlyDominates(SILInstruction *a, SILInstruction *b) { // Otherwise, they're in the same block, and we just need to check // whether B comes after A. This is a non-strict computation. - SILInstruction *f = &*aBlock->begin(); - while (b != f) { - b = b->getPrevNode(); - if (a == b) return true; + auto aIter = a->getIterator(); + auto bIter = b->getIterator(); + auto fIter = aBlock->begin(); + while (bIter != fIter) { + --bIter; + if (aIter == bIter) + return true; } return false; @@ -68,7 +71,7 @@ void DominanceInfo::verify() const { PostDominanceInfo::PostDominanceInfo(SILFunction *F) : DominatorTreeBase(/*isPostDom*/ true) { assert(!F->isExternalDeclaration() && - "Can not construct a post dominator tree for a declaration"); + "Cannot construct a post dominator tree for a declaration"); recalculate(*F); } diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp index ac65c66071f0b..4e8502d2ff6a4 100644 --- a/lib/SIL/DynamicCasts.cpp +++ b/lib/SIL/DynamicCasts.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -400,7 +400,7 @@ swift::classifyDynamicCast(Module *M, // FIXME: tuple conversions? - // FIXME: Be more careful with briding conversions from + // FIXME: Be more careful with bridging conversions from // NSArray, NSDictionary and NSSet as they may fail? // Check if there might be a bridging conversion. @@ -459,7 +459,7 @@ namespace { CanType FormalType; CastConsumptionKind Consumption; - bool isAddress() const { return Value.getType().isAddress(); } + bool isAddress() const { return Value->getType().isAddress(); } IsTake_t shouldTake() const { return shouldTakeOnSuccess(Consumption); } @@ -482,13 +482,13 @@ namespace { } Source asScalarSource(SILValue value) const { assert(!isAddress()); - assert(!value.getType().isAddress()); + assert(!value->getType().isAddress()); return { value, FormalType, CastConsumptionKind::TakeAlways }; } Target() = default; Target(SILValue address, CanType formalType) - : Address(address), LoweredType(address.getType()), + : Address(address), LoweredType(address->getType()), FormalType(formalType) { assert(LoweredType.isAddress()); } @@ -529,7 +529,7 @@ namespace { } Source putOwnedScalar(SILValue scalar, Target target) { - assert(scalar.getType() == target.LoweredType.getObjectType()); + assert(scalar->getType() == target.LoweredType.getObjectType()); if (!target.isAddress()) return target.asScalarSource(scalar); @@ -542,7 +542,7 @@ namespace { Source emitSameType(Source source, Target target) { assert(source.FormalType == target.FormalType); - auto &srcTL = getTypeLowering(source.Value.getType()); + auto &srcTL = getTypeLowering(source.Value->getType()); // The destination always wants a +1 value, so make the source // +1 if it's a scalar. @@ -591,8 +591,8 @@ namespace { // FIXME: Upcasts between existential metatypes are not handled yet. // We should generate for it: // %openedSrcMetatype = open_existential srcMetatype - // init_existental dstMetatype, %openedSrcMetatype - auto &srcTL = getTypeLowering(source.Value.getType()); + // init_existential dstMetatype, %openedSrcMetatype + auto &srcTL = getTypeLowering(source.Value->getType()); SILValue value; if (source.isAddress()) { value = srcTL.emitLoadOfCopy(B, Loc, source.Value, source.shouldTake()); @@ -642,7 +642,7 @@ namespace { auto sourceSomeDecl = Ctx.getOptionalSomeDecl(sourceOptKind); SILType loweredSourceObjectType = - source.Value.getType().getEnumElementType(sourceSomeDecl, M); + source.Value->getType().getEnumElementType(sourceSomeDecl, M); // Form the target for the optional object. EmitSomeState state; @@ -657,8 +657,8 @@ namespace { SILValue sourceAddr = source.Value; if (!source.shouldTake()) { sourceTemp = B.createAllocStack(Loc, - sourceAddr.getType().getObjectType()); - sourceAddr = sourceTemp->getAddressResult(); + sourceAddr->getType().getObjectType()); + sourceAddr = sourceTemp; B.createCopyAddr(Loc, source.Value, sourceAddr, IsNotTake, IsInitialization); } @@ -677,7 +677,7 @@ namespace { // Deallocate the source temporary if we needed one. if (sourceTemp) { - B.createDeallocStack(Loc, sourceTemp->getContainerResult()); + B.createDeallocStack(Loc, sourceTemp); } Source result = emitSome(resultObject, target, state); @@ -743,7 +743,7 @@ namespace { B.createInjectEnumAddr(Loc, target.Address, state.SomeDecl); return target.asAddressSource(); } else { - auto &srcTL = getTypeLowering(source.Value.getType()); + auto &srcTL = getTypeLowering(source.Value->getType()); auto sourceObject = getOwnedScalar(source, srcTL); auto source = B.createEnum(Loc, sourceObject, state.SomeDecl, target.LoweredType); @@ -799,7 +799,7 @@ swift::emitSuccessfulScalarUnconditionalCast(SILBuilder &B, Module *M, Target target(loweredTargetType, targetType); Source result = CastEmitter(B, M, loc).emitTopLevel(source, target); assert(!result.isAddress()); - assert(result.Value.getType() == loweredTargetType); + assert(result.Value->getType() == loweredTargetType); assert(result.Consumption == CastConsumptionKind::TakeAlways); return result.Value; } @@ -815,8 +815,8 @@ bool swift::emitSuccessfulIndirectUnconditionalCast(SILBuilder &B, Module *M, assert(classifyDynamicCast(M, sourceType, targetType) == DynamicCastFeasibility::WillSucceed); - assert(src.getType().isAddress()); - assert(dest.getType().isAddress()); + assert(src->getType().isAddress()); + assert(dest->getType().isAddress()); // Casts between the same types can be always handled here. // Casts from non-existentials into existentials and @@ -824,11 +824,11 @@ bool swift::emitSuccessfulIndirectUnconditionalCast(SILBuilder &B, Module *M, // Casts between a value type and a class cannot be optimized. // Therefore generate a simple unconditional_checked_cast_aadr. - if (src.getType() != dest.getType()) - if (src.getType().isAnyExistentialType() != - dest.getType().isAnyExistentialType() || - !(src.getType().getClassOrBoundGenericClass() && - dest.getType().getClassOrBoundGenericClass())) { + if (src->getType() != dest->getType()) + if (src->getType().isAnyExistentialType() != + dest->getType().isAnyExistentialType() || + !(src->getType().getClassOrBoundGenericClass() && + dest->getType().getClassOrBoundGenericClass())) { // If there is an existing cast with the same arguments, // indicate we cannot improve it. if (existingCast) { @@ -939,14 +939,14 @@ emitIndirectConditionalCastWithScalar(SILBuilder &B, Module *M, // We always need a different success block. SILBasicBlock *scalarSuccBB = B.splitBlockForFallthrough(); - auto &srcTL = B.getModule().Types.getTypeLowering(src.getType()); + auto &srcTL = B.getModule().Types.getTypeLowering(src->getType()); // Always take; this works under an assumption that retaining the // result is equivalent to retaining the source. That means that // these casts would not be appropriate for bridging-like conversions. SILValue srcValue = srcTL.emitLoadOfCopy(B, loc, src, IsTake); - SILType targetValueType = dest.getType().getObjectType(); + SILType targetValueType = dest->getType().getObjectType(); B.createCheckedCastBranch(loc, /*exact*/ false, srcValue, targetValueType, scalarSuccBB, scalarFailBB); diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp new file mode 100644 index 0000000000000..68129f49c4bf4 --- /dev/null +++ b/lib/SIL/InstructionUtils.cpp @@ -0,0 +1,180 @@ +//===--- InstructionUtils.cpp - Utilities for SIL instructions ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-inst-utils" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/Projection.h" + +using namespace swift; + +/// Strip off casts/indexing insts/address projections from V until there is +/// nothing left to strip. +/// FIXME: Why don't we strip projections after stripping indexes? +SILValue swift::getUnderlyingObject(SILValue V) { + while (true) { + SILValue V2 = stripIndexingInsts(stripAddressProjections(stripCasts(V))); + if (V2 == V) + return V2; + V = V2; + } +} + +static bool isRCIdentityPreservingCast(ValueKind Kind) { + switch (Kind) { + case ValueKind::UpcastInst: + case ValueKind::UncheckedRefCastInst: + case ValueKind::UncheckedRefCastAddrInst: + case ValueKind::UnconditionalCheckedCastInst: + case ValueKind::RefToBridgeObjectInst: + case ValueKind::BridgeObjectToRefInst: + return true; + default: + return false; + } +} + +/// Return the underlying SILValue after stripping off identity SILArguments if +/// we belong to a BB with one predecessor. +SILValue swift::stripSinglePredecessorArgs(SILValue V) { + while (true) { + auto *A = dyn_cast(V); + if (!A) + return V; + + SILBasicBlock *BB = A->getParent(); + + // First try and grab the single predecessor of our parent BB. If we don't + // have one, bail. + SILBasicBlock *Pred = BB->getSinglePredecessor(); + if (!Pred) + return V; + + // Then grab the terminator of Pred... + TermInst *PredTI = Pred->getTerminator(); + + // And attempt to find our matching argument. + // + // *NOTE* We can only strip things here if we know that there is no semantic + // change in terms of upcasts/downcasts/enum extraction since this is used + // by other routines here. This means that we can only look through + // cond_br/br. + // + // For instance, routines that use stripUpcasts() do not want to strip off a + // downcast that results from checked_cast_br. + if (auto *BI = dyn_cast(PredTI)) { + V = BI->getArg(A->getIndex()); + continue; + } + + if (auto *CBI = dyn_cast(PredTI)) { + if (SILValue Arg = CBI->getArgForDestBB(BB, A)) { + V = Arg; + continue; + } + } + + return V; + } +} + +SILValue swift::stripCasts(SILValue V) { + while (true) { + V = stripSinglePredecessorArgs(V); + + auto K = V->getKind(); + if (isRCIdentityPreservingCast(K) + || K == ValueKind::UncheckedTrivialBitCastInst + || K == ValueKind::MarkDependenceInst) { + V = cast(V)->getOperand(0); + continue; + } + + return V; + } +} + +SILValue swift::stripUpCasts(SILValue V) { + assert(V->getType().isClassOrClassMetatype() && + "Expected class or class metatype!"); + + V = stripSinglePredecessorArgs(V); + + while (isa(V)) + V = stripSinglePredecessorArgs(cast(V)->getOperand()); + + return V; +} + +SILValue swift::stripClassCasts(SILValue V) { + while (true) { + if (auto *UI = dyn_cast(V)) { + V = UI->getOperand(); + continue; + } + + if (auto *UCCI = dyn_cast(V)) { + V = UCCI->getOperand(); + continue; + } + + return V; + } +} + +SILValue swift::stripAddressProjections(SILValue V) { + while (true) { + V = stripSinglePredecessorArgs(V); + if (!NewProjection::isAddressProjection(V)) + return V; + V = cast(V)->getOperand(0); + } +} + +SILValue swift::stripUnaryAddressProjections(SILValue V) { + while (true) { + V = stripSinglePredecessorArgs(V); + if (!NewProjection::isAddressProjection(V)) + return V; + auto *Inst = cast(V); + if (Inst->getNumOperands() > 1) + return V; + V = Inst->getOperand(0); + } +} + +SILValue swift::stripValueProjections(SILValue V) { + while (true) { + V = stripSinglePredecessorArgs(V); + if (!NewProjection::isObjectProjection(V)) + return V; + V = cast(V)->getOperand(0); + } +} + +SILValue swift::stripIndexingInsts(SILValue V) { + while (true) { + if (!isa(V)) + return V; + V = cast(V)->getBase(); + } +} + +SILValue swift::stripExpectIntrinsic(SILValue V) { + auto *BI = dyn_cast(V); + if (!BI) + return V; + if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::expect) + return V; + return BI->getArguments()[0]; +} diff --git a/lib/SIL/Linker.cpp b/lib/SIL/Linker.cpp index bd4f4a721a9e5..6a3e8ace66126 100644 --- a/lib/SIL/Linker.cpp +++ b/lib/SIL/Linker.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,7 +16,6 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include @@ -34,7 +33,7 @@ STATISTIC(NumFuncLinked, "Number of SIL functions linked"); static bool shouldImportFunction(SILFunction *F) { // Skip functions that are marked with the 'no import' tag. These // are functions that we don't want to copy from the module. - if (F->hasSemanticsString("stdlib_binary_only")) { + if (F->hasSemanticsAttr("stdlib_binary_only")) { // If we are importing a function declaration mark it as external since we // are not importing the body. if (F->isExternalDeclaration()) @@ -225,12 +224,13 @@ bool SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) { } bool SILLinkerVisitor::visitProtocolConformance( - ProtocolConformance *C, const Optional &Member) { - // If a null protocol conformance was passed in, just return false. - if (!C) + ProtocolConformanceRef ref, const Optional &Member) { + // If an abstract protocol conformance was passed in, just return false. + if (ref.isAbstract()) return false; // Otherwise try and lookup a witness table for C. + auto C = ref.getConcrete(); SILWitnessTable *WT = Mod.lookUpWitnessTable(C).first; // If we don't find any witness table for the conformance, bail and return @@ -283,7 +283,7 @@ bool SILLinkerVisitor::visitInitExistentialAddrInst( // visiting the open_existential_addr/witness_method before the // init_existential_inst. bool performFuncDeserialization = false; - for (ProtocolConformance *C : IEI->getConformances()) { + for (ProtocolConformanceRef C : IEI->getConformances()) { performFuncDeserialization |= visitProtocolConformance(C, Optional()); } @@ -300,7 +300,7 @@ bool SILLinkerVisitor::visitInitExistentialRefInst( // not going to be smart about this to enable avoiding any issues with // visiting the protocol_method before the init_existential_inst. bool performFuncDeserialization = false; - for (ProtocolConformance *C : IERI->getConformances()) { + for (ProtocolConformanceRef C : IERI->getConformances()) { performFuncDeserialization |= visitProtocolConformance(C, Optional()); } @@ -352,21 +352,6 @@ bool SILLinkerVisitor::process() { if (!shouldImportFunction(F)) continue; - // The ExternalSource may wish to rewrite non-empty bodies. - if (!F->isExternalDeclaration() && ExternalSource) { - if (auto *NewFn = ExternalSource->lookupSILFunction(F)) { - if (NewFn->isExternalDeclaration()) - continue; - - NewFn->verify(); - Worklist.push_back(NewFn); - - ++NumFuncLinked; - Result = true; - continue; - } - } - DEBUG(llvm::dbgs() << "Imported function: " << F->getName() << "\n"); F->setBare(IsBare); diff --git a/lib/SIL/Linker.h b/lib/SIL/Linker.h index dad956ed5e242..fd2bd7b95d5dd 100644 --- a/lib/SIL/Linker.h +++ b/lib/SIL/Linker.h @@ -1,8 +1,8 @@ -//===--- Linker.h --------------------------------------------*- C++ -*----===// +//===--- Linker.h -----------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,7 +14,6 @@ #define SWIFT_SIL_LINKER_H #include "swift/SIL/SILDebugScope.h" -#include "swift/SIL/SILExternalSource.h" #include "swift/SIL/SILVisitor.h" #include "swift/SIL/SILModule.h" #include "swift/Serialization/SerializedSILLoader.h" @@ -32,9 +31,6 @@ class SILLinkerVisitor : public SILInstructionVisitor { /// The SILLoader that this visitor is using to link. SerializedSILLoader *Loader; - /// The external SIL source to use when linking this module. - SILExternalSource *ExternalSource = nullptr; - /// Worklist of SILFunctions we are processing. llvm::SmallVector Worklist; @@ -47,10 +43,9 @@ class SILLinkerVisitor : public SILInstructionVisitor { public: SILLinkerVisitor(SILModule &M, SerializedSILLoader *L, - SILModule::LinkingMode LinkingMode, - SILExternalSource *E = nullptr) - : Mod(M), Loader(L), ExternalSource(E), Worklist(), - FunctionDeserializationWorklist(), Mode(LinkingMode) {} + SILModule::LinkingMode LinkingMode) + : Mod(M), Loader(L), Worklist(), FunctionDeserializationWorklist(), + Mode(LinkingMode) {} /// Process F, recursively deserializing any thing F may reference. bool processFunction(SILFunction *F); @@ -76,7 +71,7 @@ class SILLinkerVisitor : public SILInstructionVisitor { bool visitApplyInst(ApplyInst *AI); bool visitPartialApplyInst(PartialApplyInst *PAI); bool visitFunctionRefInst(FunctionRefInst *FRI); - bool visitProtocolConformance(ProtocolConformance *C, + bool visitProtocolConformance(ProtocolConformanceRef C, const Optional &Member); bool visitWitnessMethodInst(WitnessMethodInst *WMI) { return visitProtocolConformance(WMI->getConformance(), WMI->getMember()); diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp index 3f387dd8c6d60..96af2f7ad31c5 100644 --- a/lib/SIL/LoopInfo.cpp +++ b/lib/SIL/LoopInfo.cpp @@ -1,8 +1,8 @@ -//===-------------- LoopInfo.cpp - SIL Loop Analysis -----*- C++ -*--------===// +//===--- LoopInfo.cpp - SIL Loop Analysis ---------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/Mangle.cpp b/lib/SIL/Mangle.cpp index 0a9fdaeca2119..f6c9a1e8e1c5c 100644 --- a/lib/SIL/Mangle.cpp +++ b/lib/SIL/Mangle.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -46,22 +46,20 @@ using namespace Mangle; //===----------------------------------------------------------------------===// static void mangleSubstitution(Mangler &M, Substitution Sub) { - M.mangleType(Sub.getReplacement()->getCanonicalType(), - ResilienceExpansion::Minimal, 0); + M.mangleType(Sub.getReplacement()->getCanonicalType(), 0); for (auto C : Sub.getConformances()) { - if (!C) + if (C.isAbstract()) return; - M.mangleProtocolConformance(C); + M.mangleProtocolConformance(C.getConcrete()); } } void GenericSpecializationMangler::mangleSpecialization() { Mangler &M = getMangler(); - llvm::raw_ostream &Buf = getBuffer(); for (auto &Sub : Subs) { mangleSubstitution(M, Sub); - Buf << '_'; + M.append('_'); } } @@ -136,10 +134,9 @@ setArgumentBoxToStack(unsigned ArgNo) { void FunctionSignatureSpecializationMangler::mangleConstantProp(LiteralInst *LI) { Mangler &M = getMangler(); - llvm::raw_ostream &os = getBuffer(); // Append the prefix for constant propagation 'cp'. - os << "cp"; + M.append("cp"); // Then append the unique identifier of our literal. switch (LI->getKind()) { @@ -147,36 +144,40 @@ FunctionSignatureSpecializationMangler::mangleConstantProp(LiteralInst *LI) { llvm_unreachable("unknown literal"); case ValueKind::FunctionRefInst: { SILFunction *F = cast(LI)->getReferencedFunction(); - os << "fr"; - M.mangleIdentifier(F->getName()); + M.append("fr"); + M.mangleIdentifierSymbol(F->getName()); break; } case ValueKind::GlobalAddrInst: { SILGlobalVariable *G = cast(LI)->getReferencedGlobal(); - os << "g"; - M.mangleIdentifier(G->getName()); + M.append("g"); + M.mangleIdentifierSymbol(G->getName()); break; } case ValueKind::IntegerLiteralInst: { APInt apint = cast(LI)->getValue(); - os << "i" << apint; + M.append("i"); + M.mangleNatural(apint); break; } case ValueKind::FloatLiteralInst: { APInt apint = cast(LI)->getBits(); - os << "fl" << apint; + M.append("fl"); + M.mangleNatural(apint); break; } case ValueKind::StringLiteralInst: { StringLiteralInst *SLI = cast(LI); StringRef V = SLI->getValue(); - assert(V.size() <= 32 && "Can not encode string of length > 32"); + assert(V.size() <= 32 && "Cannot encode string of length > 32"); llvm::SmallString<33> Str; Str += "u"; Str += V; - os << "se" << unsigned(SLI->getEncoding()) << "v"; + M.append("se"); + M.mangleNatural(APInt(32, unsigned(SLI->getEncoding()))); + M.append("v"); M.mangleIdentifier(Str); break; } @@ -187,38 +188,34 @@ void FunctionSignatureSpecializationMangler:: mangleClosureProp(PartialApplyInst *PAI) { Mangler &M = getMangler(); - llvm::raw_ostream &os = getBuffer(); - - os << "cl"; + M.append("cl"); // Add in the partial applies function name if we can find one. Assert // otherwise. The reason why this is ok to do is currently we only perform // closure specialization if we know the function_ref in question. When this // restriction is removed, the assert here will fire. auto *FRI = cast(PAI->getCallee()); - M.mangleIdentifier(FRI->getReferencedFunction()->getName()); + M.mangleIdentifierSymbol(FRI->getReferencedFunction()->getName()); // Then we mangle the types of the arguments that the partial apply is // specializing. for (auto &Op : PAI->getArgumentOperands()) { - SILType Ty = Op.get().getType(); - M.mangleType(Ty.getSwiftRValueType(), ResilienceExpansion::Minimal, 0); + SILType Ty = Op.get()->getType(); + M.mangleType(Ty.getSwiftRValueType(), 0); } } void FunctionSignatureSpecializationMangler::mangleClosureProp( ThinToThickFunctionInst *TTTFI) { Mangler &M = getMangler(); - llvm::raw_ostream &os = getBuffer(); - - os << "cl"; + M.append("cl"); // Add in the partial applies function name if we can find one. Assert // otherwise. The reason why this is ok to do is currently we only perform // closure specialization if we know the function_ref in question. When this // restriction is removed, the assert here will fire. auto *FRI = cast(TTTFI->getCallee()); - M.mangleIdentifier(FRI->getReferencedFunction()->getName()); + M.mangleIdentifierSymbol(FRI->getReferencedFunction()->getName()); } void FunctionSignatureSpecializationMangler::mangleArgument( @@ -239,35 +236,33 @@ void FunctionSignatureSpecializationMangler::mangleArgument( return; } - llvm::raw_ostream &os = getBuffer(); - if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::Unmodified)) { - os << "n"; + M.append("n"); return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToValue)) { - os << "i"; + M.append("i"); return; } if (ArgMod == ArgumentModifierIntBase(ArgumentModifier::BoxToStack)) { - os << "k"; + M.append("k"); return; } bool hasSomeMod = false; if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::Dead)) { - os << "d"; + M.append("d"); hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::OwnedToGuaranteed)) { - os << "g"; + M.append("g"); hasSomeMod = true; } if (ArgMod & ArgumentModifierIntBase(ArgumentModifier::SROA)) { - os << "s"; + M.append("s"); hasSomeMod = true; } @@ -275,13 +270,12 @@ void FunctionSignatureSpecializationMangler::mangleArgument( } void FunctionSignatureSpecializationMangler::mangleSpecialization() { - llvm::raw_ostream &os = getBuffer(); for (unsigned i : indices(Args)) { ArgumentModifierIntBase ArgMod; NullablePtr Inst; std::tie(ArgMod, Inst) = Args[i]; mangleArgument(ArgMod, Inst); - os << "_"; + M.append("_"); } } diff --git a/lib/SIL/PrettyStackTrace.cpp b/lib/SIL/PrettyStackTrace.cpp index 2cc33c0948fd0..6fd027463afad 100644 --- a/lib/SIL/PrettyStackTrace.cpp +++ b/lib/SIL/PrettyStackTrace.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp index 6a64d006edca5..efd66f659951e 100644 --- a/lib/SIL/Projection.cpp +++ b/lib/SIL/Projection.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,6 +14,7 @@ #include "swift/SIL/Projection.h" #include "swift/Basic/NullablePtr.h" #include "swift/SIL/SILBuilder.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/DebugUtils.h" #include "llvm/ADT/None.h" #include "llvm/Support/Debug.h" @@ -34,22 +35,659 @@ static_assert(sizeof(Projection) == ((sizeof(uintptr_t) * 2) "Projection size changed"); //===----------------------------------------------------------------------===// -// Projection +// Utility //===----------------------------------------------------------------------===// -/// Returns true if we are accessing different fields. -static bool areProjectionsToDifferentFields(const Projection &P1, - const Projection &P2) { - // If operands have the same type and we are accessing different fields, - // returns true. Operand's type is not saved in Projection. Instead we check - // Decl's context. - if (!P1.isNominalKind() || !P2.isNominalKind()) +static unsigned getIndexForValueDecl(ValueDecl *Decl) { + NominalTypeDecl *D = cast(Decl->getDeclContext()); + + unsigned i = 0; + for (auto *V : D->getStoredProperties()) { + if (V == Decl) + return i; + ++i; + } + + llvm_unreachable("Failed to find Decl in its decl context?!"); +} + +//===----------------------------------------------------------------------===// +// New Projection +//===----------------------------------------------------------------------===// + +NewProjection::NewProjection(SILInstruction *I) : Value() { + if (!I) + return; + /// Initialize given the specific instruction type and verify with asserts + /// that we constructed it correctly. + switch (I->getKind()) { + // If we do not support this instruction kind, then just bail. Index will + // be None so the Projection will be invalid. + default: + return; + case ValueKind::StructElementAddrInst: { + auto *SEAI = cast(I); + Value = ValueTy(NewProjectionKind::Struct, SEAI->getFieldNo()); + assert(getKind() == NewProjectionKind::Struct); + assert(getIndex() == SEAI->getFieldNo()); + assert(getType(SEAI->getOperand()->getType(), SEAI->getModule()) == + SEAI->getType()); + break; + } + case ValueKind::StructExtractInst: { + auto *SEI = cast(I); + Value = ValueTy(NewProjectionKind::Struct, SEI->getFieldNo()); + assert(getKind() == NewProjectionKind::Struct); + assert(getIndex() == SEI->getFieldNo()); + assert(getType(SEI->getOperand()->getType(), SEI->getModule()) == + SEI->getType()); + break; + } + case ValueKind::RefElementAddrInst: { + auto *REAI = cast(I); + Value = ValueTy(NewProjectionKind::Class, REAI->getFieldNo()); + assert(getKind() == NewProjectionKind::Class); + assert(getIndex() == REAI->getFieldNo()); + assert(getType(REAI->getOperand()->getType(), REAI->getModule()) == + REAI->getType()); + break; + } + case ValueKind::ProjectBoxInst: { + auto *PBI = cast(I); + Value = ValueTy(NewProjectionKind::Box, (unsigned)0); + assert(getKind() == NewProjectionKind::Box); + assert(getIndex() == 0); + assert(getType(PBI->getOperand()->getType(), PBI->getModule()) == + PBI->getType()); + (void) PBI; + break; + } + case ValueKind::TupleExtractInst: { + auto *TEI = cast(I); + Value = ValueTy(NewProjectionKind::Tuple, TEI->getFieldNo()); + assert(getKind() == NewProjectionKind::Tuple); + assert(getIndex() == TEI->getFieldNo()); + assert(getType(TEI->getOperand()->getType(), TEI->getModule()) == + TEI->getType()); + break; + } + case ValueKind::TupleElementAddrInst: { + auto *TEAI = cast(I); + Value = ValueTy(NewProjectionKind::Tuple, TEAI->getFieldNo()); + assert(getKind() == NewProjectionKind::Tuple); + assert(getIndex() == TEAI->getFieldNo()); + assert(getType(TEAI->getOperand()->getType(), TEAI->getModule()) == + TEAI->getType()); + break; + } + case ValueKind::UncheckedEnumDataInst: { + auto *UEDI = cast(I); + Value = ValueTy(NewProjectionKind::Enum, UEDI->getElementNo()); + assert(getKind() == NewProjectionKind::Enum); + assert(getIndex() == UEDI->getElementNo()); + assert(getType(UEDI->getOperand()->getType(), UEDI->getModule()) == + UEDI->getType()); + break; + } + case ValueKind::UncheckedTakeEnumDataAddrInst: { + auto *UTEDAI = cast(I); + Value = ValueTy(NewProjectionKind::Enum, UTEDAI->getElementNo()); + assert(getKind() == NewProjectionKind::Enum); + assert(getIndex() == UTEDAI->getElementNo()); + assert(getType(UTEDAI->getOperand()->getType(), UTEDAI->getModule()) == + UTEDAI->getType()); + break; + } + case ValueKind::IndexAddrInst: { + // We can represent all integers provided here since getIntegerIndex only + // returns 32 bit values. When that changes, this code will need to be + // updated and a MaxLargeIndex will need to be used here. Currently we + // represent large Indexes using a 64 bit integer, so we don't need to mess + // with anything. + unsigned NewIndex = ~0; + auto *IAI = cast(I); + if (getIntegerIndex(IAI->getIndex(), NewIndex)) { + assert(NewIndex != unsigned(~0) && "NewIndex should have been changed " + "by getIntegerIndex?!"); + Value = ValueTy(NewProjectionKind::Index, NewIndex); + assert(getKind() == NewProjectionKind::Index); + assert(getIndex() == NewIndex); + } + break; + } + case ValueKind::UpcastInst: { + auto *Ty = I->getType().getSwiftRValueType().getPointer(); + assert(Ty->isCanonical()); + Value = ValueTy(NewProjectionKind::Upcast, Ty); + assert(getKind() == NewProjectionKind::Upcast); + assert(getType(I->getOperand(0)->getType(), I->getModule()) == + I->getType()); + break; + } + case ValueKind::UncheckedRefCastInst: { + auto *Ty = I->getType().getSwiftRValueType().getPointer(); + assert(Ty->isCanonical()); + Value = ValueTy(NewProjectionKind::RefCast, Ty); + assert(getKind() == NewProjectionKind::RefCast); + assert(getType(I->getOperand(0)->getType(), I->getModule()) == + I->getType()); + break; + } + case ValueKind::UncheckedBitwiseCastInst: + case ValueKind::UncheckedAddrCastInst: { + auto *Ty = I->getType().getSwiftRValueType().getPointer(); + assert(Ty->isCanonical()); + Value = ValueTy(NewProjectionKind::BitwiseCast, Ty); + assert(getKind() == NewProjectionKind::BitwiseCast); + assert(getType(I->getOperand(0)->getType(), I->getModule()) == + I->getType()); + break; + } + } +} + +NullablePtr +NewProjection::createObjectProjection(SILBuilder &B, SILLocation Loc, + SILValue Base) const { + SILType BaseTy = Base->getType(); + + // We can only create a value projection from an object. + if (!BaseTy.isObject()) + return nullptr; + + // Ok, we now know that the type of Base and the type represented by the base + // of this projection match and that this projection can be represented as + // value. Create the instruction if we can. Otherwise, return nullptr. + switch (getKind()) { + case NewProjectionKind::Struct: + return B.createStructExtract(Loc, Base, getVarDecl(BaseTy)); + case NewProjectionKind::Tuple: + return B.createTupleExtract(Loc, Base, getIndex()); + case NewProjectionKind::Index: + return nullptr; + case NewProjectionKind::Enum: + return B.createUncheckedEnumData(Loc, Base, getEnumElementDecl(BaseTy)); + case NewProjectionKind::Class: + return nullptr; + case NewProjectionKind::Box: + return nullptr; + case NewProjectionKind::Upcast: + return B.createUpcast(Loc, Base, getCastType(BaseTy)); + case NewProjectionKind::RefCast: + return B.createUncheckedRefCast(Loc, Base, getCastType(BaseTy)); + case NewProjectionKind::BitwiseCast: + return B.createUncheckedBitwiseCast(Loc, Base, getCastType(BaseTy)); + } +} + +NullablePtr +NewProjection::createAddressProjection(SILBuilder &B, SILLocation Loc, + SILValue Base) const { + SILType BaseTy = Base->getType(); + + // We can only create an address projection from an object, unless we have a + // class. + if (BaseTy.getClassOrBoundGenericClass() || !BaseTy.isAddress()) + return nullptr; + + // Ok, we now know that the type of Base and the type represented by the base + // of this projection match and that this projection can be represented as + // value. Create the instruction if we can. Otherwise, return nullptr. + switch (getKind()) { + case NewProjectionKind::Struct: + return B.createStructElementAddr(Loc, Base, getVarDecl(BaseTy)); + case NewProjectionKind::Tuple: + return B.createTupleElementAddr(Loc, Base, getIndex()); + case NewProjectionKind::Index: { + auto IntLiteralTy = + SILType::getBuiltinIntegerType(64, B.getModule().getASTContext()); + auto IntLiteralIndex = + B.createIntegerLiteral(Loc, IntLiteralTy, getIndex()); + return B.createIndexAddr(Loc, Base, IntLiteralIndex); + } + case NewProjectionKind::Enum: + return B.createUncheckedTakeEnumDataAddr(Loc, Base, + getEnumElementDecl(BaseTy)); + case NewProjectionKind::Class: + return B.createRefElementAddr(Loc, Base, getVarDecl(BaseTy)); + case NewProjectionKind::Box: + return B.createProjectBox(Loc, Base); + case NewProjectionKind::Upcast: + return B.createUpcast(Loc, Base, getCastType(BaseTy)); + case NewProjectionKind::RefCast: + case NewProjectionKind::BitwiseCast: + return B.createUncheckedAddrCast(Loc, Base, getCastType(BaseTy)); + } +} + +void NewProjection::getFirstLevelProjections( + SILType Ty, SILModule &Mod, llvm::SmallVectorImpl &Out) { + if (auto *S = Ty.getStructOrBoundGenericStruct()) { + unsigned Count = 0; + for (auto *VDecl : S->getStoredProperties()) { + (void) VDecl; + NewProjection P(NewProjectionKind::Struct, Count++); + DEBUG(NewProjectionPath X(Ty); + assert(X.getMostDerivedType(Mod) == Ty); + X.append(P); + assert(X.getMostDerivedType(Mod) == Ty.getFieldType(VDecl, Mod)); + X.verify(Mod);); + Out.push_back(P); + } + return; + } + + if (auto TT = Ty.getAs()) { + for (unsigned i = 0, e = TT->getNumElements(); i != e; ++i) { + NewProjection P(NewProjectionKind::Tuple, i); + DEBUG(NewProjectionPath X(Ty); + assert(X.getMostDerivedType(Mod) == Ty); + X.append(P); + assert(X.getMostDerivedType(Mod) == Ty.getTupleElementType(i)); + X.verify(Mod);); + Out.push_back(P); + } + return; + } + + if (auto *C = Ty.getClassOrBoundGenericClass()) { + unsigned Count = 0; + for (auto *VDecl : C->getStoredProperties()) { + (void) VDecl; + NewProjection P(NewProjectionKind::Class, Count++); + DEBUG(NewProjectionPath X(Ty); + assert(X.getMostDerivedType(Mod) == Ty); + X.append(P); + assert(X.getMostDerivedType(Mod) == Ty.getFieldType(VDecl, Mod)); + X.verify(Mod);); + Out.push_back(P); + } + return; + } + + if (auto Box = Ty.getAs()) { + NewProjection P(NewProjectionKind::Box, (unsigned)0); + DEBUG(NewProjectionPath X(Ty); + assert(X.getMostDerivedType(Mod) == Ty); + X.append(P); + assert(X.getMostDerivedType(Mod) == SILType::getPrimitiveAddressType( + Box->getBoxedType())); + X.verify(Mod);); + (void) Box; + Out.push_back(P); + return; + } +} + +//===----------------------------------------------------------------------===// +// New Projection Path +//===----------------------------------------------------------------------===// + +Optional NewProjectionPath::getProjectionPath(SILValue Start, + SILValue End) { + NewProjectionPath P(Start->getType(), End->getType()); + + // If Start == End, there is a "trivial" projection path in between the + // two. This is represented by returning an empty ProjectionPath. + if (Start == End) + return std::move(P); + + // Do not inspect the body of types with unreferenced types such as bitfields + // and unions. This is currently only associated with structs. + if (Start->getType().aggregateHasUnreferenceableStorage() || + End->getType().aggregateHasUnreferenceableStorage()) + return llvm::NoneType::None; + + auto Iter = End; + while (Start != Iter) { + NewProjection AP(Iter); + if (!AP.isValid()) + break; + P.Path.push_back(AP); + Iter = cast(*Iter).getOperand(0); + } + + // Return None if we have an empty projection list or if Start == Iter. + // We do not worry about th implicit #0 in case of index_addr, as the + // NewProjectionPath never allow paths to be compared as a list of indices. + // Only the encoded type+index pair will be compared. + if (P.empty() || Start != Iter) + return llvm::NoneType::None; + + // Reverse to get a path from base to most-derived. + std::reverse(P.Path.begin(), P.Path.end()); + + // Otherwise, return P. + return std::move(P); +} + +/// Returns true if the two paths have a non-empty symmetric difference. +/// +/// This means that the two objects have the same base but access different +/// fields of the base object. +bool NewProjectionPath::hasNonEmptySymmetricDifference( + const NewProjectionPath &RHS) const { + // First make sure that both of our base types are the same. + if (BaseType != RHS.BaseType) return false; - return P1.getDecl()->getDeclContext() == P2.getDecl()->getDeclContext() && - P1 != P2; + // We assume that the two paths must be non-empty. + // + // I believe that we assume this since in the code that uses this we check for + // full differences before we use this code path. + // + // TODO: Is this necessary. + if (empty() || RHS.empty()) + return false; + + // Otherwise, we have a common base and perhaps some common subpath. + auto LHSIter = Path.begin(); + auto RHSIter = RHS.Path.begin(); + + bool FoundDifferingProjections = false; + + // For each index i until min path size... + unsigned i = 0; + for (unsigned e = std::min(size(), RHS.size()); i != e; ++i) { + // Grab the current projections. + const NewProjection &LHSProj = *LHSIter; + const NewProjection &RHSProj = *RHSIter; + + // If we are accessing different fields of a common object, the two + // projection paths may have a non-empty symmetric difference. We check if + if (LHSProj != RHSProj) { + DEBUG(llvm::dbgs() << " Path different at index: " << i << '\n'); + FoundDifferingProjections = true; + break; + } + + // Continue if we are accessing the same field. + LHSIter++; + RHSIter++; + } + + // All path elements are the same. The symmetric difference is empty. + if (!FoundDifferingProjections) + return false; + + // We found differing projections, but we need to make sure that there are no + // casts in the symmetric difference. To be conservative, we only wish to + // allow for casts to appear in the common parts of projections. + for (unsigned li = i, e = size(); li != e; ++li) { + if (LHSIter->isAliasingCast()) + return false; + LHSIter++; + } + for (unsigned ri = i, e = RHS.size(); ri != e; ++ri) { + if (RHSIter->isAliasingCast()) + return false; + RHSIter++; + } + + // If we don't have any casts in our symmetric difference (i.e. only typed + // GEPs), then we can say that these actually have a symmetric difference we + // can understand. The fundamental issue here is that since we do not have any + // notion of size, we cannot know the effect of a cast + gep on the final + // location that we are reaching. + return true; } +/// TODO: Integrate has empty non-symmetric difference into here. +SubSeqRelation_t +NewProjectionPath::computeSubSeqRelation(const NewProjectionPath &RHS) const { + // Make sure that both base types are the same. Otherwise, we can not compare + // the projections as sequences. + if (BaseType != RHS.BaseType) + return SubSeqRelation_t::Unknown; + + // If either path is empty, we can not prove anything, return Unknown. + if (empty() || RHS.empty()) + return SubSeqRelation_t::Unknown; + + auto LHSIter = begin(); + auto RHSIter = RHS.begin(); + + unsigned MinPathSize = std::min(size(), RHS.size()); + + // For each index i until min path size... + for (unsigned i = 0; i != MinPathSize; ++i) { + // Grab the current projections. + const NewProjection &LHSProj = *LHSIter; + const NewProjection &RHSProj = *RHSIter; + + // If the two projections do not equal exactly, return Unrelated. + // + // TODO: If Index equals zero, then we know that the two lists have nothing + // in common and should return unrelated. If Index is greater than zero, + // then we know that the two projection paths have a common base but a + // non-empty symmetric difference. For now we just return Unrelated since I + // can not remember why I had the special check in the + // hasNonEmptySymmetricDifference code. + if (LHSProj != RHSProj) + return SubSeqRelation_t::Unknown; + + // Otherwise increment reverse iterators. + LHSIter++; + RHSIter++; + } + + // Ok, we now know that one of the paths is a subsequence of the other. If + // both size() and RHS.size() equal then we know that the entire sequences + // equal. + if (size() == RHS.size()) + return SubSeqRelation_t::Equal; + + // If MinPathSize == size(), then we know that LHS is a strict subsequence of + // RHS. + if (MinPathSize == size()) + return SubSeqRelation_t::LHSStrictSubSeqOfRHS; + + // Otherwise, we know that MinPathSize must be RHS.size() and RHS must be a + // strict subsequence of LHS. Assert to check this and return. + assert(MinPathSize == RHS.size() && + "Since LHS and RHS don't equal and size() != MinPathSize, RHS.size() " + "must equal MinPathSize"); + return SubSeqRelation_t::RHSStrictSubSeqOfLHS; +} + +bool NewProjectionPath::findMatchingObjectProjectionPaths( + SILInstruction *I, SmallVectorImpl &T) const { + // We only support unary instructions. + if (I->getNumOperands() != 1) + return false; + + // Check that the base result type of I is equivalent to this types base path. + if (I->getOperand(0)->getType().copyCategory(BaseType) != BaseType) + return false; + + // We maintain the head of our worklist so we can use our worklist as a queue + // and work in breadth first order. This makes sense since we want to process + // in levels so we can maintain one tail list and delete the tail list when we + // move to the next level. + unsigned WorkListHead = 0; + llvm::SmallVector WorkList; + WorkList.push_back(I); + + // Start at the root of the list. + for (auto PI = rbegin(), PE = rend(); PI != PE; ++PI) { + // When we start a new level, clear the tail list. + T.clear(); + + // If we have an empty worklist, return false. We have been unable to + // complete the list. + unsigned WorkListSize = WorkList.size(); + if (WorkListHead == WorkListSize) + return false; + + // Otherwise, process each instruction in the worklist. + for (; WorkListHead != WorkListSize; WorkListHead++) { + SILInstruction *Ext = WorkList[WorkListHead]; + + // If the current projection does not match I, continue and process the + // next instruction. + if (!PI->matchesObjectProjection(Ext)) { + continue; + } + + // Otherwise, we know that Ext matched this projection path and we should + // visit all of its uses and add Ext itself to our tail list. + T.push_back(Ext); + for (auto *Op : Ext->getUses()) { + WorkList.push_back(Op->getUser()); + } + } + + // Reset the worklist size. + WorkListSize = WorkList.size(); + } + + return true; +} + +Optional +NewProjectionPath::removePrefix(const NewProjectionPath &Path, + const NewProjectionPath &Prefix) { + // We can only subtract paths that have the same base. + if (Path.BaseType != Prefix.BaseType) + return llvm::NoneType::None; + + // If Prefix is greater than or equal to Path in size, Prefix can not be a + // prefix of Path. Return None. + unsigned PrefixSize = Prefix.size(); + unsigned PathSize = Path.size(); + + if (PrefixSize >= PathSize) + return llvm::NoneType::None; + + // First make sure that the prefix matches. + Optional P = NewProjectionPath(Path.BaseType); + for (unsigned i = 0; i < PrefixSize; i++) { + if (Path.Path[i] != Prefix.Path[i]) { + P.reset(); + return P; + } + } + + // Add the rest of Path to P and return P. + for (unsigned i = PrefixSize, e = PathSize; i != e; ++i) { + P->Path.push_back(Path.Path[i]); + } + + return P; +} + +SILValue NewProjectionPath::createObjectProjections(SILBuilder &B, + SILLocation Loc, + SILValue Base) { + assert(BaseType.isAddress()); + assert(Base->getType().isObject()); + assert(Base->getType().getAddressType() == BaseType); + SILValue Val = Base; + for (auto iter : Path) { + Val = iter.createObjectProjection(B, Loc, Val).get(); + } + return Val; +} + +raw_ostream &NewProjectionPath::print(raw_ostream &os, SILModule &M) { + // Match how the memlocation print tests expect us to print projection paths. + // + // TODO: It sort of sucks having to print these bottom up computationally. We + // should really change the test so that prints out the path elements top + // down the path, rather than constructing all of these intermediate paths. + for (unsigned i : reversed(indices(Path))) { + SILType IterType = getDerivedType(i, M); + auto &IterProj = Path[i]; + os << "Address Projection Type: "; + if (IterProj.isNominalKind()) { + auto *Decl = IterProj.getVarDecl(IterType); + IterType = IterProj.getType(IterType, M); + os << IterType.getAddressType() << "\n"; + os << "Field Type: "; + Decl->print(os); + os << "\n"; + continue; + } + + if (IterProj.getKind() == NewProjectionKind::Tuple) { + IterType = IterProj.getType(IterType, M); + os << IterType.getAddressType() << "\n"; + os << "Index: "; + os << IterProj.getIndex() << "\n"; + continue; + } + + if (IterProj.getKind() == NewProjectionKind::Box) { + os << "Box: "; + continue; + } + + llvm_unreachable("Can not print this projection kind"); + } + +// Migrate the tests to this format eventually. +#if 0 + os << "(Projection Path ["; + SILType NextType = BaseType; + os << NextType; + for (const NewProjection &P : Path) { + os << ", "; + NextType = P.getType(NextType, M); + os << NextType; + } + os << "]"; +#endif + return os; +} + +raw_ostream &NewProjectionPath::printProjections(raw_ostream &os, SILModule &M) const { + // Match how the memlocation print tests expect us to print projection paths. + // + // TODO: It sort of sucks having to print these bottom up computationally. We + // should really change the test so that prints out the path elements top + // down the path, rather than constructing all of these intermediate paths. + for (unsigned i : reversed(indices(Path))) { + auto &IterProj = Path[i]; + if (IterProj.isNominalKind()) { + os << "Field Type: " << IterProj.getIndex() << "\n"; + continue; + } + + if (IterProj.getKind() == NewProjectionKind::Tuple) { + os << "Index: " << IterProj.getIndex() << "\n"; + continue; + } + + llvm_unreachable("Can not print this projection kind"); + } + + return os; +} + +void NewProjectionPath::dump(SILModule &M) { + print(llvm::outs(), M); + llvm::outs() << "\n"; +} + +void NewProjectionPath::dumpProjections(SILModule &M) const { + printProjections(llvm::outs(), M); +} + +void NewProjectionPath::verify(SILModule &M) { +#ifndef NDEBUG + SILType IterTy = getBaseType(); + assert(IterTy); + for (auto &Proj : Path) { + IterTy = Proj.getType(IterTy, M); + assert(IterTy); + } +#endif +} + +//===----------------------------------------------------------------------===// +// Projection +//===----------------------------------------------------------------------===// + bool Projection::matchesValueProjection(SILInstruction *I) const { llvm::Optional P = Projection::valueProjectionForInstruction(I); if (!P) @@ -90,6 +728,9 @@ Projection::addressProjectionForInstruction(SILInstruction *I) { case ValueKind::RefElementAddrInst: assert(isAddrProjection(I) && "isAddrProjection out of sync"); return Projection(cast(I)); + case ValueKind::ProjectBoxInst: + assert(isAddrProjection(I) && "isAddrProjection out of sync"); + return Projection(cast(I)); case ValueKind::UncheckedTakeEnumDataAddrInst: assert(isAddrProjection(I) && "isAddrProjection out of sync"); return Projection(cast(I)); @@ -139,19 +780,6 @@ Projection::operator<(Projection Other) const { } } -static unsigned getIndexForValueDecl(ValueDecl *Decl) { - NominalTypeDecl *D = cast(Decl->getDeclContext()); - - unsigned i = 0; - for (auto *V : D->getStoredProperties()) { - if (V == Decl) - return i; - ++i; - } - - llvm_unreachable("Failed to find Decl in its decl context?!"); -} - /// We do not support symbolic projections yet, only 32-bit unsigned integers. bool swift::getIntegerIndex(SILValue IndexVal, unsigned &IndexConst) { if (auto *IndexLiteral = dyn_cast(IndexVal)) { @@ -187,6 +815,11 @@ Projection::Projection(RefElementAddrInst *REA) Index(getIndexForValueDecl(Decl)), Kind(unsigned(ProjectionKind::Class)) { } +Projection::Projection(ProjectBoxInst *PBI) + : Type(PBI->getType()), Decl(nullptr), + Index(0), Kind(unsigned(ProjectionKind::Box)) { +} + /// UncheckedTakeEnumDataAddrInst always have an index of 0 since enums only /// have one payload. Projection::Projection(UncheckedTakeEnumDataAddrInst *UTEDAI) @@ -212,22 +845,12 @@ NullablePtr Projection:: createValueProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const { // Grab Base's type. - SILType BaseTy = Base.getType(); + SILType BaseTy = Base->getType(); // If BaseTy is not an object type, bail. if (!BaseTy.isObject()) return nullptr; - // If this projection is associated with an address type, convert its type to - // an object type. - // - // We explicitly do not convert Type to be an object if it is a local storage - // type since we want it to fail. - SILType Ty = Type.isAddress()? Type.getObjectType() : Type; - - if (!Ty.isObject()) - return nullptr; - // Ok, we now know that the type of Base and the type represented by the base // of this projection match and that this projection can be represented as // value. Create the instruction if we can. Otherwise, return nullptr. @@ -243,6 +866,8 @@ createValueProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const { cast(getDecl())); case ProjectionKind::Class: return nullptr; + case ProjectionKind::Box: + return nullptr; } } @@ -250,23 +875,12 @@ NullablePtr Projection:: createAddrProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const { // Grab Base's type. - SILType BaseTy = Base.getType(); + SILType BaseTy = Base->getType(); // If BaseTy is not an address type, bail. if (!BaseTy.isAddress()) return nullptr; - // If this projection is associated with an object type, convert its type to - // an address type. - // - // *NOTE* We purposely do not handle local storage types here since we want to - // always fail in such a case. That is handled by checking that Ty is an - // address. - SILType Ty = Type.isObject()? Type.getAddressType() : Type; - - if (!Ty.isAddress()) - return nullptr; - // Ok, we now know that the type of Base and the type represented by the base // of this projection match and that this projection can be represented as // value. Create the instruction if we can. Otherwise, return nullptr. @@ -285,6 +899,8 @@ createAddrProjection(SILBuilder &B, SILLocation Loc, SILValue Base) const { cast(getDecl())); case ProjectionKind::Class: return B.createRefElementAddr(Loc, Base, cast(getDecl())); + case ProjectionKind::Box: + return B.createProjectBox(Loc, Base); } } @@ -309,7 +925,9 @@ SILValue Projection::getOperandForAggregate(SILInstruction *I) const { } break; case ProjectionKind::Class: - // There is no SIL instruction to create a class by aggregating values. + case ProjectionKind::Box: + // There is no SIL instruction to create a class or box by aggregating + // values. break; } return SILValue(); @@ -343,6 +961,13 @@ void Projection::getFirstLevelAddrProjections( } return; } + + if (auto Box = Ty.getAs()) { + Out.push_back(Projection(ProjectionKind::Box, + SILType::getPrimitiveAddressType(Box->getBoxedType()), + nullptr, 0)); + return; + } } void Projection::getFirstLevelProjections( @@ -370,11 +995,18 @@ void Projection::getFirstLevelProjections( } return; } + + if (auto Box = Ty.getAs()) { + Out.push_back(Projection(ProjectionKind::Box, + SILType::getPrimitiveObjectType(Box->getBoxedType()), + nullptr, 0)); + return; + } } void Projection::getFirstLevelProjections( SILValue V, SILModule &Mod, llvm::SmallVectorImpl &Out) { - getFirstLevelProjections(V.getType(), Mod, Out); + getFirstLevelProjections(V->getType(), Mod, Out); } NullablePtr @@ -397,13 +1029,24 @@ createAggFromFirstLevelProjections(SILBuilder &B, SILLocation Loc, // Projection Path //===----------------------------------------------------------------------===// +static bool areProjectionsToDifferentFields(const Projection &P1, + const Projection &P2) { + // If operands have the same type and we are accessing different fields, + // returns true. Operand's type is not saved in Projection. Instead we check + // Decl's context. + if (!P1.isNominalKind() || !P2.isNominalKind()) + return false; + return P1.getDecl()->getDeclContext() == P2.getDecl()->getDeclContext() && + P1 != P2; +} + Optional ProjectionPath::getAddrProjectionPath(SILValue Start, SILValue End, bool IgnoreCasts) { // Do not inspect the body of structs with unreferenced types such as // bitfields and unions. - if (Start.getType().aggregateHasUnreferenceableStorage() || - End.getType().aggregateHasUnreferenceableStorage()) { + if (Start->getType().aggregateHasUnreferenceableStorage() || + End->getType().aggregateHasUnreferenceableStorage()) { return llvm::NoneType::None; } @@ -418,7 +1061,7 @@ ProjectionPath::getAddrProjectionPath(SILValue Start, SILValue End, // End is a projection at all. auto Iter = End; if (IgnoreCasts) - Iter = Iter.stripCasts(); + Iter = stripCasts(Iter); bool NextAddrIsIndex = false; while (Projection::isAddrProjection(Iter) && Start != Iter) { Projection AP = *Projection::addressProjectionForValue(Iter); @@ -427,7 +1070,7 @@ ProjectionPath::getAddrProjectionPath(SILValue Start, SILValue End, Iter = cast(*Iter).getOperand(0); if (IgnoreCasts) - Iter = Iter.stripCasts(); + Iter = stripCasts(Iter); } // Return None if we have an empty projection list or if Start == Iter. @@ -488,21 +1131,21 @@ hasNonEmptySymmetricDifference(const ProjectionPath &RHS) const { SubSeqRelation_t ProjectionPath:: computeSubSeqRelation(const ProjectionPath &RHS) const { - // If either path is empty, we can not prove anything, return Unrelated. + // If either path is empty, we cannot prove anything, return Unrelated. if (empty() || RHS.empty()) return SubSeqRelation_t::Unknown; // We reverse the projection path to scan from the common object. - auto LHSReverseIter = rbegin(); - auto RHSReverseIter = RHS.rbegin(); + auto LHSIter = begin(); + auto RHSIter = RHS.begin(); unsigned MinPathSize = std::min(size(), RHS.size()); // For each index i until min path size... for (unsigned i = 0; i != MinPathSize; ++i) { // Grab the current projections. - const Projection &LHSProj = *LHSReverseIter; - const Projection &RHSProj = *RHSReverseIter; + const Projection &LHSProj = *LHSIter; + const Projection &RHSProj = *RHSIter; // If the two projections do not equal exactly, return Unrelated. // @@ -510,14 +1153,14 @@ computeSubSeqRelation(const ProjectionPath &RHS) const { // in common and should return unrelated. If Index is greater than zero, // then we know that the two projection paths have a common base but a // non-empty symmetric difference. For now we just return Unrelated since I - // can not remember why I had the special check in the + // cannot remember why I had the special check in the // hasNonEmptySymmetricDifference code. if (LHSProj != RHSProj) return SubSeqRelation_t::Unknown; // Otherwise increment reverse iterators. - LHSReverseIter++; - RHSReverseIter++; + LHSIter++; + RHSIter++; } // Ok, we now know that one of the paths is a subsequence of the other. If @@ -588,7 +1231,7 @@ findMatchingValueProjectionPaths(SILInstruction *I, Optional ProjectionPath::subtractPaths(const ProjectionPath &LHS, const ProjectionPath &RHS) { - // If RHS is greater than or equal to LHS in size, RHS can not be a prefix of + // If RHS is greater than or equal to LHS in size, RHS cannot be a prefix of // LHS. Return None. unsigned RHSSize = RHS.size(); unsigned LHSSize = LHS.size(); @@ -612,6 +1255,143 @@ ProjectionPath::subtractPaths(const ProjectionPath &LHS, const ProjectionPath &R return P; } +void +NewProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, + NewProjectionPathList &Paths) { + // Perform a BFS to expand the given type into projectionpath each of + // which contains 1 field from the type. + llvm::SmallVector Worklist; + llvm::SmallVector Projections; + + // Push an empty projection path to get started. + NewProjectionPath P(B); + Worklist.push_back(P); + do { + // Get the next level projections based on current projection's type. + NewProjectionPath PP = Worklist.pop_back_val(); + // Get the current type to process. + SILType Ty = PP.getMostDerivedType(*Mod); + + DEBUG(llvm::dbgs() << "Visiting type: " << Ty << "\n"); + + // Get the first level projection of the current type. + Projections.clear(); + NewProjection::getFirstLevelProjections(Ty, *Mod, Projections); + + // Reached the end of the projection tree, this field can not be expanded + // anymore. + if (Projections.empty()) { + DEBUG(llvm::dbgs() << " No projections. Finished projection list\n"); + Paths.push_back(PP); + continue; + } + + // If this is a class type, we also have reached the end of the type + // tree for this type. + // + // We do not push its next level projection into the worklist, + // if we do that, we could run into an infinite loop, e.g. + // + // class SelfLoop { + // var p : SelfLoop + // } + // + // struct XYZ { + // var x : Int + // var y : SelfLoop + // } + // + // The worklist would never be empty in this case !. + // + if (Ty.getClassOrBoundGenericClass()) { + DEBUG(llvm::dbgs() << " Found class. Finished projection list\n"); + Paths.push_back(PP); + continue; + } + + // Keep expanding the location. + for (auto &P : Projections) { + NewProjectionPath X(B); + X.append(PP); + ///assert(PP.getMostDerivedType(*Mod) == X.getMostDerivedType(*Mod)); + X.append(P); + Worklist.push_back(X); + } + // Keep iterating if the worklist is not empty. + } while (!Worklist.empty()); +} + +void +NewProjectionPath::expandTypeIntoNodeProjectionPaths(SILType B, SILModule *Mod, + NewProjectionPathList &Paths) { + // Perform a BFS to expand the given type into projectionpath each of + // which contains 1 field from the type. + llvm::SmallVector Worklist; + llvm::SmallVector Projections; + + // Push an empty projection path to get started. + NewProjectionPath P(B); + Worklist.push_back(P); + do { + // Get the next level projections based on current projection's type. + NewProjectionPath PP = Worklist.pop_back_val(); + // Get the current type to process. + SILType Ty = PP.getMostDerivedType(*Mod); + + DEBUG(llvm::dbgs() << "Visiting type: " << Ty << "\n"); + + // Get the first level projection of the current type. + Projections.clear(); + NewProjection::getFirstLevelProjections(Ty, *Mod, Projections); + + // Reached the end of the projection tree, this field can not be expanded + // anymore. + if (Projections.empty()) { + DEBUG(llvm::dbgs() << " No projections. Finished projection list\n"); + Paths.push_back(PP); + continue; + } + + // If this is a class type, we also have reached the end of the type + // tree for this type. + // + // We do not push its next level projection into the worklist, + // if we do that, we could run into an infinite loop, e.g. + // + // class SelfLoop { + // var p : SelfLoop + // } + // + // struct XYZ { + // var x : Int + // var y : SelfLoop + // } + // + // The worklist would never be empty in this case !. + // + if (Ty.getClassOrBoundGenericClass()) { + DEBUG(llvm::dbgs() << " Found class. Finished projection list\n"); + Paths.push_back(PP); + continue; + } + + // This is NOT a leaf node, keep the intermediate nodes as well. + DEBUG(llvm::dbgs() << " Found class. Finished projection list\n"); + Paths.push_back(PP); + + // Keep expanding the location. + for (auto &P : Projections) { + NewProjectionPath X(B); + X.append(PP); + assert(PP.getMostDerivedType(*Mod) == X.getMostDerivedType(*Mod)); + X.append(P); + Worklist.push_back(X); + } + + // Keep iterating if the worklist is not empty. + } while (!Worklist.empty()); +} + void ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, ProjectionPathList &Paths) { @@ -636,7 +1416,7 @@ ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, Projections.clear(); Projection::getFirstLevelAddrProjections(Ty, *Mod, Projections); - // Reached the end of the projection tree, this field can not be expanded + // Reached the end of the projection tree, this field cannot be expanded // anymore. if (Projections.empty()) { Paths.push_back(std::move(PP.getValue())); @@ -700,7 +1480,7 @@ ProjectionPath::expandTypeIntoNodeProjectionPaths(SILType B, SILModule *Mod, Projections.clear(); Projection::getFirstLevelAddrProjections(Ty, *Mod, Projections); - // Reached the end of the projection tree, this field can not be expanded + // Reached the end of the projection tree, this field cannot be expanded // anymore. if (Projections.empty()) { Paths.push_back(std::move(PP.getValue())); @@ -729,8 +1509,16 @@ ProjectionPath::expandTypeIntoNodeProjectionPaths(SILType B, SILModule *Mod, continue; } - // Keep the intermediate nodes as well. - Paths.push_back(std::move(PP.getValue())); + // Keep the intermediate nodes as well. + // + // std::move clears the passed ProjectionPath. Give it a temporarily + // created ProjectionPath for now. + // + // TODO: this can be simplified once we reduce the size of the projection + // path and make them copyable. + ProjectionPath T; + T.append(PP.getValue()); + Paths.push_back(std::move(T)); // Keep expanding the location. for (auto &P : Projections) { @@ -814,9 +1602,9 @@ processUsersOfValue(ProjectionTree &Tree, DEBUG(llvm::dbgs() << " Created projection.\n"); - assert(User->getNumTypes() == 1 && "Projections should only have one use"); + assert(User->hasValue() && "Projections should have a value"); - // Look up the Node for this projection add add {User, ChildNode} to the + // Look up the Node for this projection add {User, ChildNode} to the // worklist. // // *NOTE* This means that we will process ChildNode multiple times @@ -832,7 +1620,7 @@ processUsersOfValue(ProjectionTree &Tree, "Adding to non projection user!\b"); // The only projection which we do not currently handle are enums since we - // may not know the correct case. This can be xtended in the future. + // may not know the correct case. This can be extended in the future. addNonProjectionUser(Op); } } @@ -1072,7 +1860,7 @@ createTreeFromValue(SILBuilder &B, SILLocation Loc, SILValue NewBase, SILValue V = std::get<1>(Worklist.back()); Worklist.pop_back(); - DEBUG(llvm::dbgs() << "Visiting: " << V.getType() << ": " << V); + DEBUG(llvm::dbgs() << "Visiting: " << V->getType() << ": " << V); // If we have any children... unsigned NumChildren = Node->ChildProjections.size(); @@ -1084,7 +1872,7 @@ createTreeFromValue(SILBuilder &B, SILLocation Loc, SILValue NewBase, for (unsigned ChildIdx : reversed(Node->ChildProjections)) { const ProjectionTreeNode *ChildNode = getNode(ChildIdx); SILInstruction *I = ChildNode->createProjection(B, Loc, V).get(); - DEBUG(llvm::dbgs() << " Adding Child: " << I->getType(0) << ": " << *I); + DEBUG(llvm::dbgs() << " Adding Child: " << I->getType() << ": " << *I); Worklist.push_back(std::make_tuple(ChildNode, SILValue(I))); } } else { @@ -1128,12 +1916,12 @@ class ProjectionTreeNode::AggregateBuilder { /// If all SILValues have been set, we are complete. bool isComplete() const { return std::all_of(Values.begin(), Values.end(), [](SILValue V) -> bool { - return V.getDef(); + return V; }); } SILInstruction *createInstruction() const { - assert(isComplete() && "Can not create instruction until the aggregate is " + assert(isComplete() && "Cannot create instruction until the aggregate is " "complete"); assert(!Invalidated && "Must not be invalidated to create an instruction"); const_cast(this)->Invalidated = true; diff --git a/lib/SIL/SIL.cpp b/lib/SIL/SIL.cpp index 0439805386c58..56f6f50d72bf6 100644 --- a/lib/SIL/SIL.cpp +++ b/lib/SIL/SIL.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,13 +31,9 @@ using namespace swift; void ValueBase::replaceAllUsesWith(ValueBase *RHS) { assert(this != RHS && "Cannot RAUW a value with itself"); - assert(getNumTypes() == RHS->getNumTypes() && - "An instruction and the value base that it is being replaced by " - "must have the same number of types"); - while (!use_empty()) { Operand *Op = *use_begin(); - Op->set(SILValue(RHS, Op->get().getResultNumber())); + Op->set(RHS); } } @@ -50,18 +46,6 @@ SILUndef *SILUndef::get(SILType Ty, SILModule *M) { return Entry; } -static FormalLinkage -getGenericClauseLinkage(ArrayRef params) { - FormalLinkage result = FormalLinkage::Top; - for (auto ¶m : params) { - for (auto proto : param->getConformingProtocols(nullptr)) - result ^= getTypeLinkage(CanType(proto->getDeclaredType())); - if (auto superclass = param->getSuperclass()) - result ^= getTypeLinkage(superclass->getCanonicalType()); - } - return result; -} - FormalLinkage swift::getDeclLinkage(const ValueDecl *D) { const DeclContext *fileContext = D->getDeclContext()->getModuleScopeContext(); @@ -98,15 +82,11 @@ FormalLinkage swift::getTypeLinkage(CanType type) { CanType type = CanType(_type); // For any nominal type reference, look at the type declaration. - if (auto nominal = type->getAnyNominal()) { + if (auto nominal = type->getAnyNominal()) result ^= getDeclLinkage(nominal); - // For polymorphic function types, look at the generic parameters. - // FIXME: findIf should do this, once polymorphic function types can be - // canonicalized and re-formed properly. - } else if (auto polyFn = dyn_cast(type)) { - result ^= getGenericClauseLinkage(polyFn->getGenericParameters()); - } + assert(!isa(type) && + "Don't expect a polymorphic function type here"); return false; // continue searching }); diff --git a/lib/SIL/SILArgument.cpp b/lib/SIL/SILArgument.cpp index 4c88c8b81b4e3..3dc38a86a0290 100644 --- a/lib/SIL/SILArgument.cpp +++ b/lib/SIL/SILArgument.cpp @@ -1,8 +1,8 @@ -//===--- SILArgument.cpp - Arguments for high-level SIL code ---------------==// +//===--- SILArgument.cpp - Arguments for high-level SIL code --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,6 +60,43 @@ SILModule &SILArgument::getModule() const { return getFunction()->getModule(); } +static SILValue getIncomingValueForPred(const SILBasicBlock *BB, + const SILBasicBlock *Pred, + unsigned Index) { + const TermInst *TI = Pred->getTerminator(); + + switch (TI->getTermKind()) { + // TODO: This list is conservative. I think we can probably handle more of + // these. + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::CheckedCastAddrBranchInst: + case TermKind::DynamicMethodBranchInst: + return SILValue(); + case TermKind::BranchInst: + return cast(TI)->getArg(Index); + case TermKind::CondBranchInst: + return cast(TI)->getArgForDestBB(BB, Index); + case TermKind::CheckedCastBranchInst: + return cast(TI)->getOperand(); + case TermKind::SwitchEnumInst: + return cast(TI)->getOperand(); + } + llvm_unreachable("Unhandled TermKind?!"); +} + +SILValue SILArgument::getSingleIncomingValue() const { + const SILBasicBlock *Parent = getParent(); + const SILBasicBlock *PredBB = Parent->getSinglePredecessor(); + if (!PredBB) + return SILValue(); + return getIncomingValueForPred(Parent, PredBB, getIndex()); +} + bool SILArgument::getIncomingValues(llvm::SmallVectorImpl &OutArray) { SILBasicBlock *Parent = getParent(); @@ -68,29 +105,10 @@ bool SILArgument::getIncomingValues(llvm::SmallVectorImpl &OutArray) { unsigned Index = getIndex(); for (SILBasicBlock *Pred : getParent()->getPreds()) { - TermInst *TI = Pred->getTerminator(); - - if (auto *BI = dyn_cast(TI)) { - OutArray.push_back(BI->getArg(Index)); - continue; - } - - if (auto *CBI = dyn_cast(TI)) { - OutArray.push_back(CBI->getArgForDestBB(getParent(), this)); - continue; - } - - if (auto *CCBI = dyn_cast(TI)) { - OutArray.push_back(CCBI->getOperand()); - continue; - } - - if (auto *SWEI = dyn_cast(TI)) { - OutArray.push_back(SWEI->getOperand()); - continue; - } - - return false; + SILValue Value = getIncomingValueForPred(Parent, Pred, Index); + if (!Value) + return false; + OutArray.push_back(Value); } return true; @@ -105,29 +123,10 @@ bool SILArgument::getIncomingValues( unsigned Index = getIndex(); for (SILBasicBlock *Pred : getParent()->getPreds()) { - TermInst *TI = Pred->getTerminator(); - - if (auto *BI = dyn_cast(TI)) { - OutArray.push_back({Pred, BI->getArg(Index)}); - continue; - } - - if (auto *CBI = dyn_cast(TI)) { - OutArray.push_back({Pred, CBI->getArgForDestBB(getParent(), this)}); - continue; - } - - if (auto *CCBI = dyn_cast(TI)) { - OutArray.push_back({Pred, CCBI->getOperand()}); - continue; - } - - if (auto *SWEI = dyn_cast(TI)) { - OutArray.push_back({Pred, SWEI->getOperand()}); - continue; - } - - return false; + SILValue Value = getIncomingValueForPred(Parent, Pred, Index); + if (!Value) + return false; + OutArray.push_back({Pred, Value}); } return true; @@ -155,23 +154,9 @@ SILValue SILArgument::getIncomingValue(unsigned BBIndex) { continue; } - TermInst *TI = Pred->getTerminator(); - - if (auto *BI = dyn_cast(TI)) - return BI->getArg(Index); - - if (auto *CBI = dyn_cast(TI)) - return CBI->getArgForDestBB(Parent, this); - - if (auto *CCBI = dyn_cast(TI)) - return CCBI->getOperand(); - - if (auto *SWEI = dyn_cast(TI)) - return SWEI->getOperand(); - - // Return an empty SILValue since we ran into something we were unable to + // This will return an empty SILValue if we found something we do not // understand. - return SILValue(); + return getIncomingValueForPred(Parent, Pred, Index); } return SILValue(); @@ -187,33 +172,10 @@ SILValue SILArgument::getIncomingValue(SILBasicBlock *BB) { // that would involve walking the linked list anyways, so we just iterate once // over the loop. - // We use this funky loop since predecessors are stored in a linked list but - // we want array like semantics. - for (SILBasicBlock *Pred : Parent->getPreds()) { - // If BBCount is not BBIndex, continue. - if (Pred != BB) - continue; - - TermInst *TI = Pred->getTerminator(); - - if (auto *BI = dyn_cast(TI)) - return BI->getArg(Index); - - if (auto *CBI = dyn_cast(TI)) - return CBI->getArgForDestBB(Parent, this); - - if (auto *CCBI = dyn_cast(TI)) - return CCBI->getOperand(); - - if (auto *SWEI = dyn_cast(TI)) - return SWEI->getOperand(); - - // Return an empty SILValue since we ran into something we were unable to - // understand. + auto Target = std::find(Parent->pred_begin(), Parent->pred_end(), BB); + if (Target == Parent->pred_end()) return SILValue(); - } - - return SILValue(); + return getIncomingValueForPred(Parent, BB, Index); } bool SILArgument::isSelf() const { diff --git a/lib/SIL/SILBasicBlock.cpp b/lib/SIL/SILBasicBlock.cpp index 90cc45dbc3fd8..d284b1e106bb8 100644 --- a/lib/SIL/SILBasicBlock.cpp +++ b/lib/SIL/SILBasicBlock.cpp @@ -1,8 +1,8 @@ -//===--- SILBasicBlock.cpp - Basic blocks for high-level SIL code ----------==// +//===--- SILBasicBlock.cpp - Basic blocks for high-level SIL code ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp index 5c5fce062af12..61e37e977545d 100644 --- a/lib/SIL/SILBuilder.cpp +++ b/lib/SIL/SILBuilder.cpp @@ -1,8 +1,8 @@ -//===--- SILBuilder.cpp - Class for creating SIL Constructs ----------------==// +//===--- SILBuilder.cpp - Class for creating SIL Constructs ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -48,7 +48,7 @@ SILInstruction *SILBuilder::tryCreateUncheckedRefCast(SILLocation Loc, SILValue Op, SILType ResultTy) { auto &M = F.getModule(); - if (!SILType::canRefCast(Op.getType(), ResultTy, M)) + if (!SILType::canRefCast(Op->getType(), ResultTy, M)) return nullptr; return insert( @@ -165,7 +165,7 @@ static bool couldReduceStrongRefcount(SILInstruction *Inst) { // value drops a retain. We would have to do more alias analysis to be able // to safely ignore one of those. if (auto AI = dyn_cast(Inst)) { - auto StoredType = AI->getOperand(0).getType(); + auto StoredType = AI->getOperand(0)->getType(); if (StoredType.isTrivial(Inst->getModule()) || StoredType.is()) return false; @@ -176,7 +176,7 @@ static bool couldReduceStrongRefcount(SILInstruction *Inst) { if (CAI->isInitializationOfDest()) return false; - SILType StoredType = CAI->getOperand(0).getType().getObjectType(); + SILType StoredType = CAI->getOperand(0)->getType().getObjectType(); if (StoredType.isTrivial(Inst->getModule()) || StoredType.is()) return false; diff --git a/lib/SIL/SILCoverageMap.cpp b/lib/SIL/SILCoverageMap.cpp index daac690fa0a6c..edda49cedfcb6 100644 --- a/lib/SIL/SILCoverageMap.cpp +++ b/lib/SIL/SILCoverageMap.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp index 45afe79015076..4cc482b192742 100644 --- a/lib/SIL/SILDeclRef.cpp +++ b/lib/SIL/SILDeclRef.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -105,8 +105,8 @@ bool swift::requiresObjCDispatch(ValueDecl *vd) { } static unsigned getFuncNaturalUncurryLevel(AnyFunctionRef AFR) { - assert(AFR.getBodyParamPatterns().size() >= 1 && "no arguments for func?!"); - unsigned Level = AFR.getBodyParamPatterns().size() - 1; + assert(AFR.getParameterLists().size() >= 1 && "no arguments for func?!"); + unsigned Level = AFR.getParameterLists().size() - 1; // Functions with captures have an extra uncurry level for the capture // context. if (AFR.getCaptureInfo().hasLocalCaptures()) @@ -209,7 +209,7 @@ SILDeclRef::SILDeclRef(SILDeclRef::Loc baseLoc, } else if (auto *ACE = baseLoc.dyn_cast()) { loc = ACE; kind = Kind::Func; - assert(ACE->getParamPatterns().size() >= 1 && + assert(ACE->getParameterLists().size() >= 1 && "no param patterns for function?!"); naturalUncurryLevel = getFuncNaturalUncurryLevel(ACE); } else { @@ -451,10 +451,9 @@ static void mangleClangDecl(raw_ostream &buffer, importer->getMangledName(buffer, clangDecl); } -static void mangleConstant(SILDeclRef c, llvm::raw_ostream &buffer, - StringRef prefix) { +static std::string mangleConstant(SILDeclRef c, StringRef prefix) { using namespace Mangle; - Mangler mangler(buffer); + Mangler mangler; // Almost everything below gets one of the common prefixes: // mangled-name ::= '_T' global // Native symbol @@ -478,11 +477,10 @@ static void mangleConstant(SILDeclRef c, llvm::raw_ostream &buffer, // entity ::= declaration // other declaration case SILDeclRef::Kind::Func: if (!c.hasDecl()) { - buffer << introducer; + mangler.append(introducer); mangler.mangleClosureEntity(c.getAbstractClosureExpr(), - c.getResilienceExpansion(), c.uncurryLevel); - return; + return mangler.finalize(); } // As a special case, functions can have external asm names. @@ -491,8 +489,8 @@ static void mangleConstant(SILDeclRef c, llvm::raw_ostream &buffer, if (auto AsmA = c.getDecl()->getAttrs().getAttribute()) if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk() && !c.isCurried) { - buffer << AsmA->Name; - return; + mangler.append(AsmA->Name); + return mangler.finalize(); } // Otherwise, fall through into the 'other decl' case. @@ -505,95 +503,93 @@ static void mangleConstant(SILDeclRef c, llvm::raw_ostream &buffer, && !c.isCurried) { if (auto namedClangDecl = dyn_cast(clangDecl)) { if (auto asmLabel = namedClangDecl->getAttr()) { - buffer << '\01' << asmLabel->getLabel(); + mangler.append('\01'); + mangler.append(asmLabel->getLabel()); } else if (namedClangDecl->hasAttr()) { + std::string storage; + llvm::raw_string_ostream SS(storage); // FIXME: When we can import C++, use Clang's mangler all the time. - mangleClangDecl(buffer, namedClangDecl, + mangleClangDecl(SS, namedClangDecl, c.getDecl()->getASTContext()); + mangler.append(SS.str()); } else { - buffer << namedClangDecl->getName(); + mangler.append(namedClangDecl->getName()); } - return; + return mangler.finalize(); } } } - buffer << introducer; - mangler.mangleEntity(c.getDecl(), c.getResilienceExpansion(), c.uncurryLevel); - return; - + mangler.append(introducer); + mangler.mangleEntity(c.getDecl(), c.uncurryLevel); + return mangler.finalize(); + // entity ::= context 'D' // deallocating destructor case SILDeclRef::Kind::Deallocator: - buffer << introducer; + mangler.append(introducer); mangler.mangleDestructorEntity(cast(c.getDecl()), /*isDeallocating*/ true); - return; + return mangler.finalize(); // entity ::= context 'd' // destroying destructor case SILDeclRef::Kind::Destroyer: - buffer << introducer; + mangler.append(introducer); mangler.mangleDestructorEntity(cast(c.getDecl()), /*isDeallocating*/ false); - return; + return mangler.finalize(); // entity ::= context 'C' type // allocating constructor case SILDeclRef::Kind::Allocator: - buffer << introducer; + mangler.append(introducer); mangler.mangleConstructorEntity(cast(c.getDecl()), /*allocating*/ true, - c.getResilienceExpansion(), c.uncurryLevel); - return; + return mangler.finalize(); // entity ::= context 'c' type // initializing constructor case SILDeclRef::Kind::Initializer: - buffer << introducer; + mangler.append(introducer); mangler.mangleConstructorEntity(cast(c.getDecl()), /*allocating*/ false, - c.getResilienceExpansion(), c.uncurryLevel); - return; + return mangler.finalize(); // entity ::= declaration 'e' // ivar initializer // entity ::= declaration 'E' // ivar destroyer case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: - buffer << introducer; + mangler.append(introducer); mangler.mangleIVarInitDestroyEntity( cast(c.getDecl()), c.kind == SILDeclRef::Kind::IVarDestroyer); - return; + return mangler.finalize(); // entity ::= declaration 'a' // addressor case SILDeclRef::Kind::GlobalAccessor: - buffer << introducer; + mangler.append(introducer); mangler.mangleAddressorEntity(c.getDecl()); - return; + return mangler.finalize(); // entity ::= declaration 'G' // getter case SILDeclRef::Kind::GlobalGetter: - buffer << introducer; + mangler.append(introducer); mangler.mangleGlobalGetterEntity(c.getDecl()); - return; + return mangler.finalize(); // entity ::= context 'e' index // default arg generator case SILDeclRef::Kind::DefaultArgGenerator: - buffer << introducer; + mangler.append(introducer); mangler.mangleDefaultArgumentEntity(cast(c.getDecl()), c.defaultArgIndex); - return; + return mangler.finalize(); } llvm_unreachable("bad entity kind!"); } -StringRef SILDeclRef::mangle(SmallVectorImpl &buffer, - StringRef prefix) const { - assert(buffer.empty()); - llvm::raw_svector_ostream stream(buffer); - mangleConstant(*this, stream, prefix); - return stream.str(); -} +std::string SILDeclRef::mangle(StringRef prefix) const { + return mangleConstant(*this, prefix); + } SILDeclRef SILDeclRef::getNextOverriddenVTableEntry() const { if (auto overridden = getOverridden()) { diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp index dd29f11aed1b3..30ad2ac650436 100644 --- a/lib/SIL/SILFunction.cpp +++ b/lib/SIL/SILFunction.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,7 +16,6 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/CFG.h" -#include "swift/SIL/SILModule.h" // FIXME: For mapTypeInContext #include "swift/AST/ArchetypeBuilder.h" #include "llvm/ADT/Optional.h" @@ -90,7 +89,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, Linkage(unsigned(Linkage)), KeepAsPublic(false), ForeignBody(false), - EK(E) { + EffectsKindAttr(E) { if (InsertBefore) Module.functions.insert(SILModule::iterator(InsertBefore), this); else @@ -166,7 +165,7 @@ ASTContext &SILFunction::getASTContext() const { bool SILFunction::shouldOptimize() const { if (Module.getStage() == SILStage::Raw) return true; - return !hasSemanticsString("optimize.sil.never"); + return !hasSemanticsAttr("optimize.sil.never"); } Type SILFunction::mapTypeIntoContext(Type type) const { diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 61518ffcf0c16..ae56333daec3a 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -64,7 +64,7 @@ static CanType getKnownType(Optional &cacheSlot, ASTContext &C, } CanType t = *cacheSlot; - // It is possible that we won't find a briding type (e.g. String) when we're + // It is possible that we won't find a bridging type (e.g. String) when we're // parsing the stdlib itself. if (t) { DEBUG(llvm::dbgs() << "Bridging type " << moduleName << '.' << typeName @@ -122,6 +122,7 @@ enum class ConventionsKind : uint8_t { CFunction = 4, SelectorFamily = 5, Deallocator = 6, + Capture = 7, }; class Conventions { @@ -261,17 +262,23 @@ enum class ConventionsKind : uint8_t { const TypeLowering &substTL) { // If the substituted type is passed indirectly, so must the // unsubstituted type. - if (origType.isOpaque() || substTL.isPassedIndirectly()) { + if ((origType.isTypeParameter() && + !origType.requiresClass(*M.getSwiftModule()))|| + substTL.isPassedIndirectly()) { return true; // If the substitution didn't change the type, then a negative // response to the above is determinative as well. - } else if (origType.getType() == substType) { + } else if (origType.getType() == substType && + !origType.getType()->hasTypeParameter()) { return false; // Otherwise, query specifically for the original type. } else { - return SILType::isPassedIndirectly(origType.getType(), M); + // FIXME: Get expansion from SILDeclRef + return SILType::isPassedIndirectly(origType.getType(), M, + origType.getGenericSignature(), + ResilienceExpansion::Minimal); } } @@ -339,9 +346,10 @@ enum class ConventionsKind : uint8_t { // l-value type -- then it's a valid target for substitution and // we should not expand it. if (isa(substType) && - (!origType.isOpaque() || !substType->isMaterializable())) { + (!origType.isTypeParameter() || + !substType->isMaterializable())) { auto substTuple = cast(substType); - assert(origType.isOpaque() || + assert(origType.isTypeParameter() || origType.getNumTupleElements() == substTuple->getNumElements()); for (auto i : indices(substTuple.getElementTypes())) { visit(origType.getTupleElementType(i), @@ -357,11 +365,8 @@ enum class ConventionsKind : uint8_t { auto &substTL = M.Types.getTypeLowering(origType, substType); ParameterConvention convention; if (isa(substType)) { - assert(origType.isOpaque() || origType.getAs()); + assert(origType.isTypeParameter() || origType.getAs()); convention = ParameterConvention::Indirect_Inout; - } else if (isa(substType)) { - assert(origType.isOpaque() || origType.getAs()); - convention = ParameterConvention::Indirect_InoutAliasable; } else if (isPassedIndirectly(origType, substType, substTL)) { convention = Convs.getIndirectParameter(origParamIndex, origType); assert(isIndirectParameter(convention)); @@ -426,23 +431,23 @@ enum class ConventionsKind : uint8_t { /// \param conventions - conventions as expressed for the original type static CanSILFunctionType getSILFunctionType(SILModule &M, AbstractionPattern origType, - CanAnyFunctionType substFnOldType, CanAnyFunctionType substFnInterfaceType, AnyFunctionType::ExtInfo extInfo, const Conventions &conventions, - const Optional &foreignError) { + const Optional &foreignError, + Optional constant) { SmallVector inputs; // Per above, only fully honor opaqueness in the abstraction pattern // for thick or polymorphic functions. We don't need to worry about // non-opaque patterns because the type-checker forbids non-thick // function types from having generic parameters or results. - if (origType.isOpaque() && - substFnOldType->getExtInfo().getSILRepresentation() + if (origType.isTypeParameter() && + substFnInterfaceType->getExtInfo().getSILRepresentation() != SILFunctionType::Representation::Thick && - isa(substFnOldType)) { + isa(substFnInterfaceType)) { origType = AbstractionPattern(M.Types.getCurGenericContext(), - substFnOldType); + substFnInterfaceType); } // Find the generic parameters. @@ -480,7 +485,7 @@ static CanSILFunctionType getSILFunctionType(SILModule &M, case ForeignErrorConvention::NonZeroResult: assert(substFormalResultType->isVoid()); substFormalResultType = foreignError->getResultType(); - origResultType = AbstractionPattern(substFormalResultType); + origResultType = AbstractionPattern(genericSig, substFormalResultType); break; // These conventions wrap the result type in a level of optionality. @@ -510,19 +515,24 @@ static CanSILFunctionType getSILFunctionType(SILModule &M, // If the unsubstituted type is dependent, then we use the most // general type for the function, which involves an indirect result. - } else if (origResultType.isOpaque()) { + } else if (origResultType.isTypeParameter() && + !origResultType.requiresClass(*M.getSwiftModule())) { hasIndirectResult = true; // If the substitution didn't change the result type, we can use the // lowering that we already fetched. - } else if (origResultType.getType() == substFormalResultType) { + } else if (origResultType.getType() == substFormalResultType && + !origResultType.getType()->hasTypeParameter()) { assert(!substResultTL.isReturnedIndirectly()); hasIndirectResult = false; // Otherwise, ask whether the original result type was address-only. } else { - hasIndirectResult = - SILType::isReturnedIndirectly(origResultType.getType(), M); + // FIXME: Get expansion from SILDeclRef + hasIndirectResult = SILType::isReturnedIndirectly( + origResultType.getType(), M, + origResultType.getGenericSignature(), + ResilienceExpansion::Minimal); } // Okay, with that we can actually construct the result type. @@ -564,7 +574,70 @@ static CanSILFunctionType getSILFunctionType(SILModule &M, substFnInterfaceType.getInput(), extInfo); } - + + // Lower the capture context parameters, if any. + // But note that default arg generators can't capture anything right now, + // and if we ever add that ability, it will be a different capture list + // from the function to which the argument is attached. + if (constant && !constant->isDefaultArgGenerator()) + if (auto function = constant->getAnyFunctionRef()) { + auto &Types = M.Types; + auto loweredCaptures = Types.getLoweredLocalCaptures(*function); + + for (auto capture : loweredCaptures.getCaptures()) { + auto *VD = capture.getDecl(); + auto type = VD->getType()->getCanonicalType(); + + type = Types.getInterfaceTypeOutOfContext(type, + function->getAsDeclContext()); + + auto &loweredTL = Types.getTypeLowering( + AbstractionPattern(genericSig, type), type); + auto loweredTy = loweredTL.getLoweredType(); + switch (Types.getDeclCaptureKind(capture)) { + case CaptureKind::None: + break; + case CaptureKind::Constant: { + // Constants are captured by value. + ParameterConvention convention; + if (loweredTL.isAddressOnly()) { + convention = M.getOptions().EnableGuaranteedClosureContexts + ? ParameterConvention::Indirect_In_Guaranteed + : ParameterConvention::Indirect_In; + } else if (loweredTL.isTrivial()) { + convention = ParameterConvention::Direct_Unowned; + } else { + convention = M.getOptions().EnableGuaranteedClosureContexts + ? ParameterConvention::Direct_Guaranteed + : ParameterConvention::Direct_Owned; + } + SILParameterInfo param(loweredTy.getSwiftRValueType(), convention); + inputs.push_back(param); + break; + } + case CaptureKind::Box: { + // Lvalues are captured as a box that owns the captured value. + SILType ty = loweredTy.getAddressType(); + CanType boxTy = SILBoxType::get(ty.getSwiftRValueType()); + auto convention = M.getOptions().EnableGuaranteedClosureContexts + ? ParameterConvention::Direct_Guaranteed + : ParameterConvention::Direct_Owned; + auto param = SILParameterInfo(boxTy, convention); + inputs.push_back(param); + break; + } + case CaptureKind::StorageAddress: { + // Non-escaping lvalues are captured as the address of the value. + SILType ty = loweredTy.getAddressType(); + auto param = SILParameterInfo(ty.getSwiftRValueType(), + ParameterConvention::Indirect_InoutAliasable); + inputs.push_back(param); + break; + } + } + } + } + auto calleeConvention = ParameterConvention::Direct_Unowned; if (extInfo.hasContext()) calleeConvention = conventions.getCallee(); @@ -730,17 +803,18 @@ namespace { } static CanSILFunctionType getNativeSILFunctionType(SILModule &M, - AbstractionPattern origType, - CanAnyFunctionType substType, - CanAnyFunctionType substInterfaceType, - AnyFunctionType::ExtInfo extInfo, - SILDeclRef::Kind kind) { + AbstractionPattern origType, + CanAnyFunctionType substInterfaceType, + AnyFunctionType::ExtInfo extInfo, + Optional constant, + SILDeclRef::Kind kind) { switch (extInfo.getSILRepresentation()) { case SILFunctionType::Representation::Block: case SILFunctionType::Representation::CFunctionPointer: - return getSILFunctionType(M, origType, substType, substInterfaceType, + // TODO: Ought to support captures in block funcs. + return getSILFunctionType(M, origType, substInterfaceType, extInfo, DefaultBlockConventions(), - None); + None, constant); case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::ObjCMethod: @@ -749,9 +823,9 @@ static CanSILFunctionType getNativeSILFunctionType(SILModule &M, case SILFunctionType::Representation::WitnessMethod: { switch (kind) { case SILDeclRef::Kind::Initializer: - return getSILFunctionType(M, origType, substType, substInterfaceType, + return getSILFunctionType(M, origType, substInterfaceType, extInfo, DefaultInitializerConventions(), - None); + None, constant); case SILDeclRef::Kind::Func: case SILDeclRef::Kind::Allocator: @@ -762,12 +836,13 @@ static CanSILFunctionType getNativeSILFunctionType(SILModule &M, case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: case SILDeclRef::Kind::EnumElement: - return getSILFunctionType(M, origType, substType, substInterfaceType, + return getSILFunctionType(M, origType, substInterfaceType, extInfo, DefaultConventions(), - None); + None, constant); case SILDeclRef::Kind::Deallocator: - return getSILFunctionType(M, origType, substType, substInterfaceType, - extInfo, DeallocatorConventions(), None); + return getSILFunctionType(M, origType, substInterfaceType, + extInfo, DeallocatorConventions(), None, + constant); } } } @@ -775,7 +850,6 @@ static CanSILFunctionType getNativeSILFunctionType(SILModule &M, CanSILFunctionType swift::getNativeSILFunctionType(SILModule &M, AbstractionPattern origType, - CanAnyFunctionType substType, CanAnyFunctionType substInterfaceType, SILDeclRef::Kind kind) { AnyFunctionType::ExtInfo extInfo; @@ -786,10 +860,10 @@ CanSILFunctionType swift::getNativeSILFunctionType(SILModule &M, // Otherwise, preserve function type attributes from the substituted type. } else { - extInfo = substType->getExtInfo(); + extInfo = substInterfaceType->getExtInfo(); } - return ::getNativeSILFunctionType(M, origType, substType, substInterfaceType, - extInfo, kind); + return ::getNativeSILFunctionType(M, origType, substInterfaceType, + extInfo, None, kind); } //===----------------------------------------------------------------------===// @@ -1092,24 +1166,23 @@ namespace { static CanSILFunctionType getSILFunctionTypeForClangDecl(SILModule &M, const clang::Decl *clangDecl, CanAnyFunctionType origType, - CanAnyFunctionType substType, CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, const Optional &foreignError) { if (auto method = dyn_cast(clangDecl)) { auto origPattern = AbstractionPattern::getObjCMethod(origType, method, foreignError); - return getSILFunctionType(M, origPattern, substType, substInterfaceType, + return getSILFunctionType(M, origPattern, substInterfaceType, extInfo, ObjCMethodConventions(method), - foreignError); + foreignError, None); } if (auto func = dyn_cast(clangDecl)) { AbstractionPattern origPattern(origType, func->getType().getTypePtr()); - return getSILFunctionType(M, origPattern, substType, substInterfaceType, + return getSILFunctionType(M, origPattern, substInterfaceType, extInfo, CFunctionConventions(func), - foreignError); + foreignError, None); } llvm_unreachable("call to unknown kind of C function"); @@ -1289,55 +1362,33 @@ namespace { static CanSILFunctionType getSILFunctionTypeForSelectorFamily(SILModule &M, SelectorFamily family, CanAnyFunctionType origType, - CanAnyFunctionType substType, CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, const Optional &foreignError) { return getSILFunctionType(M, AbstractionPattern(origType), - substType, substInterfaceType, + substInterfaceType, extInfo, SelectorFamilyConventions(family), - foreignError); + foreignError, None); } static CanSILFunctionType getUncachedSILFunctionTypeForConstant(SILModule &M, SILDeclRef constant, - CanAnyFunctionType origLoweredType, - CanAnyFunctionType origLoweredInterfaceType, - CanAnyFunctionType substFormalType, - CanAnyFunctionType substInterfaceType) { - assert(origLoweredType->getExtInfo().getSILRepresentation() + CanAnyFunctionType origLoweredInterfaceType) { + assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation() != SILFunctionTypeRepresentation::Thick - && origLoweredType->getExtInfo().getSILRepresentation() + && origLoweredInterfaceType->getExtInfo().getSILRepresentation() != SILFunctionTypeRepresentation::Block); - auto extInfo = origLoweredType->getExtInfo(); - - CanAnyFunctionType substLoweredType; - CanAnyFunctionType substLoweredInterfaceType; - if (substFormalType) { - assert(substInterfaceType); - substLoweredType = M.Types.getLoweredASTFunctionType(substFormalType, - constant.uncurryLevel, - extInfo, - constant); - substLoweredInterfaceType - = M.Types.getLoweredASTFunctionType(substInterfaceType, - constant.uncurryLevel, - extInfo, - constant); - } else { - assert(!substInterfaceType); - substLoweredType = origLoweredType; - substLoweredInterfaceType = origLoweredInterfaceType; - } + auto extInfo = origLoweredInterfaceType->getExtInfo(); if (!constant.isForeign) { - return getNativeSILFunctionType(M, AbstractionPattern(origLoweredType), - substLoweredType, - substLoweredInterfaceType, - extInfo, - constant.kind); + return getNativeSILFunctionType(M, + AbstractionPattern(origLoweredInterfaceType), + origLoweredInterfaceType, + extInfo, + constant, + constant.kind); } Optional foreignError; @@ -1352,16 +1403,16 @@ getUncachedSILFunctionTypeForConstant(SILModule &M, SILDeclRef constant, if (auto clangDecl = findClangMethod(decl)) return getSILFunctionTypeForClangDecl(M, clangDecl, - origLoweredType, substLoweredType, - substLoweredInterfaceType, + origLoweredInterfaceType, + origLoweredInterfaceType, extInfo, foreignError); } // If the decl belongs to an ObjC method family, use that family's // ownership conventions. return getSILFunctionTypeForSelectorFamily(M, getSelectorFamily(constant), - origLoweredType, substLoweredType, - substLoweredInterfaceType, + origLoweredInterfaceType, + origLoweredInterfaceType, extInfo, foreignError); } @@ -1430,7 +1481,6 @@ SILConstantInfo TypeConverter::getConstantInfo(SILDeclRef constant) { // First, get a function type for the constant. This creates the // right type for a getter or setter. - auto formalType = makeConstantType(constant); auto formalInterfaceType = makeConstantInterfaceType(constant); GenericParamList *contextGenerics, *innerGenerics; std::tie(contextGenerics, innerGenerics) @@ -1438,36 +1488,31 @@ SILConstantInfo TypeConverter::getConstantInfo(SILDeclRef constant) { // The formal type is just that with the right representation. auto rep = getDeclRefRepresentation(constant); - formalType = adjustFunctionType(formalType, rep); formalInterfaceType = adjustFunctionType(formalInterfaceType, rep); // The lowered type is the formal type, but uncurried and with // parameters automatically turned into their bridged equivalents. - auto loweredType = - getLoweredASTFunctionType(formalType, constant.uncurryLevel, constant); auto loweredInterfaceType = getLoweredASTFunctionType(formalInterfaceType, constant.uncurryLevel, constant); // The SIL type encodes conventions according to the original type. CanSILFunctionType silFnType = - getUncachedSILFunctionTypeForConstant(M, constant, loweredType, - loweredInterfaceType, - CanAnyFunctionType(), - CanAnyFunctionType()); + getUncachedSILFunctionTypeForConstant(M, constant, + loweredInterfaceType); DEBUG(llvm::dbgs() << "lowering type for constant "; constant.print(llvm::dbgs()); llvm::dbgs() << "\n formal type: "; - formalType.print(llvm::dbgs()); + formalInterfaceType.print(llvm::dbgs()); llvm::dbgs() << "\n lowered AST type: "; - loweredType.print(llvm::dbgs()); + loweredInterfaceType.print(llvm::dbgs()); llvm::dbgs() << "\n SIL type: "; silFnType.print(llvm::dbgs()); llvm::dbgs() << "\n"); SILConstantInfo result = { - formalType, formalInterfaceType, - loweredType, loweredInterfaceType, + formalInterfaceType, + loweredInterfaceType, silFnType, contextGenerics, innerGenerics, @@ -1653,10 +1698,10 @@ namespace { CanSILFunctionType TypeConverter::substFunctionType(CanSILFunctionType origFnType, CanAnyFunctionType origLoweredType, - CanAnyFunctionType substLoweredType, CanAnyFunctionType substLoweredInterfaceType, const Optional &foreignError) { - if (origLoweredType == substLoweredType) + // FIXME: is this inefficient now? + if (origLoweredType == substLoweredInterfaceType) return origFnType; // Use the generic parameters from the substituted type. @@ -1667,9 +1712,11 @@ TypeConverter::substFunctionType(CanSILFunctionType origFnType, GenericContextScope scope(*this, genericSig); SILFunctionTypeSubstituter substituter(*this, origFnType, foreignError); + AbstractionPattern origLoweredPattern(origLoweredType); + // Map the result. SILResultInfo substResult = - substituter.substResult(AbstractionPattern(origLoweredType.getResult()), + substituter.substResult(origLoweredPattern.getFunctionResultType(), substLoweredInterfaceType.getResult()); // Map the error result. Currently this is never dependent. @@ -1680,16 +1727,16 @@ TypeConverter::substFunctionType(CanSILFunctionType origFnType, !substErrorResult->getType()->hasArchetype())); // Map the inputs. - substituter.substInputs(AbstractionPattern(origLoweredType.getInput()), + substituter.substInputs(origLoweredPattern.getFunctionInputType(), substLoweredInterfaceType.getInput()); // Allow the substituted type to add thick-ness, but not remove it. assert(!origFnType->getExtInfo().hasContext() - || substLoweredType->getExtInfo().hasContext()); - assert(substLoweredType->getExtInfo().getSILRepresentation() + || substLoweredInterfaceType->getExtInfo().hasContext()); + assert(substLoweredInterfaceType->getExtInfo().getSILRepresentation() == substLoweredInterfaceType->getExtInfo().getSILRepresentation()); - auto rep = substLoweredType->getExtInfo().getSILRepresentation(); + auto rep = substLoweredInterfaceType->getExtInfo().getSILRepresentation(); auto extInfo = origFnType->getExtInfo().withRepresentation(rep); // FIXME: Map into archetype context. @@ -1702,28 +1749,6 @@ TypeConverter::substFunctionType(CanSILFunctionType origFnType, Context); } -// This is a hack until we eliminate contextual type usage from ConstantInfo, -// or add support for GenericFunctionType to mapTypeIntoContext(). -static AnyFunctionType *mapFuncTypeIntoContext(Module *M, - GenericParamList *genericParams, - Type type) { - auto fnTy = type->castTo(); - if (!genericParams) - return fnTy; - - auto inputTy = ArchetypeBuilder::mapTypeIntoContext(M, genericParams, - fnTy->getInput()); - auto resultTy = ArchetypeBuilder::mapTypeIntoContext(M, genericParams, - fnTy->getResult()); - - // Introduce a generic signature - if (fnTy->is()) - return PolymorphicFunctionType::get(inputTy, resultTy, genericParams, - fnTy->getExtInfo()); - else - return FunctionType::get(inputTy, resultTy, fnTy->getExtInfo()); -} - /// Returns the ConstantInfo corresponding to the VTable thunk for overriding. /// Will be the same as getConstantInfo if the declaration does not override. SILConstantInfo TypeConverter::getConstantOverrideInfo(SILDeclRef derived, @@ -1744,7 +1769,7 @@ SILConstantInfo TypeConverter::getConstantOverrideInfo(SILDeclRef derived, // If the derived method is ABI-compatible with the base method, give the // vtable thunk the same signature as the derived method. - auto basePattern = AbstractionPattern(baseInfo.LoweredType); + auto basePattern = AbstractionPattern(baseInfo.LoweredInterfaceType); auto baseInterfaceTy = makeConstantInterfaceType(base); auto derivedInterfaceTy = makeConstantInterfaceType(derived); @@ -1782,21 +1807,13 @@ SILConstantInfo TypeConverter::getConstantOverrideInfo(SILDeclRef derived, base.uncurryLevel + 1); } - auto overrideFormalTy = mapFuncTypeIntoContext(M.getSwiftModule(), - derivedInfo.ContextGenericParams, - overrideInterfaceTy); - - // Lower the formal AST types. - auto overrideLoweredTy = getLoweredASTFunctionType( - cast(overrideFormalTy->getCanonicalType()), - derived.uncurryLevel, derived); + // Lower the formal AST type. auto overrideLoweredInterfaceTy = getLoweredASTFunctionType( cast(overrideInterfaceTy->getCanonicalType()), derived.uncurryLevel, derived); // Build the SILFunctionType for the vtable thunk. CanSILFunctionType fnTy = getNativeSILFunctionType(M, basePattern, - overrideLoweredTy, overrideLoweredInterfaceTy, derived.kind); @@ -1814,7 +1831,6 @@ SILConstantInfo TypeConverter::getConstantOverrideInfo(SILDeclRef derived, // Build the SILConstantInfo and cache it. SILConstantInfo overrideInfo; - overrideInfo.LoweredType = overrideLoweredTy; overrideInfo.LoweredInterfaceType = overrideLoweredInterfaceTy; overrideInfo.SILFnType = fnTy; overrideInfo.ContextGenericParams = derivedInfo.ContextGenericParams; @@ -1832,28 +1848,9 @@ namespace { SILModule &TheSILModule; Module *TheASTModule; TypeSubstitutionMap &Subs; - CanGenericSignature Generics; ASTContext &getASTContext() { return TheSILModule.getASTContext(); } - class GenericsRAII { - SILTypeSubstituter &Self; - GenericContextScope Scope; - CanGenericSignature OldGenerics; - public: - GenericsRAII(SILTypeSubstituter &self, CanGenericSignature generics) - : Self(self), - Scope(self.TheSILModule.Types, generics), - OldGenerics(self.Generics) { - if (generics) self.Generics = generics; - } - - ~GenericsRAII() { - Self.Generics = OldGenerics; - } - }; - - public: SILTypeSubstituter(SILModule &silModule, Module *astModule, TypeSubstitutionMap &subs) @@ -1866,7 +1863,8 @@ namespace { CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType, bool dropGenerics = false) { - GenericsRAII scope(*this, origType->getGenericSignature()); + GenericContextScope scope(TheSILModule.Types, + origType->getGenericSignature()); SILResultInfo substResult = subst(origType->getResult()); @@ -1936,7 +1934,9 @@ namespace { assert(!isa(origType)); assert(!isa(origType) && !isa(origType)); - AbstractionPattern abstraction(Generics, origType); + CanGenericSignature genericSig = + TheSILModule.Types.getCurGenericContext(); + AbstractionPattern abstraction(genericSig, origType); assert(TheSILModule.Types.getLoweredType(abstraction, origType) .getSwiftRValueType() == origType); @@ -2007,29 +2007,17 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, genericSig = gft.getGenericSignature(); } - // Pull the innermost generic parameter list in the type out. - Optional genericParams; + // Remove this when PolymorphicFunctionType goes away. { CanAnyFunctionType innerTy = t; while (innerTy) { - if (auto pft = dyn_cast(innerTy)) { - assert(!genericParams - || pft->getGenericParams().getOuterParameters() == *genericParams); - genericParams = &pft->getGenericParams(); - } + assert(!isa(innerTy)); innerTy = dyn_cast(innerTy.getResult()); } } - GenericParamList *innerGenericParams - = genericParams ? *genericParams : nullptr; auto rebuild = [&](CanType input, CanType result) -> CanAnyFunctionType { - if (genericParams) { - assert(!genericSig && "got mix of poly/generic function type?!"); - return CanPolymorphicFunctionType::get(input, result, - innerGenericParams, - extInfo); - } else if (genericSig) { + if (genericSig) { return CanGenericFunctionType::get(genericSig, input, result, extInfo); } else { return CanFunctionType::get(input, result, extInfo); @@ -2042,7 +2030,7 @@ TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, case SILFunctionTypeRepresentation::Method: case SILFunctionTypeRepresentation::WitnessMethod: // No bridging needed for native functions. - if (t->getExtInfo() == extInfo && !innerGenericParams) + if (t->getExtInfo() == extInfo) return t; return rebuild(t.getInput(), t.getResult()); @@ -2160,19 +2148,11 @@ TypeConverter::getLoweredASTFunctionType(CanAnyFunctionType fnType, // The uncurried input types. SmallVector inputs; - // The innermost generic parameter list. - // FIXME: Interface types make this unnecessary. - Optional genericParams; - // Merge inputs and generic parameters from the uncurry levels. for (;;) { inputs.push_back(TupleTypeElt(fnType->getInput())); - if (auto pft = dyn_cast(fnType)) { - assert(!genericParams - || pft->getGenericParams().getOuterParameters() == *genericParams); - genericParams = &pft->getGenericParams(); - } + assert(!isa(fnType)); // The uncurried function calls all of the intermediate function // levels and so throws if any of them do. @@ -2233,18 +2213,9 @@ TypeConverter::getLoweredASTFunctionType(CanAnyFunctionType fnType, // Create the new function type. CanType inputType = CanType(TupleType::get(inputs, Context)); - GenericParamList *innerGenericParams - = genericParams ? *genericParams : nullptr; if (genericSig) { - assert(!innerGenericParams && "got mix of Polymorphic/Generic FunctionType?!"); return CanGenericFunctionType::get(genericSig, inputType, resultType, extInfo); - } - - if (innerGenericParams) { - return CanPolymorphicFunctionType::get(inputType, resultType, - innerGenericParams, - extInfo); } else { return CanFunctionType::get(inputType, resultType, extInfo); } diff --git a/lib/SIL/SILGlobalVariable.cpp b/lib/SIL/SILGlobalVariable.cpp index 9d05362978776..c7acd4e47c886 100644 --- a/lib/SIL/SILGlobalVariable.cpp +++ b/lib/SIL/SILGlobalVariable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -67,6 +67,8 @@ SILGlobalVariable::~SILGlobalVariable() { getModule().GlobalVariableTable.erase(Name); } +// FIXME + static bool analyzeStaticInitializer(SILFunction *F, SILInstruction *&Val, SILGlobalVariable *&GVar) { Val = nullptr; @@ -81,16 +83,18 @@ static bool analyzeStaticInitializer(SILFunction *F, SILInstruction *&Val, for (auto &I : *BB) { // Make sure we have a single GlobalAddrInst and a single StoreInst. // And the StoreInst writes to the GlobalAddrInst. - if (auto *sga = dyn_cast(&I)) { + if (isa(&I)) { + continue; + } else if (auto *sga = dyn_cast(&I)) { if (SGA) return false; SGA = sga; GVar = SGA->getReferencedGlobal(); } else if (auto *SI = dyn_cast(&I)) { - if (HasStore || SI->getDest().getDef() != SGA) + if (HasStore || SI->getDest() != SGA) return false; HasStore = true; - Val = dyn_cast(SI->getSrc().getDef()); + Val = dyn_cast(SI->getSrc()); // We only handle StructInst and TupleInst being stored to a // global variable for now. @@ -109,12 +113,24 @@ static bool analyzeStaticInitializer(SILFunction *F, SILInstruction *&Val, } } + // Objective-C selector string literals cannot be used in static + // initializers. + if (auto *stringLit = dyn_cast(&I)) { + switch (stringLit->getEncoding()) { + case StringLiteralInst::Encoding::UTF8: + case StringLiteralInst::Encoding::UTF16: + continue; + + case StringLiteralInst::Encoding::ObjCSelector: + return false; + } + } + if (I.getKind() != ValueKind::ReturnInst && I.getKind() != ValueKind::StructInst && I.getKind() != ValueKind::TupleInst && I.getKind() != ValueKind::IntegerLiteralInst && - I.getKind() != ValueKind::FloatLiteralInst && - I.getKind() != ValueKind::StringLiteralInst) + I.getKind() != ValueKind::FloatLiteralInst) return false; } } diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp index 63b7783edb28c..ff3f5c8d49c5e 100644 --- a/lib/SIL/SILInstruction.cpp +++ b/lib/SIL/SILInstruction.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the high-level SILInstruction classes used for SIL code. +// This file defines the high-level SILInstruction classes used for SIL code. // //===----------------------------------------------------------------------===// @@ -35,13 +35,6 @@ using namespace Lowering; // Instruction-specific properties on SILValue //===----------------------------------------------------------------------===// -Optional SILValue::getLoc() const { - if (auto I = dyn_cast(*this)) { - return I->getLoc(); - } - return None; -} - SILLocation SILInstruction::getLoc() const { return Location.getLocation(); } const SILDebugScope *SILInstruction::getDebugScope() const { @@ -88,7 +81,7 @@ void llvm::ilist_traits:: transferNodesFromList(llvm::ilist_traits &L2, llvm::ilist_iterator first, llvm::ilist_iterator last) { - // If transfering instructions within the same basic block, no reason to + // If transferring instructions within the same basic block, no reason to // update their parent pointers. SILBasicBlock *ThisParent = getContainingBlock(); if (ThisParent == L2.getContainingBlock()) return; @@ -172,7 +165,7 @@ void SILInstruction::replaceAllUsesWithUndef() { SILModule &Mod = getModule(); while (!use_empty()) { Operand *Op = *use_begin(); - Op->set(SILUndef::get(Op->get().getType(), Mod)); + Op->set(SILUndef::get(Op->get()->getType(), Mod)); } } @@ -261,6 +254,10 @@ namespace { return true; } + bool visitProjectExistentialBoxInst(const ProjectExistentialBoxInst *RHS) { + return true; + } + bool visitStrongReleaseInst(const StrongReleaseInst *RHS) { return true; } @@ -287,6 +284,11 @@ namespace { return X->getReferencedFunction() == RHS->getReferencedFunction(); } + bool visitAllocGlobalInst(const AllocGlobalInst *RHS) { + auto *X = cast(LHS); + return X->getReferencedGlobal() == RHS->getReferencedGlobal(); + } + bool visitGlobalAddrInst(const GlobalAddrInst *RHS) { auto *X = cast(LHS); return X->getReferencedGlobal() == RHS->getReferencedGlobal(); diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 8e089f16b4608..2688dad9866bc 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -1,8 +1,8 @@ -//===--- SILInstruction.cpp - Instructions for SIL code -------------------===// +//===--- SILInstructions.cpp - Instructions for SIL code ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the high-level SILInstruction classes used for SIL code. +// This file defines the high-level SILInstruction classes used for SIL code. // //===----------------------------------------------------------------------===// @@ -35,16 +35,6 @@ using namespace Lowering; // SILInstruction Subclasses //===----------------------------------------------------------------------===// -// alloc_stack always returns two results: Builtin.RawPointer & LValue[EltTy] -static SILTypeList *getAllocStackType(SILType eltTy, SILFunction &F) { - SILType resTys[] = { - eltTy.getLocalStorageType(), - eltTy.getAddressType() - }; - - return F.getModule().getSILTypeList(resTys); -} - template static void *allocateDebugVarCarryingInst(SILModule &M, SILDebugVariable Var) { return M.allocateInst(sizeof(INST) + Var.Name.size(), alignof(INST)); @@ -65,7 +55,7 @@ StringRef TailAllocatedDebugVariable::getName(const char *buf) const { AllocStackInst::AllocStackInst(SILDebugLocation *Loc, SILType elementType, SILFunction &F, SILDebugVariable Var) : AllocationInst(ValueKind::AllocStackInst, Loc, - getAllocStackType(elementType, F)), + elementType.getAddressType()), VarInfo(Var, reinterpret_cast(this + 1)) {} AllocStackInst *AllocStackInst::create(SILDebugLocation *Loc, @@ -87,23 +77,11 @@ AllocRefInst::AllocRefInst(SILDebugLocation *Loc, SILType elementType, : AllocationInst(ValueKind::AllocRefInst, Loc, elementType), StackPromotable(canBeOnStack), ObjC(objc) {} -// alloc_box returns two results: Builtin.NativeObject & LValue[EltTy] -static SILTypeList *getAllocBoxType(SILType EltTy, SILFunction &F) { - SILType boxTy = SILType::getPrimitiveObjectType( - SILBoxType::get(EltTy.getSwiftRValueType())); - - SILType ResTys[] = { - boxTy, - EltTy.getAddressType() - }; - - return F.getModule().getSILTypeList(ResTys); -} - AllocBoxInst::AllocBoxInst(SILDebugLocation *Loc, SILType ElementType, SILFunction &F, SILDebugVariable Var) : AllocationInst(ValueKind::AllocBoxInst, Loc, - getAllocBoxType(ElementType, F)), + SILType::getPrimitiveObjectType( + SILBoxType::get(ElementType.getSwiftRValueType()))), VarInfo(Var, reinterpret_cast(this + 1)) {} AllocBoxInst *AllocBoxInst::create(SILDebugLocation *Loc, SILType ElementType, @@ -149,28 +127,17 @@ VarDecl *DebugValueAddrInst::getDecl() const { return getLoc().getAsASTNode(); } -static SILTypeList *getAllocExistentialBoxType(SILType ExistTy, - SILType ConcreteTy, - SILFunction &F) { - SILType Tys[] = { - ExistTy.getObjectType(), - ConcreteTy.getAddressType(), - }; - return F.getModule().getSILTypeList(Tys); -} - AllocExistentialBoxInst::AllocExistentialBoxInst( SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType, - SILType ConcreteLoweredType, ArrayRef Conformances, - SILFunction *Parent) + ArrayRef Conformances, SILFunction *Parent) : AllocationInst(ValueKind::AllocExistentialBoxInst, Loc, - getAllocExistentialBoxType(ExistentialType, - ConcreteLoweredType, *Parent)), + ExistentialType.getObjectType()), ConcreteType(ConcreteType), Conformances(Conformances) {} static void declareWitnessTable(SILModule &Mod, - ProtocolConformance *C) { - if (!C) return; + ProtocolConformanceRef conformanceRef) { + if (conformanceRef.isAbstract()) return; + auto C = conformanceRef.getConcrete(); if (!Mod.lookUpWitnessTable(C, false).first) Mod.createWitnessTableDeclaration(C, TypeConverter::getLinkageForProtocolConformance( @@ -180,17 +147,16 @@ static void declareWitnessTable(SILModule &Mod, AllocExistentialBoxInst *AllocExistentialBoxInst::create( SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType, - SILType ConcreteLoweredType, ArrayRef Conformances, + ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst), alignof(AllocExistentialBoxInst)); - for (ProtocolConformance *C : Conformances) + for (ProtocolConformanceRef C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) AllocExistentialBoxInst(Loc, ExistentialType, ConcreteType, - ConcreteLoweredType, Conformances, F); } @@ -241,7 +207,7 @@ ApplyInst *ApplyInst::create(SILDebugLocation *Loc, SILValue Callee, bool swift::doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics) { if (auto *FRI = dyn_cast(callee)) if (auto *F = FRI->getReferencedFunction()) - return F->hasSemanticsString(semantics); + return F->hasSemanticsAttr(semantics); return false; } @@ -310,9 +276,18 @@ void FunctionRefInst::dropReferencedFunction() { Function = nullptr; } -GlobalAddrInst::GlobalAddrInst(SILDebugLocation *Loc, SILGlobalVariable *Global) +AllocGlobalInst::AllocGlobalInst(SILDebugLocation *Loc, + SILGlobalVariable *Global) + : SILInstruction(ValueKind::AllocGlobalInst, Loc), + Global(Global) {} + +AllocGlobalInst::AllocGlobalInst(SILDebugLocation *Loc) + : SILInstruction(ValueKind::AllocGlobalInst, Loc) {} + +GlobalAddrInst::GlobalAddrInst(SILDebugLocation *Loc, + SILGlobalVariable *Global) : LiteralInst(ValueKind::GlobalAddrInst, Loc, - Global->getLoweredType().getAddressType()), + Global->getLoweredType().getAddressType()), Global(Global) {} GlobalAddrInst::GlobalAddrInst(SILDebugLocation *Loc, SILType Ty) @@ -482,7 +457,7 @@ static SILType getPinResultType(SILType operandType) { } StrongPinInst::StrongPinInst(SILDebugLocation *Loc, SILValue operand) - : UnaryInstructionBase(Loc, operand, getPinResultType(operand.getType())) {} + : UnaryInstructionBase(Loc, operand, getPinResultType(operand->getType())) {} CopyAddrInst::CopyAddrInst(SILDebugLocation *Loc, SILValue SrcLValue, SILValue DestLValue, IsTake_t isTakeOfSrc, @@ -542,15 +517,15 @@ bool TupleExtractInst::isTrivialEltOfOneRCIDTuple() const { if (!getType().isTrivial(Mod)) return false; - // If the elt we are extracting is trivial, we can not have any non trivial + // If the elt we are extracting is trivial, we cannot have any non trivial // fields. - if (getOperand().getType().isTrivial(Mod)) + if (getOperand()->getType().isTrivial(Mod)) return false; // Ok, now we know that our tuple has non-trivial fields. Make sure that our // parent tuple has only one non-trivial field. bool FoundNonTrivialField = false; - SILType OpTy = getOperand().getType(); + SILType OpTy = getOperand()->getType(); unsigned FieldNo = getFieldNo(); // For each element index of the tuple... @@ -585,14 +560,14 @@ bool TupleExtractInst::isTrivialEltOfOneRCIDTuple() const { bool TupleExtractInst::isEltOnlyNonTrivialElt() const { SILModule &Mod = getModule(); - // If the elt we are extracting is trivial, we can not be a non-trivial + // If the elt we are extracting is trivial, we cannot be a non-trivial // field... return false. if (getType().isTrivial(Mod)) return false; // Ok, we know that the elt we are extracting is non-trivial. Make sure that // we have no other non-trivial elts. - SILType OpTy = getOperand().getType(); + SILType OpTy = getOperand()->getType(); unsigned FieldNo = getFieldNo(); // For each element index of the tuple... @@ -623,9 +598,9 @@ bool StructExtractInst::isTrivialFieldOfOneRCIDStruct() const { if (!getType().isTrivial(Mod)) return false; - SILType StructTy = getOperand().getType(); + SILType StructTy = getOperand()->getType(); - // If the elt we are extracting is trivial, we can not have any non trivial + // If the elt we are extracting is trivial, we cannot have any non trivial // fields. if (StructTy.isTrivial(Mod)) return false; @@ -669,12 +644,12 @@ bool StructExtractInst::isTrivialFieldOfOneRCIDStruct() const { bool StructExtractInst::isFieldOnlyNonTrivialField() const { SILModule &Mod = getModule(); - // If the field we are extracting is trivial, we can not be a non-trivial + // If the field we are extracting is trivial, we cannot be a non-trivial // field... return false. if (getType().isTrivial(Mod)) return false; - SILType StructTy = getOperand().getType(); + SILType StructTy = getOperand()->getType(); // Ok, we are visiting a non-trivial field. Then for every stored field... for (VarDecl *D : getStructDecl()->getStoredProperties()) { @@ -774,23 +749,26 @@ OperandValueArrayRef CondBranchInst::getFalseArgs() const { return Operands.asValueArray().slice(1 + NumTrueArgs, NumFalseArgs); } -SILValue -CondBranchInst::getArgForDestBB(SILBasicBlock *DestBB, SILArgument *A) { - // If TrueBB and FalseBB equal, we can not find an arg for this DestBB so +SILValue CondBranchInst::getArgForDestBB(const SILBasicBlock *DestBB, + const SILArgument *Arg) const { + return getArgForDestBB(DestBB, Arg->getIndex()); +} + +SILValue CondBranchInst::getArgForDestBB(const SILBasicBlock *DestBB, + unsigned ArgIndex) const { + // If TrueBB and FalseBB equal, we cannot find an arg for this DestBB so // return an empty SILValue. if (getTrueBB() == getFalseBB()) { assert(DestBB == getTrueBB() && "DestBB is not a target of this cond_br"); return SILValue(); } - unsigned i = A->getIndex(); - if (DestBB == getTrueBB()) - return Operands[1 + i].get(); + return Operands[1 + ArgIndex].get(); assert(DestBB == getFalseBB() && "By process of elimination BB must be false BB"); - return Operands[1 + NumTrueArgs + i].get(); + return Operands[1 + NumTrueArgs + ArgIndex].get(); } ArrayRef CondBranchInst::getTrueOperands() const { @@ -857,11 +835,17 @@ SwitchValueInst::SwitchValueInst(SILDebugLocation *Loc, SILValue Operand, auto *succs = getSuccessorBuf(); unsigned OperandBitWidth = 0; - if (auto OperandTy = Operand.getType().getAs()) { + if (auto OperandTy = Operand->getType().getAs()) { OperandBitWidth = OperandTy->getGreatestWidth(); } for (unsigned i = 0, size = Cases.size(); i < size; ++i) { + // If we have undef, just add the case and continue. + if (isa(Cases[i])) { + ::new (succs + i) SILSuccessor(this, BBs[i]); + continue; + } + if (OperandBitWidth) { auto *IL = dyn_cast(Cases[i]); assert(IL && "switch_value case value should be of an integer type"); @@ -922,7 +906,7 @@ SelectValueInst::SelectValueInst(SILDebugLocation *Loc, SILValue Operand, unsigned OperandBitWidth = 0; - if (auto OperandTy = Operand.getType().getAs()) { + if (auto OperandTy = Operand->getType().getAs()) { OperandBitWidth = OperandTy->getGreatestWidth(); } @@ -945,7 +929,7 @@ SelectValueInst::create(SILDebugLocation *Loc, SILValue Operand, SILType Type, SILFunction &F) { // Allocate enough room for the instruction with tail-allocated data for all // the case values and the SILSuccessor arrays. There are `CaseBBs.size()` - // SILValuues and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. + // SILValues and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. SmallVector CaseValuesAndResults; for (auto pair : CaseValues) { CaseValuesAndResults.push_back(pair.first); @@ -1045,14 +1029,16 @@ namespace { template EnumElementDecl * getUniqueCaseForDefaultValue(Inst *inst, SILValue enumValue) { assert(inst->hasDefault() && "doesn't have a default"); - SILType enumType = enumValue.getType(); - - if (!enumType.hasFixedLayout(inst->getModule())) - return nullptr; + SILType enumType = enumValue->getType(); EnumDecl *decl = enumType.getEnumOrBoundGenericEnum(); assert(decl && "switch_enum operand is not an enum"); + // FIXME: Get expansion from SILFunction + if (!decl->hasFixedLayout(inst->getModule().getSwiftModule(), + ResilienceExpansion::Maximal)) + return nullptr; + llvm::SmallPtrSet unswitchedElts; for (auto elt : decl->getAllElements()) unswitchedElts.insert(elt); @@ -1133,7 +1119,7 @@ NullablePtr SwitchEnumInstBase::getUniqueCaseForDefault() { NullablePtr SwitchEnumInstBase::getUniqueCaseForDestination(SILBasicBlock *BB) { SILValue value = getOperand(); - SILType enumType = value.getType(); + SILType enumType = value->getType(); EnumDecl *decl = enumType.getEnumOrBoundGenericEnum(); assert(decl && "switch_enum operand is not an enum"); (void)decl; @@ -1223,7 +1209,7 @@ TypeConverter::getLinkageForProtocolConformance(const NormalProtocolConformance /// deserialize the actual function definition if we need to. WitnessMethodInst * WitnessMethodInst::create(SILDebugLocation *Loc, CanType LookupType, - ProtocolConformance *Conformance, SILDeclRef Member, + ProtocolConformanceRef Conformance, SILDeclRef Member, SILType Ty, SILFunction *F, SILValue OpenedExistential, bool Volatile) { SILModule &Mod = F->getModule(); @@ -1237,12 +1223,12 @@ WitnessMethodInst::create(SILDebugLocation *Loc, CanType LookupType, InitExistentialAddrInst *InitExistentialAddrInst::create( SILDebugLocation *Loc, SILValue Existential, CanType ConcreteType, - SILType ConcreteLoweredType, ArrayRef Conformances, + SILType ConcreteLoweredType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(InitExistentialAddrInst), alignof(InitExistentialAddrInst)); - for (ProtocolConformance *C : Conformances) + for (ProtocolConformanceRef C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) InitExistentialAddrInst(Loc, Existential, ConcreteType, @@ -1253,17 +1239,13 @@ InitExistentialAddrInst *InitExistentialAddrInst::create( InitExistentialRefInst * InitExistentialRefInst::create(SILDebugLocation *Loc, SILType ExistentialType, CanType ConcreteType, SILValue Instance, - ArrayRef Conformances, + ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(InitExistentialRefInst), alignof(InitExistentialRefInst)); - for (ProtocolConformance *C : Conformances) { - if (!C) - continue; - if (!Mod.lookUpWitnessTable(C, false).first) - declareWitnessTable(Mod, C); - } + for (ProtocolConformanceRef C : Conformances) + declareWitnessTable(Mod, C); return ::new (Buffer) InitExistentialRefInst(Loc, ExistentialType, ConcreteType, @@ -1273,41 +1255,36 @@ InitExistentialRefInst::create(SILDebugLocation *Loc, SILType ExistentialType, InitExistentialMetatypeInst::InitExistentialMetatypeInst( SILDebugLocation *Loc, SILType existentialMetatypeType, SILValue metatype, - ArrayRef conformances) + ArrayRef conformances) : UnaryInstructionBase(Loc, metatype, existentialMetatypeType), - LastConformance(nullptr) { + NumConformances(conformances.size()) { if (conformances.empty()) return; - auto **offset = reinterpret_cast(this + 1); + auto offset = reinterpret_cast(this + 1); memcpy(offset, &conformances[0], - conformances.size() * sizeof(ProtocolConformance *)); - LastConformance = &offset[conformances.size() - 1]; + conformances.size() * sizeof(ProtocolConformanceRef)); } InitExistentialMetatypeInst *InitExistentialMetatypeInst::create( SILDebugLocation *Loc, SILType existentialMetatypeType, SILValue metatype, - ArrayRef conformances, SILFunction *F) { + ArrayRef conformances, SILFunction *F) { SILModule &M = F->getModule(); unsigned size = sizeof(InitExistentialMetatypeInst); - size += conformances.size() * sizeof(ProtocolConformance *); + size += conformances.size() * sizeof(ProtocolConformanceRef); void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst)); - for (ProtocolConformance *conformance : conformances) - if (!M.lookUpWitnessTable(conformance, false).first) - declareWitnessTable(M, conformance); + for (ProtocolConformanceRef conformance : conformances) + declareWitnessTable(M, conformance); return ::new (buffer) InitExistentialMetatypeInst( Loc, existentialMetatypeType, metatype, conformances); } -ArrayRef +ArrayRef InitExistentialMetatypeInst::getConformances() const { - if (!LastConformance) - return ArrayRef(); // The first conformance is going to be at *this[1]; - auto **FirstConformance = reinterpret_cast( - const_cast(this) + 1); + auto *FirstConformance = + reinterpret_cast(this + 1); // Construct the protocol conformance list from the range of our conformances. - return ArrayRef(FirstConformance, - LastConformance.get() + 1); + return ArrayRef(FirstConformance, NumConformances); } diff --git a/lib/SIL/SILLocation.cpp b/lib/SIL/SILLocation.cpp index d0539d9ef9448..043c49d8434e1 100644 --- a/lib/SIL/SILLocation.cpp +++ b/lib/SIL/SILLocation.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index b19c0e9ac7582..936f37cf7d2ea 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,7 +14,6 @@ #include "swift/SIL/SILModule.h" #include "Linker.h" #include "swift/SIL/SILDebugScope.h" -#include "swift/SIL/SILExternalSource.h" #include "swift/SIL/SILVisitor.h" #include "swift/Serialization/SerializedSILLoader.h" #include "swift/SIL/SILValue.h" @@ -27,30 +26,6 @@ using namespace swift; using namespace Lowering; -namespace swift { - /// SILTypeList - The uniqued backing store for the SILValue type list. This - /// is only exposed out of SILValue as an ArrayRef of types, so it should - /// never be used outside of libSIL. - class SILTypeList : public llvm::FoldingSetNode { - public: - unsigned NumTypes; - SILType Types[1]; // Actually variable sized. - - void Profile(llvm::FoldingSetNodeID &ID) const { - for (unsigned i = 0, e = NumTypes; i != e; ++i) { - ID.AddPointer(Types[i].getOpaqueValue()); - } - } - }; -} // end namespace swift. - -void SILExternalSource::anchor() { -} - -/// SILTypeListUniquingType - This is the type of the folding set maintained by -/// SILModule that these things are uniqued into. -typedef llvm::FoldingSet SILTypeListUniquingType; - class SILModule::SerializationCallback : public SerializedSILLoader::Callback { void didDeserialize(Module *M, SILFunction *fn) override { updateLinkage(fn); @@ -103,7 +78,6 @@ SILModule::SILModule(Module *SwiftModule, SILOptions &Options, : TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC), Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()), wholeModule(wholeModule), Options(Options), Types(*this) { - TypeListUniquing = new SILTypeListUniquingType(); } SILModule::~SILModule() { @@ -120,8 +94,6 @@ SILModule::~SILModule() { // at all. for (SILFunction &F : *this) F.dropAllReferences(); - - delete (SILTypeListUniquingType*)TypeListUniquing; } void *SILModule::allocate(unsigned Size, unsigned Align) const { @@ -143,7 +115,7 @@ SILWitnessTable * SILModule::createWitnessTableDeclaration(ProtocolConformance *C, SILLinkage linkage) { // If we are passed in a null conformance (a valid value), just return nullptr - // since we can not map a witness table to it. + // since we cannot map a witness table to it. if (!C) return nullptr; @@ -158,14 +130,22 @@ SILModule::createWitnessTableDeclaration(ProtocolConformance *C, std::pair> SILModule:: -lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily) { - // If we have a null conformance passed in (a legal value), just return +lookUpWitnessTable(ProtocolConformanceRef C, bool deserializeLazily) { + // If we have an abstract conformance passed in (a legal value), just return // nullptr. - ArrayRef Subs; - if (!C) - return {nullptr, Subs}; + if (!C.isConcrete()) + return {nullptr, {}}; + + return lookUpWitnessTable(C.getConcrete()); +} + +std::pair> +SILModule:: +lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily) { + assert(C && "null conformance passed to lookUpWitnessTable"); // Walk down to the base NormalProtocolConformance. + ArrayRef Subs; const ProtocolConformance *ParentC = C; while (!isa(ParentC)) { switch (ParentC->getKind()) { @@ -328,8 +308,7 @@ SILFunction *SILModule::getOrCreateFunction(SILLocation loc, SILDeclRef constant, ForDefinition_t forDefinition) { - SmallVector buffer; - auto name = constant.mangle(buffer); + auto name = constant.mangle(); auto constantType = Types.getConstantType(constant).castTo(); SILLinkage linkage = constant.getLinkage(forDefinition); @@ -378,15 +357,15 @@ SILFunction *SILModule::getOrCreateFunction(SILLocation loc, if (constant.isForeign && constant.isClangGenerated()) F->setForeignBody(HasForeignBody); - if (auto SemanticsA = - constant.getDecl()->getAttrs().getAttribute()) - F->setSemanticsAttr(SemanticsA->Value); + auto Attrs = constant.getDecl()->getAttrs(); + for (auto A : Attrs.getAttributes()) + F->addSemanticsAttr(cast(A)->Value); } F->setDeclContext(constant.hasDecl() ? constant.getDecl() : nullptr); // If this function has a self parameter, make sure that it has a +0 calling - // convention. This can not be done for general function types, since + // convention. This cannot be done for general function types, since // function_ref's SILFunctionTypes do not have archetypes associated with // it. CanSILFunctionType FTy = F->getLoweredFunctionType(); @@ -426,47 +405,6 @@ SILFunction *SILModule::getOrCreateFunction( inlineStrategy, EK, InsertBefore, DebugScope, DC); } -ArrayRef ValueBase::getTypes() const { - // No results. - if (TypeOrTypeList.isNull()) - return ArrayRef(); - // Arbitrary list of results. - if (auto *TypeList = TypeOrTypeList.dyn_cast()) - return ArrayRef(TypeList->Types, TypeList->NumTypes); - // Single result. - return TypeOrTypeList.get(); -} - - - -/// getSILTypeList - Get a uniqued pointer to a SIL type list. This can only -/// be used by SILValue. -SILTypeList *SILModule::getSILTypeList(ArrayRef Types) const { - assert(Types.size() > 1 && "Shouldn't use type list for 0 or 1 types"); - auto UniqueMap = (SILTypeListUniquingType*)TypeListUniquing; - - llvm::FoldingSetNodeID ID; - for (auto T : Types) { - ID.AddPointer(T.getOpaqueValue()); - } - - // If we already have this type list, just return it. - void *InsertPoint = 0; - if (SILTypeList *TypeList = UniqueMap->FindNodeOrInsertPos(ID, InsertPoint)) - return TypeList; - - // Otherwise, allocate a new one. - void *NewListP = BPA.Allocate(sizeof(SILTypeList)+ - sizeof(SILType)*(Types.size()-1), - alignof(SILTypeList)); - SILTypeList *NewList = new (NewListP) SILTypeList(); - NewList->NumTypes = Types.size(); - std::copy(Types.begin(), Types.end(), NewList->Types); - - UniqueMap->InsertNode(NewList, InsertPoint); - return NewList; -} - const IntrinsicInfo &SILModule::getIntrinsicInfo(Identifier ID) { unsigned OldSize = IntrinsicIDCache.size(); IntrinsicInfo &Info = IntrinsicIDCache[ID]; @@ -521,24 +459,20 @@ const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) { } SILFunction *SILModule::lookUpFunction(SILDeclRef fnRef) { - llvm::SmallString<32> name; - fnRef.mangle(name); + auto name = fnRef.mangle(); return lookUpFunction(name); } bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) { - return SILLinkerVisitor(*this, getSILLoader(), Mode, ExternalSource) - .processFunction(Fun); + return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Fun); } bool SILModule::linkFunction(SILDeclRef Decl, SILModule::LinkingMode Mode) { - return SILLinkerVisitor(*this, getSILLoader(), Mode, ExternalSource) - .processDeclRef(Decl); + return SILLinkerVisitor(*this, getSILLoader(), Mode).processDeclRef(Decl); } bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) { - return SILLinkerVisitor(*this, getSILLoader(), Mode, ExternalSource) - .processFunction(Name); + return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Name); } void SILModule::linkAllWitnessTables() { @@ -598,8 +532,7 @@ SILVTable *SILModule::lookUpVTable(const ClassDecl *C) { // If that fails, try to deserialize it. If that fails, return nullptr. SILVTable *Vtbl = - SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkAll, - ExternalSource) + SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkAll) .processClassDecl(C); if (!Vtbl) return nullptr; @@ -625,7 +558,7 @@ SerializedSILLoader *SILModule::getSILLoader() { /// required. Notice that we do not scan the class hierarchy, just the concrete /// class type. std::tuple> -SILModule::lookUpFunctionInWitnessTable(const ProtocolConformance *C, +SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C, SILDeclRef Member) { // Look up the witness table associated with our protocol conformance from the // SILModule. @@ -634,7 +567,7 @@ SILModule::lookUpFunctionInWitnessTable(const ProtocolConformance *C, // If no witness table was found, bail. if (!Ret.first) { DEBUG(llvm::dbgs() << " Failed speculative lookup of witness for: "; - if (C) C->dump(); else Member.dump()); + C.dump(); Member.dump()); return std::make_tuple(nullptr, nullptr, ArrayRef()); } diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 69ba2a9564914..d08617a6e48d6 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -55,7 +55,6 @@ struct ID { SILBasicBlock, SILUndef, SSAValue } Kind; unsigned Number; - int ResultNumber; // A stable ordering of ID objects. bool operator<(ID Other) const { @@ -63,8 +62,6 @@ struct ID { return true; if (Number < Other.Number) return true; - if (ResultNumber < Other.ResultNumber) - return true; return false; } }; @@ -123,8 +120,6 @@ static raw_ostream &operator<<(raw_ostream &OS, ID i) { } OS << i.Number; - if (i.ResultNumber != -1) - OS << '#' << i.ResultNumber; return OS; } @@ -212,6 +207,10 @@ static void printFullContext(const DeclContext *Context, raw_ostream &Buffer) { // FIXME Buffer << ""; return; + case DeclContextKind::SubscriptDecl: + // FIXME + Buffer << ""; + return; } llvm_unreachable("bad decl context"); } @@ -330,7 +329,6 @@ static void print(raw_ostream &OS, SILValueCategory category) { switch (category) { case SILValueCategory::Object: return; case SILValueCategory::Address: OS << '*'; return; - case SILValueCategory::LocalStorage: OS << "*@local_storage "; return; } llvm_unreachable("bad value category!"); } @@ -427,7 +425,7 @@ class SILPrinter : public SILVisitor { ID getID(const SILBasicBlock *B); ID getID(SILValue V); IDAndType getIDAndType(SILValue V) { - return { getID(V), V.getType() }; + return { getID(V), V->getType() }; } //===--------------------------------------------------------------------===// @@ -459,7 +457,7 @@ class SILPrinter : public SILVisitor { if (!BB->bbarg_empty()) { for (auto I = BB->bbarg_begin(), E = BB->bbarg_end(); I != E; ++I) { SILValue V = *I; - if (V.use_empty()) + if (V->use_empty()) continue; *this << "// " << getID(V); PrintState.OS.PadToColumn(50); @@ -519,18 +517,125 @@ class SILPrinter : public SILVisitor { //===--------------------------------------------------------------------===// // SILInstruction Printing Logic + /// Print out the users of the SILValue \p V. Return true if we printed out + /// either an id or a use list. Return false otherwise. + bool printUsersOfSILValue(SILValue V) { + if (!V->hasValue()) { + PrintState.OS.PadToColumn(50); + *this << "// id: " << getID(V); + return true; + } + + if (V->use_empty()) + return false; + + PrintState.OS.PadToColumn(50); + *this << "// user"; + if (std::next(V->use_begin()) != V->use_end()) + *this << 's'; + *this << ": "; + + // Display the user ids sorted to give a stable use order in the printer's + // output. This makes diffing large sections of SIL significantly easier. + llvm::SmallVector UserIDs; + for (auto *Op : V->getUses()) + UserIDs.push_back(getID(Op->getUser())); + std::sort(UserIDs.begin(), UserIDs.end()); + + interleave(UserIDs.begin(), UserIDs.end(), [&](ID id) { *this << id; }, + [&] { *this << ", "; }); + return true; + } + + void printSILLocation(SILLocation L, SILModule &M, const SILDebugScope *DS, + bool printedSlashes) { + if (!L.isNull()) { + if (!printedSlashes) { + PrintState.OS.PadToColumn(50); + *this << "//"; + } + *this << " "; + + // To minimize output, only print the line and column number for + // everything but the first instruction. + L.getSourceLoc().printLineAndColumn(PrintState.OS, + M.getASTContext().SourceMgr); + + // Print the type of location. + switch (L.getKind()) { + case SILLocation::NoneKind: + assert(L.isAutoGenerated() && "This kind shouldn't be printed."); + break; + case SILLocation::RegularKind: + break; + case SILLocation::ReturnKind: + *this << ":return"; + break; + case SILLocation::ImplicitReturnKind: + *this << ":imp_return"; + break; + case SILLocation::InlinedKind: + *this << ":inlined"; + break; + case SILLocation::MandatoryInlinedKind: + *this << ":minlined"; + break; + case SILLocation::CleanupKind: + *this << ":cleanup"; + break; + case SILLocation::ArtificialUnreachableKind: + *this << ":art_unreach"; + break; + case SILLocation::SILFileKind: + *this << ":sil"; + break; + } + if (L.isAutoGenerated()) + *this << ":auto_gen"; + if (L.isInPrologue()) + *this << ":in_prologue"; + } + if (L.isNull()) { + if (!printedSlashes) { + PrintState.OS.PadToColumn(50); + *this << "//"; + } + if (L.isInTopLevel()) + *this << " top_level"; + else if (L.isAutoGenerated()) + *this << " auto_gen"; + else + *this << " no_loc"; + if (L.isInPrologue()) + *this << ":in_prologue"; + } + + // Print inlined-at location, if any. + if (DS) { + while (DS->InlinedCallSite) { + *this << ": perf_inlined_at "; + auto CallSite = DS->InlinedCallSite->Loc; + if (!CallSite.isNull()) + CallSite.getSourceLoc().print( + PrintState.OS, M.getASTContext().SourceMgr, LastBufferID); + else + *this << "?"; + DS = DS->InlinedCallSite; + } + } + } + void print(SILValue V) { if (auto *FRI = dyn_cast(V)) *this << " // function_ref " - << demangleSymbolAsString(FRI->getReferencedFunction()->getName()) - << "\n"; + << demangleSymbolAsString(FRI->getReferencedFunction()->getName()) + << "\n"; *this << " "; // Print result. if (V->hasValue()) { ID Name = getID(V); - Name.ResultNumber = -1; // Don't print subresult number. *this << Name << " = "; } @@ -538,103 +643,13 @@ class SILPrinter : public SILVisitor { visit(V); // Print users, or id for valueless instructions. - bool printedSlashes = false; - - if (!V->hasValue()) { - PrintState.OS.PadToColumn(50); - *this << "// id: " << getID(V); - printedSlashes = true; - } else if (!V->use_empty()) { - PrintState.OS.PadToColumn(50); - *this << "// user"; - if (std::next(V->use_begin()) != V->use_end()) - *this << 's'; - *this << ": "; - - // Display the user ids sorted to give a stable use order in the printer's - // output. This makes diffing large sections of SIL significantly easier. - llvm::SmallVector UserIDs; - for (auto *Op : V->getUses()) - UserIDs.push_back(getID(Op->getUser())); - std::sort(UserIDs.begin(), UserIDs.end()); - - interleave(UserIDs.begin(), UserIDs.end(), - [&] (ID id) { *this << id; }, - [&] { *this << ", "; }); - printedSlashes = true; - } + bool printedSlashes = printUsersOfSILValue(V); // Print SIL location. if (Verbose) { - if (SILInstruction *I = dyn_cast(V)) { - SILLocation L = I->getLoc(); - SILModule &M = I->getModule(); - if (!L.isNull()) { - if (!printedSlashes) { - PrintState.OS.PadToColumn(50); - *this << "//"; - } - *this << " "; - - // To minimize output, only print the line and column number for - // everything but the first instruction. - L.getSourceLoc().printLineAndColumn(PrintState.OS, - M.getASTContext().SourceMgr); - - // Print the type of location. - switch (L.getKind()) { - case SILLocation::NoneKind : - assert(L.isAutoGenerated() && "This kind shouldn't be printed."); - break; - case SILLocation::RegularKind : - break; - case SILLocation::ReturnKind : - *this << ":return"; break; - case SILLocation::ImplicitReturnKind : - *this << ":imp_return"; break; - case SILLocation::InlinedKind : - *this << ":inlined"; break; - case SILLocation::MandatoryInlinedKind : - *this << ":minlined"; break; - case SILLocation::CleanupKind : - *this << ":cleanup"; break; - case SILLocation::ArtificialUnreachableKind : - *this << ":art_unreach"; break; - case SILLocation::SILFileKind : - *this << ":sil"; break; - } - if (L.isAutoGenerated()) - *this << ":auto_gen"; - if (L.isInPrologue()) - *this << ":in_prologue"; - } - if (L.isNull()) { - if (!printedSlashes) { - PrintState.OS.PadToColumn(50); - *this << "//"; - } - if (L.isInTopLevel()) - *this << " top_level"; - else if (L.isAutoGenerated()) - *this << " auto_gen"; - else - *this << " no_loc"; - if (L.isInPrologue()) - *this << ":in_prologue"; - } - - // Print inlined-at location, if any. - if (auto DS = I->getDebugScope()) - while (DS->InlinedCallSite) { - *this << ": perf_inlined_at "; - auto CallSite = DS->InlinedCallSite->Loc; - if (!CallSite.isNull()) - CallSite.getSourceLoc(). - print(PrintState.OS, M.getASTContext().SourceMgr, LastBufferID); - else - *this << "?"; - DS = DS->InlinedCallSite; - } + if (auto *I = dyn_cast(V)) { + printSILLocation(I->getLoc(), I->getModule(), I->getDebugScope(), + printedSlashes); } } @@ -751,7 +766,7 @@ class SILPrinter : public SILVisitor { interleave(AI->getArguments(), [&](const SILValue &arg) { *this << getID(arg); }, [&] { *this << ", "; }); - *this << ") : " << AI->getCallee().getType(); + *this << ") : " << AI->getCallee()->getType(); } void visitTryApplyInst(TryApplyInst *AI) { @@ -762,7 +777,7 @@ class SILPrinter : public SILVisitor { interleave(AI->getArguments(), [&](const SILValue &arg) { *this << getID(arg); }, [&] { *this << ", "; }); - *this << ") : " << AI->getCallee().getType(); + *this << ") : " << AI->getCallee()->getType(); *this << ", normal " << getID(AI->getNormalBB()); *this << ", error " << getID(AI->getErrorBB()); } @@ -776,7 +791,7 @@ class SILPrinter : public SILVisitor { interleave(CI->getArguments(), [&](const SILValue &arg) { *this << getID(arg); }, [&] { *this << ", "; }); - *this << ") : " << CI->getCallee().getType(); + *this << ") : " << CI->getCallee()->getType(); } void visitFunctionRefInst(FunctionRefInst *FRI) { @@ -800,6 +815,15 @@ class SILPrinter : public SILVisitor { *this << BI->getType(); } + void visitAllocGlobalInst(AllocGlobalInst *AGI) { + *this << "alloc_global "; + if (AGI->getReferencedGlobal()) { + AGI->getReferencedGlobal()->printName(PrintState.OS); + } else { + *this << "<>"; + } + } + void visitGlobalAddrInst(GlobalAddrInst *GAI) { *this << "global_addr "; if (GAI->getReferencedGlobal()) { @@ -826,6 +850,7 @@ class SILPrinter : public SILVisitor { switch (kind) { case StringLiteralInst::Encoding::UTF8: return "utf8 "; case StringLiteralInst::Encoding::UTF16: return "utf16 "; + case StringLiteralInst::Encoding::ObjCSelector: return "objc_selector "; } llvm_unreachable("bad string literal encoding"); } @@ -1069,7 +1094,7 @@ class SILPrinter : public SILVisitor { // elements. bool SimpleType = true; for (auto &Elt : TI->getType().castTo()->getElements()) { - if (Elt.hasName() || Elt.isVararg() || Elt.hasInit()) { + if (Elt.hasName() || Elt.isVararg() || Elt.hasDefaultArg()) { SimpleType = false; break; } @@ -1177,7 +1202,7 @@ class SILPrinter : public SILVisitor { *this << ", "; *this << getIDAndType(WMI->getOperand()); } - *this << " : " << WMI->getType(0); + *this << " : " << WMI->getType(); } void visitDynamicMethodInst(DynamicMethodInst *DMI) { printMethodInst(DMI, DMI->getOperand(), "dynamic_method"); @@ -1314,6 +1339,10 @@ class SILPrinter : public SILVisitor { void visitProjectBoxInst(ProjectBoxInst *PBI) { *this << "project_box " << getIDAndType(PBI->getOperand()); } + void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *PEBI) { + *this << "project_existential_box " << PEBI->getValueType() + << " in " << getIDAndType(PEBI->getOperand()); + } void visitCondFailInst(CondFailInst *FI) { *this << "cond_fail " << getIDAndType(FI->getOperand()); @@ -1457,24 +1486,20 @@ ID SILPrinter::getID(const SILBasicBlock *Block) { BlocksToIDMap[&B] = idx++; } - ID R = { ID::SILBasicBlock, BlocksToIDMap[Block], -1 }; + ID R = { ID::SILBasicBlock, BlocksToIDMap[Block] }; return R; } ID SILPrinter::getID(SILValue V) { if (isa(V)) - return { ID::SILUndef, 0, 0 }; + return { ID::SILUndef, 0 }; // Lazily initialize the instruction -> ID mapping. if (ValueToIDMap.empty()) { V->getParentBB()->getParent()->numberValues(ValueToIDMap); } - int ResultNumber = -1; - if (V.getDef()->getTypes().size() > 1) - ResultNumber = V.getResultNumber(); - - ID R = { ID::SSAValue, ValueToIDMap[V.getDef()], ResultNumber }; + ID R = { ID::SSAValue, ValueToIDMap[V] }; return R; } @@ -1486,14 +1511,6 @@ void SILBasicBlock::printAsOperand(raw_ostream &OS, bool PrintType) { // Printing for SILInstruction, SILBasicBlock, SILFunction, and SILModule //===----------------------------------------------------------------------===// -void SILValue::dump() const { - print(llvm::errs()); -} - -void SILValue::print(raw_ostream &OS) const { - SILPrinter(OS).print(*this); -} - void ValueBase::dump() const { print(llvm::errs()); } @@ -1586,8 +1603,8 @@ void SILFunction::print(llvm::raw_ostream &OS, bool Verbose, if (getEffectsKind() == EffectsKind::ReadWrite) OS << "[readwrite] "; - if (!getSemanticsAttr().empty()) - OS << "[_semantics \"" << getSemanticsAttr() << "\"] "; + for (auto &Attr : getSemanticsAttrs()) + OS << "[_semantics \"" << Attr << "\"] "; printName(OS); OS << " : $"; @@ -1929,8 +1946,8 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const { OS << "associated_type_protocol (" << assocProtoWitness.Requirement->getName() << ": " << assocProtoWitness.Protocol->getName() << "): "; - if (assocProtoWitness.Witness) - assocProtoWitness.Witness->printName(OS, Options); + if (assocProtoWitness.Witness.isConcrete()) + assocProtoWitness.Witness.getConcrete()->printName(OS, Options); else OS << "dependent"; break; diff --git a/lib/SIL/SILSuccessor.cpp b/lib/SIL/SILSuccessor.cpp index 52f504c2b4d4b..b52890484926d 100644 --- a/lib/SIL/SILSuccessor.cpp +++ b/lib/SIL/SILSuccessor.cpp @@ -1,8 +1,8 @@ -//===--- SILSuccessor.cpp - Implementation of SILSuccessor.h ---------------==// +//===--- SILSuccessor.cpp - Implementation of SILSuccessor.h --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp index 9cba539bf93c9..4a2754de6c78d 100644 --- a/lib/SIL/SILType.cpp +++ b/lib/SIL/SILType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -317,13 +317,6 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, SILModule &M) const { return SILType(loweredTy.getSwiftRValueType(), getCategory()); } -bool SILType::hasFixedLayout(SILModule &M) const { - if (auto *NTD = getNominalOrBoundGenericNominal()) - return NTD->hasFixedLayout(M.getSwiftModule()); - - llvm_unreachable("hasFixedLayout on non-nominal types not implemented"); -} - /// True if the type, or the referenced type of an address type, is /// address-only. For example, it could be a resilient struct or something of /// unknown size. @@ -416,7 +409,7 @@ bool SILType::aggregateContainsRecord(SILType Record, SILModule &Mod) const { for (VarDecl *Var : S->getStoredProperties()) Worklist.push_back(Ty.getFieldType(Var, Mod)); - // If we have a class address, it is a pointer so it can not contain other + // If we have a class address, it is a pointer so it cannot contain other // types. // If we reached this point, then this type has no subrecords. Since it does @@ -443,13 +436,8 @@ OptionalTypeKind SILType::getOptionalTypeKind() const { SILType SILType::getAnyOptionalObjectType(SILModule &M, OptionalTypeKind &OTK) const { if (auto objectTy = getSwiftRValueType()->getAnyOptionalObjectType(OTK)) { - // Lower the payload type at the abstraction level of Optional's generic - // parameter. - auto archetype = getNominalOrBoundGenericNominal()->getGenericParams() - ->getPrimaryArchetypes()[0]; - auto loweredTy - = M.Types.getLoweredType(AbstractionPattern(archetype), objectTy); + = M.Types.getLoweredType(AbstractionPattern::getOpaque(), objectTy); return SILType(loweredTy.getSwiftRValueType(), getCategory()); } diff --git a/lib/SIL/SILVTable.cpp b/lib/SIL/SILVTable.cpp index 5e261d618ddfd..0ebead67b9896 100644 --- a/lib/SIL/SILVTable.cpp +++ b/lib/SIL/SILVTable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SIL/SILValue.cpp b/lib/SIL/SILValue.cpp index 942fbf576b3d2..9d7a3cda73a5f 100644 --- a/lib/SIL/SILValue.cpp +++ b/lib/SIL/SILValue.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,11 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "swift/SIL/Dominance.h" #include "swift/SIL/SILValue.h" -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBasicBlock.h" using namespace swift; @@ -34,166 +31,6 @@ static_assert(sizeof(SILValue) == sizeof(uintptr_t), // Utility Methods //===----------------------------------------------------------------------===// -void SILValue::replaceAllUsesWith(SILValue V) { - assert(*this != V && "Cannot RAUW a value with itself"); - assert(getType() == V.getType() && "Invalid type"); - while (!use_empty()) - (**use_begin()).set(V); -} - -static bool isRCIdentityPreservingCast(ValueKind Kind) { - switch (Kind) { - case ValueKind::UpcastInst: - case ValueKind::UncheckedRefCastInst: - case ValueKind::UncheckedRefCastAddrInst: - case ValueKind::UnconditionalCheckedCastInst: - case ValueKind::RefToBridgeObjectInst: - case ValueKind::BridgeObjectToRefInst: - return true; - default: - return false; - } -} - -/// Return the underlying SILValue after stripping off identity SILArguments if -/// we belong to a BB with one predecessor. -static SILValue stripSinglePredecessorArgs(SILValue V) { - while (true) { - auto *A = dyn_cast(V); - if (!A) - return V; - - SILBasicBlock *BB = A->getParent(); - - // First try and grab the single predecessor of our parent BB. If we don't - // have one, bail. - SILBasicBlock *Pred = BB->getSinglePredecessor(); - if (!Pred) - return V; - - // Then grab the terminator of Pred... - TermInst *PredTI = Pred->getTerminator(); - - // And attempt to find our matching argument. - if (auto *BI = dyn_cast(PredTI)) { - V = BI->getArg(A->getIndex()); - continue; - } - - if (auto *CBI = dyn_cast(PredTI)) { - if (SILValue Arg = CBI->getArgForDestBB(BB, A)) { - V = Arg; - continue; - } - } - - return V; - } -} - -SILValue SILValue::stripCasts() { - SILValue V = *this; - - while (true) { - V = stripSinglePredecessorArgs(V); - - auto K = V->getKind(); - if (isRCIdentityPreservingCast(K) - || K == ValueKind::UncheckedTrivialBitCastInst - || K == ValueKind::MarkDependenceInst) { - V = cast(V.getDef())->getOperand(0); - continue; - } - - return V; - } -} - -SILValue SILValue::stripUpCasts() { - assert(getType().isClassOrClassMetatype() && - "Expected class or class metatype!"); - - SILValue V = stripSinglePredecessorArgs(*this); - - while (isa(V)) - V = stripSinglePredecessorArgs(cast(V)->getOperand()); - - return V; -} - -SILValue SILValue::stripClassCasts() { - SILValue V = *this; - while (true) { - if (auto *UI = dyn_cast(V)) { - V = UI->getOperand(); - continue; - } - - if (auto *UCCI = dyn_cast(V)) { - V = UCCI->getOperand(); - continue; - } - - return V; - } -} - - -SILValue SILValue::stripAddressProjections() { - SILValue V = *this; - - while (true) { - V = stripSinglePredecessorArgs(V); - - switch (V->getKind()) { - case ValueKind::StructElementAddrInst: - case ValueKind::TupleElementAddrInst: - case ValueKind::RefElementAddrInst: - case ValueKind::UncheckedTakeEnumDataAddrInst: - V = cast(V.getDef())->getOperand(0); - continue; - default: - return V; - } - } -} - -SILValue SILValue::stripValueProjections() { - SILValue V = *this; - - while (true) { - V = stripSinglePredecessorArgs(V); - - switch (V->getKind()) { - case ValueKind::StructExtractInst: - case ValueKind::TupleExtractInst: - V = cast(V.getDef())->getOperand(0); - continue; - default: - return V; - } - } -} - -SILValue SILValue::stripIndexingInsts() { - SILValue V = *this; - while (true) { - if (!isa(V.getDef())) - return V; - V = cast(V)->getBase(); - } -} - -SILValue SILValue::stripExpectIntrinsic() { - SILValue V = *this; - auto *BI = dyn_cast(V); - if (!BI) - return V; - if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::expect) - return V; - return BI->getArguments()[0]; -} - SILBasicBlock *ValueBase::getParentBB() { if (auto Inst = dyn_cast(this)) return Inst->getParent(); @@ -201,53 +38,3 @@ SILBasicBlock *ValueBase::getParentBB() { return Arg->getParent(); return nullptr; } - -void Operand::hoistAddressProjections(SILInstruction *InsertBefore, - DominanceInfo *DomTree) { - SILValue V = get(); - SILInstruction *Prev = nullptr; - auto *InsertPt = InsertBefore; - while (true) { - SILValue Incoming = stripSinglePredecessorArgs(V); - - // Forward the incoming arg from a single predeccessor. - if (V != Incoming) { - if (V == get()) { - // If we are the operand itself set the operand to the incoming - // argument. - set(Incoming); - V = Incoming; - } else { - // Otherwise, set the previous projections operand to the incoming - // argument. - assert(Prev && "Must have seen a projection"); - Prev->setOperand(0, Incoming); - V = Incoming; - } - } - - switch (V->getKind()) { - case ValueKind::StructElementAddrInst: - case ValueKind::TupleElementAddrInst: - case ValueKind::RefElementAddrInst: - case ValueKind::UncheckedTakeEnumDataAddrInst: { - auto *Inst = cast(V); - // We are done once the current projection dominates the insert point. - if (DomTree->dominates(Inst->getParent(), InsertBefore->getParent())) - return; - - // Move the current projection and memorize it for the next iteration. - Prev = Inst; - Inst->moveBefore(InsertPt); - InsertPt = Inst; - V = Inst->getOperand(0); - continue; - } - default: - assert(DomTree->dominates(V->getParentBB(), InsertBefore->getParent()) && - "The projected value must dominate the insertion point"); - return; - } - } -} - diff --git a/lib/SIL/SILValueProjection.cpp b/lib/SIL/SILValueProjection.cpp index a25f6b75cbe64..811830db7e653 100644 --- a/lib/SIL/SILValueProjection.cpp +++ b/lib/SIL/SILValueProjection.cpp @@ -1,8 +1,8 @@ -//===------------------------- SILValueProjection.cpp ---------------------===// +//===--- SILValueProjection.cpp -------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,6 +12,7 @@ #define DEBUG_TYPE "sil-value-projection" #include "swift/SIL/SILValueProjection.h" +#include "swift/SIL/InstructionUtils.h" #include "llvm/Support/Debug.h" using namespace swift; @@ -30,13 +31,13 @@ static inline void removeLSLocations(LSLocationValueMap &Values, // SILValue Projection //===----------------------------------------------------------------------===// -void SILValueProjection::print() const { +void SILValueProjection::print(SILModule *Mod) { llvm::outs() << Base; - llvm::outs() << Path.getValue(); + Path.getValue().print(llvm::outs(), *Mod); } SILValue SILValueProjection::createExtract(SILValue Base, - Optional &Path, + const Optional &Path, SILInstruction *Inst, bool IsValExt) { // If we found a projection path, but there are no projections, then the two @@ -48,16 +49,21 @@ SILValue SILValueProjection::createExtract(SILValue Base, // from our list of address projections. SILValue LastExtract = Base; SILBuilder Builder(Inst); + Builder.setCurrentDebugScope(Inst->getFunction()->getDebugScope()); + + // We use an auto-generated SILLocation for now. + // TODO: make the sil location more precise. + SILLocation Loc = RegularLocation::getAutoGeneratedLocation(); // Construct the path! - for (auto PI = Path->rbegin(), PE = Path->rend(); PI != PE; ++PI) { + for (auto PI = Path->begin(), PE = Path->end(); PI != PE; ++PI) { if (IsValExt) { LastExtract = - PI->createValueProjection(Builder, Inst->getLoc(), LastExtract).get(); + PI->createObjectProjection(Builder, Loc, LastExtract).get(); continue; } LastExtract = - PI->createAddrProjection(Builder, Inst->getLoc(), LastExtract).get(); + PI->createAddressProjection(Builder, Loc, LastExtract).get(); } // Return the last extract we created. @@ -73,8 +79,7 @@ void LSValue::expand(SILValue Base, SILModule *M, LSValueList &Vals, // To expand a LSValue to its indivisible parts, we first get the // address projection paths from the accessed type to each indivisible field, // i.e. leaf nodes, then we append these projection paths to the Base. - for (const auto &P : - TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) { + for (const auto &P : TE->getTypeExpansion((*Base).getType(), M, TEKind::TELeaf)) { Vals.push_back(LSValue(Base, P.getValue())); } } @@ -90,10 +95,9 @@ SILValue LSValue::reduce(LSLocation &Base, SILModule *M, // First, get a list of all the leaf nodes and intermediate nodes for the // Base memory location. LSLocationList ALocs; - ProjectionPath &BasePath = Base.getPath().getValue(); - for (const auto &P : - TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) { - ALocs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath)); + const NewProjectionPath &BasePath = Base.getPath().getValue(); + for (const auto &P : TE->getTypeExpansion(Base.getType(M), M, TEKind::TENode)) { + ALocs.push_back(LSLocation(Base.getBase(), BasePath, P.getValue())); } // Second, go from leaf nodes to their parents. This guarantees that at the @@ -108,22 +112,29 @@ SILValue LSValue::reduce(LSLocation &Base, SILModule *M, continue; // If this is a class reference type, we have reached end of the type tree. - if (I->getType().getClassOrBoundGenericClass()) + if (I->getType(M).getClassOrBoundGenericClass()) continue; // This is NOT a leaf node, we need to construct a value for it. - // + + // There is only 1 children node and its value's projection path is not + // empty, keep stripping it. + auto Iter = FirstLevel.begin(); + LSValue &FirstVal = Values[*Iter]; + if (FirstLevel.size() == 1 && !FirstVal.hasEmptyNewProjectionPath()) { + Values[*I] = FirstVal.stripLastLevelProjection(); + // We have a value for the parent, remove all the values for children. + removeLSLocations(Values, FirstLevel); + continue; + } + // If there are more than 1 children and all the children nodes have - // LSValues with the same base. we can get away by not extracting - // value - // for every single field. + // LSValues with the same base and non-empty projection path. we can get + // away by not extracting value for every single field. // // Simply create a new node with all the aggregated base value, i.e. // stripping off the last level projection. - // bool HasIdenticalValueBase = true; - auto Iter = FirstLevel.begin(); - LSValue &FirstVal = Values[*Iter]; SILValue FirstBase = FirstVal.getBase(); Iter = std::next(Iter); for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) { @@ -131,20 +142,23 @@ SILValue LSValue::reduce(LSLocation &Base, SILModule *M, HasIdenticalValueBase &= (FirstBase == V.getBase()); } - if (HasIdenticalValueBase && - (FirstLevel.size() > 1 || !FirstVal.hasEmptyProjectionPath())) { + if (FirstLevel.size() > 1 && HasIdenticalValueBase && + !FirstVal.hasEmptyNewProjectionPath()) { Values[*I] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeLSLocations(Values, FirstLevel); continue; } - // In 2 cases do we need aggregation. + // In 3 cases do we need aggregation. // - // 1. If there is only 1 child and we can not strip off any projections, + // 1. If there is only 1 child and we cannot strip off any projections, // that means we need to create an aggregation. + // + // 2. There are multiple children and they have the same base, but empty + // projection paths. // - // 2. Children have values from different bases, We need to create + // 3. Children have values from different bases, We need to create // extractions and aggregation in this case. // llvm::SmallVector Vals; @@ -152,11 +166,17 @@ SILValue LSValue::reduce(LSLocation &Base, SILModule *M, Vals.push_back(Values[X].materialize(InsertPt)); } SILBuilder Builder(InsertPt); + Builder.setCurrentDebugScope(InsertPt->getFunction()->getDebugScope()); + + // We use an auto-generated SILLocation for now. + // TODO: make the sil location more precise. NullablePtr AI = Projection::createAggFromFirstLevelProjections( - Builder, InsertPt->getLoc(), I->getType(), Vals); + Builder, RegularLocation::getAutoGeneratedLocation(), + I->getType(M).getObjectType(), + Vals); // This is the Value for the current node. - ProjectionPath P; + NewProjectionPath P(Base.getType(M)); Values[*I] = LSValue(SILValue(AI.get()), P); removeLSLocations(Values, FirstLevel); @@ -171,60 +191,16 @@ SILValue LSValue::reduce(LSLocation &Base, SILModule *M, return Values.begin()->second.materialize(InsertPt); } - -void LSValue::enumerateLSValue(SILModule *M, SILValue Val, - std::vector &Vault, - LSValueIndexMap &ValToBit, - TypeExpansionAnalysis *TE) { - // Expand the given Mem into individual fields and add them to the - // locationvault. - LSValueList Vals; - LSValue::expand(Val, M, Vals, TE); - for (auto &Val : Vals) { - ValToBit[Val] = Vault.size(); - Vault.push_back(Val); - } -} - -void LSValue::enumerateLSValues(SILFunction &F, std::vector &Vault, - LSValueIndexMap &ValToBit, - TypeExpansionAnalysis *TE) { - // Enumerate all LSValues created or used by the loads or stores. - // - // TODO: process more instructions as we process more instructions in - // processInstruction. - // - SILValue Op; - for (auto &B : F) { - for (auto &I : B) { - if (auto *LI = dyn_cast(&I)) { - enumerateLSValue(&I.getModule(), SILValue(LI), Vault, ValToBit, TE); - } else if (auto *SI = dyn_cast(&I)) { - enumerateLSValue(&I.getModule(), SI->getSrc(), Vault, ValToBit, TE); - } - } - } - - // Lastly, push in the covering value LSValue. - ValToBit[LSValue(true)] = Vault.size(); - Vault.push_back(LSValue(true)); -} - //===----------------------------------------------------------------------===// // Memory Location //===----------------------------------------------------------------------===// -void LSLocation::initialize(SILValue Dest) { - Base = getUnderlyingObject(Dest); - Path = ProjectionPath::getAddrProjectionPath(Base, Dest); -} - bool LSLocation::isMustAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA) { // If the bases are not must-alias, the locations may not alias. if (!AA->isMustAlias(Base, RHS.getBase())) return false; - // If projection paths are different, then the locations can not alias. + // If projection paths are different, then the locations cannot alias. if (!hasIdenticalProjectionPath(RHS)) return false; return true; @@ -232,7 +208,7 @@ bool LSLocation::isMustAliasLSLocation(const LSLocation &RHS, bool LSLocation::isMayAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA) { - // If the bases do not alias, then the locations can not alias. + // If the bases do not alias, then the locations cannot alias. if (AA->isNoAlias(Base, RHS.getBase())) return false; // If one projection path is a prefix of another, then the locations @@ -242,20 +218,37 @@ bool LSLocation::isMayAliasLSLocation(const LSLocation &RHS, return true; } + +bool LSLocation::isNonEscapingLocalLSLocation(SILFunction *Fn, + EscapeAnalysis *EA) { + // An alloc_stack is definitely dead at the end of the function. + if (isa(Base)) + return true; + // For other allocations we ask escape analysis. + auto *ConGraph = EA->getConnectionGraph(Fn); + if (isa(Base)) { + auto *Node = ConGraph->getNodeOrNull(Base, EA); + if (Node && !Node->escapes()) { + return true; + } + } + return false; +} + void LSLocation::getFirstLevelLSLocations(LSLocationList &Locs, SILModule *Mod) { - SILType Ty = getType(); - llvm::SmallVector Out; - Projection::getFirstLevelAddrProjections(Ty, *Mod, Out); + SILType Ty = getType(Mod); + llvm::SmallVector Out; + NewProjection::getFirstLevelProjections(Ty, *Mod, Out); for (auto &X : Out) { - ProjectionPath P; - P.append(X); + NewProjectionPath P((*Base).getType()); P.append(Path.getValue()); + P.append(X); Locs.push_back(LSLocation(Base, P)); } } -void LSLocation::expand(LSLocation &Base, SILModule *M, LSLocationList &Locs, +void LSLocation::expand(LSLocation Base, SILModule *M, LSLocationList &Locs, TypeExpansionAnalysis *TE) { // To expand a memory location to its indivisible parts, we first get the // address projection paths from the accessed type to each indivisible field, @@ -263,22 +256,20 @@ void LSLocation::expand(LSLocation &Base, SILModule *M, LSLocationList &Locs, // // Construct the LSLocation by appending the projection path from the // accessed node to the leaf nodes. - ProjectionPath &BasePath = Base.getPath().getValue(); - for (const auto &P : - TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) { - Locs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath)); + const NewProjectionPath &BasePath = Base.getPath().getValue(); + for (const auto &P : TE->getTypeExpansion(Base.getType(M), M, TEKind::TELeaf)) { + Locs.push_back(LSLocation(Base.getBase(), BasePath, P.getValue())); } } -void LSLocation::reduce(LSLocation &Base, SILModule *M, LSLocationSet &Locs, +void LSLocation::reduce(LSLocation Base, SILModule *M, LSLocationSet &Locs, TypeExpansionAnalysis *TE) { // First, construct the LSLocation by appending the projection path from the // accessed node to the leaf nodes. LSLocationList Nodes; - ProjectionPath &BasePath = Base.getPath().getValue(); - for (const auto &P : - TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) { - Nodes.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath)); + const NewProjectionPath &BasePath = Base.getPath().getValue(); + for (const auto &P : TE->getTypeExpansion(Base.getType(M), M, TEKind::TENode)) { + Nodes.push_back(LSLocation(Base.getBase(), BasePath, P.getValue())); } // Second, go from leaf nodes to their parents. This guarantees that at the @@ -291,7 +282,7 @@ void LSLocation::reduce(LSLocation &Base, SILModule *M, LSLocationSet &Locs, continue; // If this is a class reference type, we have reached end of the type tree. - if (I->getType().getClassOrBoundGenericClass()) + if (I->getType(M).getClassOrBoundGenericClass()) continue; // This is NOT a leaf node, check whether all its first level children are @@ -310,45 +301,57 @@ void LSLocation::reduce(LSLocation &Base, SILModule *M, LSLocationSet &Locs, } } - void LSLocation::enumerateLSLocation(SILModule *M, SILValue Mem, - std::vector &LV, - LSLocationIndexMap &BM, - TypeExpansionAnalysis *TE) { + std::vector &Locations, + LSLocationIndexMap &IndexMap, + LSLocationBaseMap &BaseMap, + TypeExpansionAnalysis *TypeCache) { + // We have processed this SILValue before. + if (BaseMap.find(Mem) != BaseMap.end()) + return; + // Construct a Location to represent the memory written by this instruction. - LSLocation L(Mem); + SILValue UO = getUnderlyingObject(Mem); + LSLocation L(UO, NewProjectionPath::getProjectionPath(UO, Mem)); // If we cant figure out the Base or Projection Path for the memory location, // simply ignore it for now. if (!L.isValid()) return; + // Record the SILValue to location mapping. + BaseMap[Mem] = L; + // Expand the given Mem into individual fields and add them to the // locationvault. LSLocationList Locs; - LSLocation::expand(L, M, Locs, TE); + LSLocation::expand(L, M, Locs, TypeCache); for (auto &Loc : Locs) { - BM[Loc] = LV.size(); - LV.push_back(Loc); + if (IndexMap.find(Loc) != IndexMap.end()) + continue; + IndexMap[Loc] = Locations.size(); + Locations.push_back(Loc); } + } void LSLocation::enumerateLSLocations(SILFunction &F, - std::vector &LV, - LSLocationIndexMap &BM, - TypeExpansionAnalysis *TE) { + std::vector &Locations, + LSLocationIndexMap &IndexMap, + LSLocationBaseMap &BaseMap, + TypeExpansionAnalysis *TypeCache) { // Enumerate all locations accessed by the loads or stores. - // - // TODO: process more instructions as we process more instructions in - // processInstruction. - // - SILValue Op; for (auto &B : F) { for (auto &I : B) { if (auto *LI = dyn_cast(&I)) { - enumerateLSLocation(&I.getModule(), LI->getOperand(), LV, BM, TE); - } else if (auto *SI = dyn_cast(&I)) { - enumerateLSLocation(&I.getModule(), SI->getDest(), LV, BM, TE); + enumerateLSLocation(&I.getModule(), LI->getOperand(), Locations, + IndexMap, BaseMap, TypeCache); + continue; + } + if (auto *SI = dyn_cast(&I)) { + enumerateLSLocation(&I.getModule(), SI->getDest(), Locations, + IndexMap, BaseMap, TypeCache); + continue; } } } diff --git a/lib/SIL/Verifier.cpp b/lib/SIL/SILVerifier.cpp similarity index 88% rename from lib/SIL/Verifier.cpp rename to lib/SIL/SILVerifier.cpp index 7d93a129a8c86..80c804085f16e 100644 --- a/lib/SIL/Verifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -139,7 +139,7 @@ class SILVerifier : public SILVerifierBase { template typename CanTypeWrapperTraits::type _requireObjectType(SILValue value, const Twine &valueDescription, const char *typeName) { - return _requireObjectType(value.getType(), valueDescription, typeName); + return _requireObjectType(value->getType(), valueDescription, typeName); } #define requireObjectType(type, value, valueDescription) \ _requireObjectType(value, valueDescription, #type) @@ -158,7 +158,7 @@ class SILVerifier : public SILVerifierBase { typename CanTypeWrapperTraits::type _forbidObjectType(SILValue value, const Twine &valueDescription, const char *typeName) { - return _forbidObjectType(value.getType(), valueDescription, typeName); + return _forbidObjectType(value->getType(), valueDescription, typeName); } #define forbidObjectType(type, value, valueDescription) \ _forbidObjectType(value, valueDescription, #type) @@ -166,8 +166,8 @@ class SILVerifier : public SILVerifierBase { // Require that the operand is a non-optional, non-unowned reference-counted // type. void requireReferenceValue(SILValue value, const Twine &valueDescription) { - require(value.getType().isObject(), valueDescription +" must be an object"); - require(value.getType().isReferenceCounted(F.getModule()), + require(value->getType().isObject(), valueDescription +" must be an object"); + require(value->getType().isReferenceCounted(F.getModule()), valueDescription + " must have reference semantics"); forbidObjectType(UnownedStorageType, value, valueDescription); } @@ -176,9 +176,9 @@ class SILVerifier : public SILVerifierBase { // thereof. void requireReferenceOrOptionalReferenceValue(SILValue value, const Twine &valueDescription) { - require(value.getType().isObject(), valueDescription +" must be an object"); + require(value->getType().isObject(), valueDescription +" must be an object"); - auto objectTy = value.getType(); + auto objectTy = value->getType(); OptionalTypeKind otk; if (auto optObjTy = objectTy.getAnyOptionalObjectType(F.getModule(), otk)) { objectTy = optObjTy; @@ -193,19 +193,10 @@ class SILVerifier : public SILVerifierBase { void requireReferenceStorageCapableValue(SILValue value, const Twine &valueDescription) { requireReferenceOrOptionalReferenceValue(value, valueDescription); - require(!value.getType().is(), + require(!value->getType().is(), valueDescription + " cannot apply to a function type"); } - // Require that the operand is a reference-counted type, or potentially an - // optional thereof. - void requireRetainablePointerValue(SILValue value, - const Twine &valueDescription) { - require(value.getType().isObject(), valueDescription +" must be an object"); - require(value.getType().hasRetainablePointerRepresentation(), - valueDescription + " must have retainable pointer representation"); - } - /// Assert that two types are equal. void requireSameType(SILType type1, SILType type2, const Twine &complaint) { _require(type1 == type2, complaint, [&] { @@ -439,7 +430,7 @@ class SILVerifier : public SILVerifierBase { } void visitSILArgument(SILArgument *arg) { - checkLegalTypes(arg->getFunction(), arg); + checkLegalType(arg->getFunction(), arg); } void visitSILInstruction(SILInstruction *I) { @@ -449,7 +440,7 @@ class SILVerifier : public SILVerifierBase { // Check the SILLLocation attached to the instruction. checkInstructionsSILLocation(I); - checkLegalTypes(I->getFunction(), I); + checkLegalType(I->getFunction(), I); } void checkSILInstruction(SILInstruction *I) { @@ -488,7 +479,7 @@ class SILVerifier : public SILVerifierBase { // Verify some basis structural stuff about an instruction's operands. for (auto &operand : I->getAllOperands()) { - require(operand.get().isValid(), "instruction has null operand"); + require(operand.get(), "instruction has null operand"); if (auto *valueI = dyn_cast(operand.get())) { require(valueI->getParent(), @@ -514,7 +505,7 @@ class SILVerifier : public SILVerifierBase { // Make sure that if operand is generic that its primary archetypes match // the function context. - checkLegalTypes(I->getFunction(), operand.get().getDef()); + checkLegalType(I->getFunction(), operand.get()); } } @@ -573,8 +564,8 @@ class SILVerifier : public SILVerifierBase { /// Check that the types of this value producer are all legal in the function /// context in which it exists. - void checkLegalTypes(SILFunction *F, ValueBase *value) { - for (auto type : value->getTypes()) { + void checkLegalType(SILFunction *F, ValueBase *value) { + if (SILType type = value->getType()) { checkLegalType(F, type); } } @@ -618,13 +609,8 @@ class SILVerifier : public SILVerifierBase { } void checkAllocStackInst(AllocStackInst *AI) { - require(AI->getContainerResult().getType().isLocalStorage(), - "first result of alloc_stack must be local storage"); - require(AI->getAddressResult().getType().isAddress(), - "second result of alloc_stack must be an address type"); - require(AI->getContainerResult().getType().getSwiftRValueType() - == AI->getElementType().getSwiftRValueType(), - "container storage must be for allocated type"); + require(AI->getType().isAddress(), + "result of alloc_stack must be an address type"); // Scan the parent block of AI and check that the users of AI inside this // block are inside the lifetime of the allocated memory. @@ -632,11 +618,11 @@ class SILVerifier : public SILVerifierBase { bool Allocated = true; for (auto Inst = AI->getIterator(), E = SBB->end(); Inst != E; ++Inst) { if (LoadInst *LI = dyn_cast(Inst)) - if (LI->getOperand().getDef() == AI) + if (LI->getOperand() == AI) require(Allocated, "AllocStack used by Load outside its lifetime"); if (StoreInst *SI = dyn_cast(Inst)) - if (SI->getDest().getDef() == AI) + if (SI->getDest() == AI) require(Allocated, "AllocStack used by Store outside its lifetime"); if (DeallocStackInst *DSI = dyn_cast(Inst)) @@ -658,9 +644,9 @@ class SILVerifier : public SILVerifierBase { void checkAllocRefDynamicInst(AllocRefDynamicInst *ARDI) { requireReferenceValue(ARDI, "Result of alloc_ref_dynamic"); - require(ARDI->getOperand().getType().is(), + require(ARDI->getOperand()->getType().is(), "operand of alloc_ref_dynamic must be of metatype type"); - auto metaTy = ARDI->getOperand().getType().castTo(); + auto metaTy = ARDI->getOperand()->getType().castTo(); require(metaTy->hasRepresentation(), "operand of alloc_ref_dynamic must have a metatype representation"); if (ARDI->isObjC()) { @@ -708,7 +694,7 @@ class SILVerifier : public SILVerifierBase { // Then make sure that we have a type that can be substituted for the // callee. auto substTy = checkApplySubstitutions(site.getSubstitutions(), - site.getCallee().getType()); + site.getCallee()->getType()); require(site.getOrigCalleeType()->getRepresentation() == site.getSubstCalleeType()->getRepresentation(), "calling convention difference between types"); @@ -725,7 +711,7 @@ class SILVerifier : public SILVerifierBase { substTy->getParameters().size(), "apply doesn't have right number of arguments for function"); for (size_t i = 0, size = site.getArguments().size(); i < size; ++i) { - requireSameType(site.getArguments()[i].getType(), + requireSameType(site.getArguments()[i]->getType(), substTy->getParameters()[i].getSILType(), "operand of 'apply' doesn't match function input type"); } @@ -748,7 +734,7 @@ class SILVerifier : public SILVerifierBase { // Check that if the apply is of a noreturn callee, make sure that an // unreachable is the next instruction. if (AI->getModule().getStage() == SILStage::Raw || - !AI->getCallee().getType().getAs()->isNoReturn()) + !AI->getCallee()->getType().getAs()->isNoReturn()) return; require(isa(std::next(SILBasicBlock::iterator(AI))), "No return apply without an unreachable as a next instruction."); @@ -834,7 +820,7 @@ class SILVerifier : public SILVerifierBase { } auto substTy = checkApplySubstitutions(PAI->getSubstitutions(), - PAI->getCallee().getType()); + PAI->getCallee()->getType()); require(!PAI->getSubstCalleeType()->isPolymorphic(), "substituted callee type should not be generic"); @@ -855,7 +841,7 @@ class SILVerifier : public SILVerifierBase { substTy->getParameters().size() - PAI->getArguments().size(); for (unsigned i = 0, size = PAI->getArguments().size(); i < size; ++i) { - require(PAI->getArguments()[i].getType() + require(PAI->getArguments()[i]->getType() == substTy->getParameters()[i + offset].getSILType(), "applied argument types do not match suffix of function type's " "inputs"); @@ -933,6 +919,16 @@ class SILVerifier : public SILVerifierBase { verifySILFunctionType(fnType); } + void checkAllocGlobalInst(AllocGlobalInst *AGI) { + if (F.isFragile()) { + SILGlobalVariable *RefG = AGI->getReferencedGlobal(); + require(RefG->isFragile() + || isValidLinkageForFragileRef(RefG->getLinkage()), + "alloc_global inside fragile function cannot " + "reference a private or hidden symbol"); + } + } + void checkGlobalAddrInst(GlobalAddrInst *GAI) { require(GAI->getType().isAddress(), "global_addr must have an address result type"); @@ -955,18 +951,18 @@ class SILVerifier : public SILVerifierBase { } void checkLoadInst(LoadInst *LI) { require(LI->getType().isObject(), "Result of load must be an object"); - require(LI->getOperand().getType().isAddress(), + require(LI->getOperand()->getType().isAddress(), "Load operand must be an address"); - require(LI->getOperand().getType().getObjectType() == LI->getType(), + require(LI->getOperand()->getType().getObjectType() == LI->getType(), "Load operand type and result type mismatch"); } void checkStoreInst(StoreInst *SI) { - require(SI->getSrc().getType().isObject(), + require(SI->getSrc()->getType().isObject(), "Can't store from an address source"); - require(SI->getDest().getType().isAddress(), + require(SI->getDest()->getType().isAddress(), "Must store to an address dest"); - require(SI->getDest().getType().getObjectType() == SI->getSrc().getType(), + require(SI->getDest()->getType().getObjectType() == SI->getSrc()->getType(), "Store operand type and dest type mismatch"); } @@ -974,15 +970,15 @@ class SILVerifier : public SILVerifierBase { SILValue Src = AI->getSrc(), Dest = AI->getDest(); require(AI->getModule().getStage() == SILStage::Raw, "assign instruction can only exist in raw SIL"); - require(Src.getType().isObject(), "Can't assign from an address source"); - require(Dest.getType().isAddress(), "Must store to an address dest"); - require(Dest.getType().getObjectType() == Src.getType(), + require(Src->getType().isObject(), "Can't assign from an address source"); + require(Dest->getType().isAddress(), "Must store to an address dest"); + require(Dest->getType().getObjectType() == Src->getType(), "Store operand type and dest type mismatch"); } void checkLoadUnownedInst(LoadUnownedInst *LUI) { require(LUI->getType().isObject(), "Result of load must be an object"); - auto PointerType = LUI->getOperand().getType(); + auto PointerType = LUI->getOperand()->getType(); auto PointerRVType = PointerType.getSwiftRValueType(); require(PointerType.isAddress() && PointerRVType->is(), @@ -993,15 +989,15 @@ class SILVerifier : public SILVerifierBase { } void checkStoreUnownedInst(StoreUnownedInst *SUI) { - require(SUI->getSrc().getType().isObject(), + require(SUI->getSrc()->getType().isObject(), "Can't store from an address source"); - auto PointerType = SUI->getDest().getType(); + auto PointerType = SUI->getDest()->getType(); auto PointerRVType = PointerType.getSwiftRValueType(); require(PointerType.isAddress() && PointerRVType->is(), "store_unowned address operand must be an unowned address"); require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() == - SUI->getSrc().getType().getSwiftType(), + SUI->getSrc()->getType().getSwiftType(), "Store operand type and dest type mismatch"); } @@ -1009,28 +1005,28 @@ class SILVerifier : public SILVerifierBase { require(LWI->getType().isObject(), "Result of load must be an object"); require(LWI->getType().getSwiftType()->getAnyOptionalObjectType(), "Result of weak load must be an optional"); - auto PointerType = LWI->getOperand().getType(); + auto PointerType = LWI->getOperand()->getType(); auto PointerRVType = PointerType.getSwiftRValueType(); require(PointerType.isAddress() && PointerRVType->is(), - "load_weak operand must be an weak address"); + "load_weak operand must be a weak address"); require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() == LWI->getType().getSwiftType(), "Load operand type and result type mismatch"); } void checkStoreWeakInst(StoreWeakInst *SWI) { - require(SWI->getSrc().getType().isObject(), + require(SWI->getSrc()->getType().isObject(), "Can't store from an address source"); - require(SWI->getSrc().getType().getSwiftType()->getAnyOptionalObjectType(), + require(SWI->getSrc()->getType().getSwiftType()->getAnyOptionalObjectType(), "store_weak must be of an optional value"); - auto PointerType = SWI->getDest().getType(); + auto PointerType = SWI->getDest()->getType(); auto PointerRVType = PointerType.getSwiftRValueType(); require(PointerType.isAddress() && PointerRVType->is(), - "store_weak address operand must be an weak address"); + "store_weak address operand must be a weak address"); require(PointerRVType->getReferenceStorageReferent()->getCanonicalType() == - SWI->getSrc().getType().getSwiftType(), + SWI->getSrc()->getType().getSwiftType(), "Store operand type and dest type mismatch"); } @@ -1038,80 +1034,108 @@ class SILVerifier : public SILVerifierBase { SILValue Src = MU->getOperand(); require(MU->getModule().getStage() == SILStage::Raw, "mark_uninitialized instruction can only exist in raw SIL"); - require(Src.getType().isAddress() || - Src.getType().getSwiftRValueType()->getClassOrBoundGenericClass(), + require(Src->getType().isAddress() || + Src->getType().getSwiftRValueType()->getClassOrBoundGenericClass(), "mark_uninitialized must be an address or class"); - require(Src.getType() == MU->getType(0),"operand and result type mismatch"); + require(Src->getType() == MU->getType(),"operand and result type mismatch"); } void checkMarkFunctionEscapeInst(MarkFunctionEscapeInst *MFE) { require(MFE->getModule().getStage() == SILStage::Raw, "mark_function_escape instruction can only exist in raw SIL"); for (auto Elt : MFE->getElements()) - require(Elt.getType().isAddress(), "MFE must refer to variable addrs"); + require(Elt->getType().isAddress(), "MFE must refer to variable addrs"); } void checkCopyAddrInst(CopyAddrInst *SI) { - require(SI->getSrc().getType().isAddress(), + require(SI->getSrc()->getType().isAddress(), "Src value should be lvalue"); - require(SI->getDest().getType().isAddress(), + require(SI->getDest()->getType().isAddress(), "Dest address should be lvalue"); - require(SI->getDest().getType() == SI->getSrc().getType(), + require(SI->getDest()->getType() == SI->getSrc()->getType(), "Store operand type and dest type mismatch"); } void checkRetainValueInst(RetainValueInst *I) { - require(I->getOperand().getType().isObject(), + require(I->getOperand()->getType().isObject(), "Source value should be an object value"); } void checkReleaseValueInst(ReleaseValueInst *I) { - require(I->getOperand().getType().isObject(), + require(I->getOperand()->getType().isObject(), "Source value should be an object value"); } void checkAutoreleaseValueInst(AutoreleaseValueInst *I) { - require(I->getOperand().getType().isObject(), + require(I->getOperand()->getType().isObject(), "Source value should be an object value"); // TODO: This instruction could in principle be generalized. - require(I->getOperand().getType().hasRetainablePointerRepresentation(), + require(I->getOperand()->getType().hasRetainablePointerRepresentation(), "Source value must be a reference type or optional thereof"); } void checkCopyBlockInst(CopyBlockInst *I) { - require(I->getOperand().getType().isBlockPointerCompatible(), + require(I->getOperand()->getType().isBlockPointerCompatible(), "operand of copy_block should be a block"); - require(I->getOperand().getType() == I->getType(), + require(I->getOperand()->getType() == I->getType(), "result of copy_block should be same type as operand"); } void checkAllocValueBufferInst(AllocValueBufferInst *I) { - require(I->getOperand().getType().isAddress(), + require(I->getOperand()->getType().isAddress(), "Operand value should be an address"); - require(I->getOperand().getType().is(), + require(I->getOperand()->getType().is(), "Operand value should be a Builtin.UnsafeValueBuffer"); } void checkProjectValueBufferInst(ProjectValueBufferInst *I) { - require(I->getOperand().getType().isAddress(), + require(I->getOperand()->getType().isAddress(), "Operand value should be an address"); - require(I->getOperand().getType().is(), + require(I->getOperand()->getType().is(), "Operand value should be a Builtin.UnsafeValueBuffer"); } void checkProjectBoxInst(ProjectBoxInst *I) { - require(I->getOperand().getType().isObject(), + require(I->getOperand()->getType().isObject(), "project_box operand should be a value"); - require(I->getOperand().getType().is(), + require(I->getOperand()->getType().is(), "project_box operand should be a @box type"); - require(I->getType() == I->getOperand().getType().castTo() + require(I->getType() == I->getOperand()->getType().castTo() ->getBoxedAddressType(), "project_box result should be address of boxed type"); } + void checkProjectExistentialBoxInst(ProjectExistentialBoxInst *PEBI) { + SILType operandType = PEBI->getOperand()->getType(); + require(operandType.isObject(), + "project_existential_box operand must not be address"); + + require(operandType.canUseExistentialRepresentation(F.getModule(), + ExistentialRepresentation::Boxed), + "project_existential_box operand must be boxed existential"); + + require(PEBI->getType().isAddress(), + "project_existential_box result must be an address"); + + if (auto *AEBI = dyn_cast(PEBI->getOperand())) { + // The lowered type must be the properly-abstracted form of the AST type. + SILType exType = AEBI->getExistentialType(); + auto archetype = ArchetypeType::getOpened(exType.getSwiftRValueType()); + + auto loweredTy = F.getModule().Types.getLoweredType( + Lowering::AbstractionPattern(archetype), + AEBI->getFormalConcreteType()) + .getAddressType(); + + requireSameType(loweredTy, PEBI->getType(), + "project_existential_box result should be the lowered " + "concrete type of its alloc_existential_box"); + } + } + void checkDeallocValueBufferInst(DeallocValueBufferInst *I) { - require(I->getOperand().getType().isAddress(), + require(I->getOperand()->getType().isAddress(), "Operand value should be an address"); - require(I->getOperand().getType().is(), + require(I->getOperand()->getType().is(), "Operand value should be a Builtin.UnsafeValueBuffer"); } @@ -1132,7 +1156,7 @@ class SILVerifier : public SILVerifierBase { "member variables of struct"); SILType loweredType = structTy.getFieldType(field, F.getModule()); - require((*opi).getType() == loweredType, + require((*opi)->getType() == loweredType, "struct operand type does not match field type"); ++opi; } @@ -1149,80 +1173,80 @@ class SILVerifier : public SILVerifierBase { "EnumInst must take an argument iff the element does"); if (UI->getElement()->hasArgumentType()) { - require(UI->getOperand().getType().isObject(), + require(UI->getOperand()->getType().isObject(), "EnumInst operand must be an object"); SILType caseTy = UI->getType().getEnumElementType(UI->getElement(), F.getModule()); - require(caseTy == UI->getOperand().getType(), + require(caseTy == UI->getOperand()->getType(), "EnumInst operand type does not match type of case"); } } void checkInitEnumDataAddrInst(InitEnumDataAddrInst *UI) { - EnumDecl *ud = UI->getOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *ud = UI->getOperand()->getType().getEnumOrBoundGenericEnum(); require(ud, "InitEnumDataAddrInst must take an enum operand"); require(UI->getElement()->getParentEnum() == ud, "InitEnumDataAddrInst case must be a case of the enum operand type"); require(UI->getElement()->hasArgumentType(), "InitEnumDataAddrInst case must have a data type"); - require(UI->getOperand().getType().isAddress(), + require(UI->getOperand()->getType().isAddress(), "InitEnumDataAddrInst must take an address operand"); require(UI->getType().isAddress(), "InitEnumDataAddrInst must produce an address"); SILType caseTy = - UI->getOperand().getType().getEnumElementType(UI->getElement(), + UI->getOperand()->getType().getEnumElementType(UI->getElement(), F.getModule()); requireSameType(caseTy, UI->getType(), "InitEnumDataAddrInst result does not match type of enum case"); } void checkUncheckedEnumDataInst(UncheckedEnumDataInst *UI) { - EnumDecl *ud = UI->getOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *ud = UI->getOperand()->getType().getEnumOrBoundGenericEnum(); require(ud, "UncheckedEnumData must take an enum operand"); require(UI->getElement()->getParentEnum() == ud, "UncheckedEnumData case must be a case of the enum operand type"); require(UI->getElement()->hasArgumentType(), "UncheckedEnumData case must have a data type"); - require(UI->getOperand().getType().isObject(), + require(UI->getOperand()->getType().isObject(), "UncheckedEnumData must take an address operand"); require(UI->getType().isObject(), "UncheckedEnumData must produce an address"); SILType caseTy = - UI->getOperand().getType().getEnumElementType(UI->getElement(), + UI->getOperand()->getType().getEnumElementType(UI->getElement(), F.getModule()); require(caseTy == UI->getType(), "UncheckedEnumData result does not match type of enum case"); } void checkUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *UI) { - EnumDecl *ud = UI->getOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *ud = UI->getOperand()->getType().getEnumOrBoundGenericEnum(); require(ud, "UncheckedTakeEnumDataAddrInst must take an enum operand"); require(UI->getElement()->getParentEnum() == ud, "UncheckedTakeEnumDataAddrInst case must be a case of the enum operand type"); require(UI->getElement()->hasArgumentType(), "UncheckedTakeEnumDataAddrInst case must have a data type"); - require(UI->getOperand().getType().isAddress(), + require(UI->getOperand()->getType().isAddress(), "UncheckedTakeEnumDataAddrInst must take an address operand"); require(UI->getType().isAddress(), "UncheckedTakeEnumDataAddrInst must produce an address"); SILType caseTy = - UI->getOperand().getType().getEnumElementType(UI->getElement(), + UI->getOperand()->getType().getEnumElementType(UI->getElement(), F.getModule()); require(caseTy == UI->getType(), "UncheckedTakeEnumDataAddrInst result does not match type of enum case"); } void checkInjectEnumAddrInst(InjectEnumAddrInst *IUAI) { - require(IUAI->getOperand().getType().is() - || IUAI->getOperand().getType().is(), + require(IUAI->getOperand()->getType().is() + || IUAI->getOperand()->getType().is(), "InjectEnumAddrInst must take an enum operand"); require(IUAI->getElement()->getParentEnum() - == IUAI->getOperand().getType().getEnumOrBoundGenericEnum(), + == IUAI->getOperand()->getType().getEnumOrBoundGenericEnum(), "InjectEnumAddrInst case must be a case of the enum operand type"); - require(IUAI->getOperand().getType().isAddress(), + require(IUAI->getOperand()->getType().isAddress(), "InjectEnumAddrInst must take an address operand"); } @@ -1233,7 +1257,7 @@ class SILVerifier : public SILVerifierBase { "Tuple field count mismatch!"); for (size_t i = 0, size = TI->getElements().size(); i < size; ++i) { - require(TI->getElement(i).getType().getSwiftType() + require(TI->getElement(i)->getType().getSwiftType() ->isEqual(ResTy.getElementType(i)), "Tuple element arguments do not match tuple type!"); } @@ -1280,9 +1304,9 @@ class SILVerifier : public SILVerifierBase { } void checkMetatypeInst(MetatypeInst *MI) { - require(MI->getType(0).is(), + require(MI->getType().is(), "metatype instruction must be of metatype type"); - require(MI->getType(0).castTo()->hasRepresentation(), + require(MI->getType().castTo()->hasRepresentation(), "metatype instruction must have a metatype representation"); } void checkValueMetatypeInst(ValueMetatypeInst *MI) { @@ -1292,7 +1316,7 @@ class SILVerifier : public SILVerifierBase { "value_metatype instruction must have a metatype representation"); auto formalInstanceTy = MI->getType().castTo().getInstanceType(); - require(isLoweringOf(MI->getOperand().getType(), formalInstanceTy), + require(isLoweringOf(MI->getOperand()->getType(), formalInstanceTy), "value_metatype result must be formal metatype of " "lowered operand type"); } @@ -1301,11 +1325,11 @@ class SILVerifier : public SILVerifierBase { "existential_metatype instruction must be of metatype type"); require(MI->getType().castTo()->hasRepresentation(), "value_metatype instruction must have a metatype representation"); - require(MI->getOperand().getType().isAnyExistentialType(), + require(MI->getOperand()->getType().isAnyExistentialType(), "existential_metatype operand must be of protocol type"); auto formalInstanceTy = MI->getType().castTo().getInstanceType(); - require(isLoweringOf(MI->getOperand().getType(), formalInstanceTy), + require(isLoweringOf(MI->getOperand()->getType(), formalInstanceTy), "existential_metatype result must be formal metatype of " "lowered operand type"); } @@ -1335,24 +1359,24 @@ class SILVerifier : public SILVerifierBase { "unowned_release requires unowned type to be loadable"); } void checkDeallocStackInst(DeallocStackInst *DI) { - require(DI->getOperand().getType().isLocalStorage(), - "Operand of dealloc_stack must be local storage"); + require(isa(DI->getOperand()), + "Operand of dealloc_stack must be an alloc_stack"); } void checkDeallocRefInst(DeallocRefInst *DI) { - require(DI->getOperand().getType().isObject(), + require(DI->getOperand()->getType().isObject(), "Operand of dealloc_ref must be object"); - require(DI->getOperand().getType().getClassOrBoundGenericClass(), + require(DI->getOperand()->getType().getClassOrBoundGenericClass(), "Operand of dealloc_ref must be of class type"); } void checkDeallocPartialRefInst(DeallocPartialRefInst *DPRI) { - require(DPRI->getInstance().getType().isObject(), + require(DPRI->getInstance()->getType().isObject(), "First operand of dealloc_partial_ref must be object"); - auto class1 = DPRI->getInstance().getType().getClassOrBoundGenericClass(); + auto class1 = DPRI->getInstance()->getType().getClassOrBoundGenericClass(); require(class1, "First operand of dealloc_partial_ref must be of class type"); - require(DPRI->getMetatype().getType().is(), + require(DPRI->getMetatype()->getType().is(), "Second operand of dealloc_partial_ref must be a metatype"); - auto class2 = DPRI->getMetatype().getType().castTo() + auto class2 = DPRI->getMetatype()->getType().castTo() ->getInstanceType()->getClassOrBoundGenericClass(); require(class2, "Second operand of dealloc_partial_ref must be a class metatype"); @@ -1365,23 +1389,19 @@ class SILVerifier : public SILVerifierBase { void checkAllocBoxInst(AllocBoxInst *AI) { // TODO: Allow the box to be typed, but for staging purposes, only require // it when -sil-enable-typed-boxes is enabled. - auto boxTy = AI->getType(0).getAs(); - require(boxTy, "first result must be a @box type"); + auto boxTy = AI->getType().getAs(); + require(boxTy, "alloc_box must have a @box type"); - require(AI->getType(0).isObject(), - "first result must be an object"); - require(AI->getType(1).isAddress(), - "second result of alloc_box must be address"); - requireSameType(boxTy->getBoxedAddressType(), AI->getType(1), - "address type must match box type"); + require(AI->getType().isObject(), + "result of alloc_box must be an object"); } void checkDeallocBoxInst(DeallocBoxInst *DI) { // TODO: Allow the box to be typed, but for staging purposes, only require // it when -sil-enable-typed-boxes is enabled. - auto boxTy = DI->getOperand().getType().getAs(); + auto boxTy = DI->getOperand()->getType().getAs(); require(boxTy, "operand must be a @box type"); - require(DI->getOperand().getType().isObject(), + require(DI->getOperand()->getType().isObject(), "operand must be an object"); requireSameType(boxTy->getBoxedAddressType().getObjectType(), DI->getElementType().getObjectType(), @@ -1389,24 +1409,24 @@ class SILVerifier : public SILVerifierBase { } void checkDestroyAddrInst(DestroyAddrInst *DI) { - require(DI->getOperand().getType().isAddress(), + require(DI->getOperand()->getType().isAddress(), "Operand of destroy_addr must be address"); } void checkIndexAddrInst(IndexAddrInst *IAI) { require(IAI->getType().isAddress(), "index_addr must produce an address"); - require(IAI->getType() == IAI->getBase().getType(), + require(IAI->getType() == IAI->getBase()->getType(), "index_addr must produce an address of the same type as its base"); - require(IAI->getIndex().getType().is(), + require(IAI->getIndex()->getType().is(), "index_addr index must be of a builtin integer type"); } void checkIndexRawPointerInst(IndexRawPointerInst *IAI) { require(IAI->getType().is(), "index_raw_pointer must produce a RawPointer"); - require(IAI->getBase().getType().is(), + require(IAI->getBase()->getType().is(), "index_raw_pointer base must be a RawPointer"); - require(IAI->getIndex().getType().is(), + require(IAI->getIndex()->getType().is(), "index_raw_pointer index must be of a builtin integer type"); } @@ -1424,7 +1444,7 @@ class SILVerifier : public SILVerifierBase { } void checkStructExtractInst(StructExtractInst *EI) { - SILType operandTy = EI->getOperand().getType(); + SILType operandTy = EI->getOperand()->getType(); require(operandTy.isObject(), "cannot struct_extract from address"); require(EI->getType().isObject(), @@ -1446,10 +1466,10 @@ class SILVerifier : public SILVerifierBase { } void checkTupleElementAddrInst(TupleElementAddrInst *EI) { - SILType operandTy = EI->getOperand().getType(); + SILType operandTy = EI->getOperand()->getType(); require(operandTy.isAddress(), "must derive element_addr from address"); - require(EI->getType(0).isAddress(), + require(EI->getType().isAddress(), "result of tuple_element_addr must be address"); require(operandTy.is(), "must derive tuple_element_addr from tuple"); @@ -1463,12 +1483,12 @@ class SILVerifier : public SILVerifierBase { } void checkStructElementAddrInst(StructElementAddrInst *EI) { - SILType operandTy = EI->getOperand().getType(); + SILType operandTy = EI->getOperand()->getType(); require(operandTy.isAddress(), "must derive struct_element_addr from address"); StructDecl *sd = operandTy.getStructOrBoundGenericStruct(); require(sd, "struct_element_addr operand must be struct address"); - require(EI->getType(0).isAddress(), + require(EI->getType().isAddress(), "result of struct_element_addr must be address"); require(!EI->getField()->isStatic(), "cannot get address of static property with struct_element_addr"); @@ -1486,13 +1506,13 @@ class SILVerifier : public SILVerifierBase { void checkRefElementAddrInst(RefElementAddrInst *EI) { requireReferenceValue(EI->getOperand(), "Operand of ref_element_addr"); - require(EI->getType(0).isAddress(), + require(EI->getType().isAddress(), "result of ref_element_addr must be lvalue"); require(!EI->getField()->isStatic(), "cannot get address of static property with struct_element_addr"); require(EI->getField()->hasStorage(), "cannot get address of computed property with ref_element_addr"); - SILType operandTy = EI->getOperand().getType(); + SILType operandTy = EI->getOperand()->getType(); ClassDecl *cd = operandTy.getClassOrBoundGenericClass(); require(cd, "ref_element_addr operand must be a class instance"); @@ -1509,12 +1529,6 @@ class SILVerifier : public SILVerifierBase { SILType getMethodSelfType(CanSILFunctionType ft) { return ft->getParameters().back().getSILType(); } - CanType getMethodSelfInstanceType(CanSILFunctionType ft) { - auto selfTy = getMethodSelfType(ft); - if (auto metaTy = selfTy.getAs()) - return metaTy.getInstanceType(); - return selfTy.getSwiftRValueType(); - } void checkWitnessMethodInst(WitnessMethodInst *AMI) { auto methodType = requireObjectType(SILFunctionType, AMI, @@ -1554,37 +1568,19 @@ class SILVerifier : public SILVerifierBase { if (isOpenedArchetype(lookupType)) require(AMI->hasOperand(), "Must have an opened existential operand"); if (isa(lookupType) || lookupType->isAnyExistentialType()) { - require(AMI->getConformance() == nullptr, - "archetype or existential lookup should have null conformance"); + require(AMI->getConformance().isAbstract(), + "archetype or existential lookup should have abstract conformance"); } else { - require(AMI->getConformance(), - "concrete type lookup requires conformance"); - require(AMI->getConformance()->getType() - ->isEqual(AMI->getLookupType()), + require(AMI->getConformance().isConcrete(), + "concrete type lookup requires concrete conformance"); + auto conformance = AMI->getConformance().getConcrete(); + require(conformance->getType()->isEqual(AMI->getLookupType()), "concrete type lookup requires conformance that matches type"); - require(AMI->getModule().lookUpWitnessTable(AMI->getConformance(), - false).first, + require(AMI->getModule().lookUpWitnessTable(conformance, false).first, "Could not find witness table for conformance."); } } - bool isSelfArchetype(CanType t, ArrayRef protocols) { - ArchetypeType *archetype = dyn_cast(t); - if (!archetype) - return false; - - auto selfProto = archetype->getSelfProtocol(); - if (!selfProto) - return false; - - for (auto checkProto : protocols) { - if (checkProto == selfProto || checkProto->inheritsFrom(selfProto)) - return true; - } - - return false; - } - bool isOpenedArchetype(CanType t) { ArchetypeType *archetype = dyn_cast(t); if (!archetype) @@ -1634,7 +1630,7 @@ class SILVerifier : public SILVerifierBase { void checkDynamicMethodInst(DynamicMethodInst *EMI) { requireObjectType(SILFunctionType, EMI, "result of dynamic_method"); - SILType operandType = EMI->getOperand().getType(); + SILType operandType = EMI->getOperand()->getType(); require(EMI->getMember().getDecl()->isObjC(), "method must be @objc"); if (!EMI->getMember().getDecl()->isInstanceMember()) { @@ -1659,7 +1655,7 @@ class SILVerifier : public SILVerifierBase { "result of class_method"); require(!methodType->getExtInfo().hasContext(), "result method must be of a context-free function type"); - SILType operandType = CMI->getOperand().getType(); + SILType operandType = CMI->getOperand()->getType(); require(operandType.isClassOrClassMetatype(), "operand must be of a class type"); require(getMethodSelfType(methodType).isClassOrClassMetatype(), @@ -1673,8 +1669,9 @@ class SILVerifier : public SILVerifierBase { || !isa(CMI->getMember().getDecl()->getDeclContext()), "extension method cannot be dispatched natively"); - /* TODO: We should enforce that ObjC methods are dispatched on ObjC - metatypes, but IRGen appears not to care right now. + // TODO: We should enforce that ObjC methods are dispatched on ObjC + // metatypes, but IRGen appears not to care right now. +#if 0 if (auto metaTy = operandType.getAs()) { bool objcMetatype = metaTy->getRepresentation() == MetatypeRepresentation::ObjC; @@ -1682,7 +1679,7 @@ class SILVerifier : public SILVerifierBase { require(objcMetatype == objcMethod, "objc class methods must be invoked on objc metatypes"); } - */ +#endif } void checkSuperMethodInst(SuperMethodInst *CMI) { @@ -1693,7 +1690,7 @@ class SILVerifier : public SILVerifierBase { "result of super_method"); require(!methodType->getExtInfo().hasContext(), "result method must be of a context-free function type"); - SILType operandType = CMI->getOperand().getType(); + SILType operandType = CMI->getOperand()->getType(); require(operandType.isClassOrClassMetatype(), "operand must be of a class type"); require(getMethodSelfType(methodType).isClassOrClassMetatype(), @@ -1714,7 +1711,7 @@ class SILVerifier : public SILVerifierBase { } void checkOpenExistentialAddrInst(OpenExistentialAddrInst *OEI) { - SILType operandType = OEI->getOperand().getType(); + SILType operandType = OEI->getOperand()->getType(); require(operandType.isAddress(), "open_existential_addr must be applied to address"); require(operandType.canUseExistentialRepresentation(F.getModule(), @@ -1729,7 +1726,7 @@ class SILVerifier : public SILVerifierBase { } void checkOpenExistentialRefInst(OpenExistentialRefInst *OEI) { - SILType operandType = OEI->getOperand().getType(); + SILType operandType = OEI->getOperand()->getType(); require(operandType.isObject(), "open_existential_ref operand must not be address"); @@ -1747,7 +1744,7 @@ class SILVerifier : public SILVerifierBase { } void checkOpenExistentialBoxInst(OpenExistentialBoxInst *OEI) { - SILType operandType = OEI->getOperand().getType(); + SILType operandType = OEI->getOperand()->getType(); require(operandType.isObject(), "open_existential_box operand must not be address"); @@ -1765,7 +1762,7 @@ class SILVerifier : public SILVerifierBase { } void checkOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *I) { - SILType operandType = I->getOperand().getType(); + SILType operandType = I->getOperand()->getType(); require(operandType.isObject(), "open_existential_metatype operand must not be address"); require(operandType.is(), @@ -1816,30 +1813,11 @@ class SILVerifier : public SILVerifierBase { "alloc_existential_box must be used with a boxed existential " "type"); - // The lowered type must be the properly-abstracted form of the AST type. - auto archetype = ArchetypeType::getOpened(exType.getSwiftRValueType()); - - auto loweredTy = F.getModule().Types.getLoweredType( - Lowering::AbstractionPattern(archetype), - AEBI->getFormalConcreteType()) - .getAddressType(); - - requireSameType(loweredTy, AEBI->getLoweredConcreteType(), - "alloc_existential_box #1 result should be the lowered " - "concrete type at the right abstraction level"); - require(isLoweringOf(AEBI->getLoweredConcreteType(), - AEBI->getFormalConcreteType()), - "alloc_existential_box payload must be a lowering of the formal " - "concrete type"); - - for (ProtocolConformance *C : AEBI->getConformances()) - // We allow for null conformances. - require(!C || AEBI->getModule().lookUpWitnessTable(C, false).first, - "Could not find witness table for conformance."); + checkExistentialProtocolConformances(exType, AEBI->getConformances()); } void checkInitExistentialAddrInst(InitExistentialAddrInst *AEI) { - SILType exType = AEI->getOperand().getType(); + SILType exType = AEI->getOperand()->getType(); require(exType.isAddress(), "init_existential_addr must be applied to an address"); require(exType.canUseExistentialRepresentation(F.getModule(), @@ -1865,14 +1843,11 @@ class SILVerifier : public SILVerifierBase { "init_existential_addr payload must be a lowering of the formal " "concrete type"); - for (ProtocolConformance *C : AEI->getConformances()) - // We allow for null conformances. - require(!C || AEI->getModule().lookUpWitnessTable(C, false).first, - "Could not find witness table for conformance."); + checkExistentialProtocolConformances(exType, AEI->getConformances()); } void checkInitExistentialRefInst(InitExistentialRefInst *IEI) { - SILType concreteType = IEI->getOperand().getType(); + SILType concreteType = IEI->getOperand()->getType(); require(concreteType.getSwiftType()->isBridgeableObjectType(), "init_existential_ref operand must be a class instance"); require(IEI->getType().canUseExistentialRepresentation(F.getModule(), @@ -1883,8 +1858,8 @@ class SILVerifier : public SILVerifierBase { "init_existential_ref result must not be an address"); // The operand must be at the right abstraction level for the existential. - auto archetype = ArchetypeType::getOpened( - IEI->getType().getSwiftRValueType()); + SILType exType = IEI->getType(); + auto archetype = ArchetypeType::getOpened(exType.getSwiftRValueType()); auto loweredTy = F.getModule().Types.getLoweredType( Lowering::AbstractionPattern(archetype), IEI->getFormalConcreteType()); @@ -1892,19 +1867,16 @@ class SILVerifier : public SILVerifierBase { "init_existential_ref operand must be lowered to the right " "abstraction level for the existential"); - require(isLoweringOf(IEI->getOperand().getType(), + require(isLoweringOf(IEI->getOperand()->getType(), IEI->getFormalConcreteType()), "init_existential_ref operand must be a lowering of the formal " "concrete type"); - for (ProtocolConformance *C : IEI->getConformances()) - // We allow for null conformances. - require(!C || IEI->getModule().lookUpWitnessTable(C, false).first, - "Could not find witness table for conformance."); + checkExistentialProtocolConformances(exType, IEI->getConformances()); } void checkDeinitExistentialAddrInst(DeinitExistentialAddrInst *DEI) { - SILType exType = DEI->getOperand().getType(); + SILType exType = DEI->getOperand()->getType(); require(exType.isAddress(), "deinit_existential_addr must be applied to an address"); require(exType.canUseExistentialRepresentation(F.getModule(), @@ -1914,7 +1886,7 @@ class SILVerifier : public SILVerifierBase { } void checkDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEBI) { - SILType exType = DEBI->getOperand().getType(); + SILType exType = DEBI->getOperand()->getType(); require(exType.isObject(), "dealloc_existential_box must be applied to a value"); require(exType.canUseExistentialRepresentation(F.getModule(), @@ -1924,7 +1896,7 @@ class SILVerifier : public SILVerifierBase { } void checkInitExistentialMetatypeInst(InitExistentialMetatypeInst *I) { - SILType operandType = I->getOperand().getType(); + SILType operandType = I->getOperand()->getType(); require(operandType.isObject(), "init_existential_metatype operand must not be an address"); require(operandType.is(), @@ -1943,11 +1915,30 @@ class SILVerifier : public SILVerifierBase { == operandType.castTo()->getRepresentation(), "init_existential_metatype result must match representation of " "operand"); - - for (ProtocolConformance *C : I->getConformances()) - // We allow for null conformances. - require(!C || I->getModule().lookUpWitnessTable(C, false).first, - "Could not find witness table for conformance."); + + checkExistentialProtocolConformances(resultType, I->getConformances()); + } + + void checkExistentialProtocolConformances(SILType resultType, + ArrayRef conformances) { + SmallVector protocols; + resultType.getSwiftRValueType().isAnyExistentialType(protocols); + + require(conformances.size() == protocols.size(), + "init_existential instruction must have the " + "right number of conformances"); + for (auto i : indices(conformances)) { + require(conformances[i].getRequirement() == protocols[i], + "init_existential instruction must have conformances in " + "proper order"); + + if (conformances[i].isConcrete()) { + auto conformance = conformances[i].getConcrete(); + require(F.getModule().lookUpWitnessTable(conformance, false).first, + "Could not find witness table for conformance."); + + } + } } void verifyCheckedCast(bool isExact, SILType fromTy, SILType toTy) { @@ -2000,13 +1991,13 @@ class SILVerifier : public SILVerifierBase { void checkUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *CI) { verifyCheckedCast(/*exact*/ false, - CI->getOperand().getType(), + CI->getOperand()->getType(), CI->getType()); } void checkCheckedCastBranchInst(CheckedCastBranchInst *CBI) { verifyCheckedCast(CBI->isExact(), - CBI->getOperand().getType(), + CBI->getOperand()->getType(), CBI->getCastType()); require(CBI->getSuccessBB()->bbarg_size() == 1, @@ -2018,6 +2009,18 @@ class SILVerifier : public SILVerifierBase { "failure dest of checked_cast_br must take no arguments"); } + void checkCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) { + require(CCABI->getSrc()->getType().isAddress(), + "checked_cast_addr_br src must be an address"); + require(CCABI->getDest()->getType().isAddress(), + "checked_cast_addr_br dest must be an address"); + + require(CCABI->getSuccessBB()->bbarg_size() == 0, + "success dest block of checked_cast_addr_br must not take an argument"); + require(CCABI->getFailureBB()->bbarg_size() == 0, + "failure dest block of checked_cast_addr_br must not take an argument"); + } + void checkThinToThickFunctionInst(ThinToThickFunctionInst *TTFI) { auto opFTy = requireObjectType(SILFunctionType, TTFI->getOperand(), "thin_to_thick_function operand"); @@ -2046,7 +2049,7 @@ class SILVerifier : public SILVerifierBase { auto resTy = requireObjectType(AnyMetatypeType, TTOCI, "thick_to_objc_metatype result"); - require(TTOCI->getOperand().getType().is() == + require(TTOCI->getOperand()->getType().is() == TTOCI->getType().is(), "thick_to_objc_metatype cannot change metatype kinds"); require(opTy->getRepresentation() == MetatypeRepresentation::Thick, @@ -2064,7 +2067,7 @@ class SILVerifier : public SILVerifierBase { auto resTy = requireObjectType(AnyMetatypeType, OCTTI, "objc_to_thick_metatype result"); - require(OCTTI->getOperand().getType().is() == + require(OCTTI->getOperand()->getType().is() == OCTTI->getType().is(), "objc_to_thick_metatype cannot change metatype kinds"); require(opTy->getRepresentation() == MetatypeRepresentation::ObjC, @@ -2079,7 +2082,7 @@ class SILVerifier : public SILVerifierBase { void checkRefToUnownedInst(RefToUnownedInst *I) { requireReferenceStorageCapableValue(I->getOperand(), "Operand of ref_to_unowned"); - auto operandType = I->getOperand().getType().getSwiftRValueType(); + auto operandType = I->getOperand()->getType().getSwiftRValueType(); auto resultType = requireObjectType(UnownedStorageType, I, "Result of ref_to_unowned"); require(resultType->isLoadable(ResilienceExpansion::Maximal), @@ -2105,7 +2108,7 @@ class SILVerifier : public SILVerifierBase { void checkRefToUnmanagedInst(RefToUnmanagedInst *I) { requireReferenceStorageCapableValue(I->getOperand(), "Operand of ref_to_unmanaged"); - auto operandType = I->getOperand().getType().getSwiftRValueType(); + auto operandType = I->getOperand()->getType().getSwiftRValueType(); auto resultType = requireObjectType(UnmanagedStorageType, I, "Result of ref_to_unmanaged"); require(resultType.getReferentType() == operandType, @@ -2125,13 +2128,13 @@ class SILVerifier : public SILVerifierBase { } void checkUpcastInst(UpcastInst *UI) { - require(UI->getType() != UI->getOperand().getType(), + require(UI->getType() != UI->getOperand()->getType(), "can't upcast to same type"); if (UI->getType().is()) { CanType instTy(UI->getType().castTo()->getInstanceType()); - require(UI->getOperand().getType().is(), + require(UI->getOperand()->getType().is(), "upcast operand must be a class or class metatype instance"); - CanType opInstTy(UI->getOperand().getType().castTo() + CanType opInstTy(UI->getOperand()->getType().castTo() ->getInstanceType()); require(instTy->getClassOrBoundGenericClass(), "upcast must convert a class metatype to a class metatype"); @@ -2141,13 +2144,13 @@ class SILVerifier : public SILVerifierBase { } require(UI->getType().getCategory() == - UI->getOperand().getType().getCategory(), + UI->getOperand()->getType().getCategory(), "Upcast can only upcast in between types of the same " "SILValueCategory. This prevents address types from being cast to " "object types or vis-a-versa"); auto ToTy = UI->getType(); - auto FromTy = UI->getOperand().getType(); + auto FromTy = UI->getOperand()->getType(); // Upcast from Optional to Optional is legal as long as B is a // subclass of A. @@ -2167,13 +2170,13 @@ class SILVerifier : public SILVerifierBase { void checkIsNonnullInst(IsNonnullInst *II) { // The operand must be a function type or a class type. - auto OpTy = II->getOperand().getType().getSwiftType(); + auto OpTy = II->getOperand()->getType().getSwiftType(); require(OpTy->mayHaveSuperclass() || OpTy->is(), "is_nonnull operand must be a class or function type"); } void checkAddressToPointerInst(AddressToPointerInst *AI) { - require(AI->getOperand().getType().isAddress(), + require(AI->getOperand()->getType().isAddress(), "address-to-pointer operand must be an address"); require(AI->getType().getSwiftType()->isEqual( AI->getType().getASTContext().TheRawPointerType), @@ -2181,18 +2184,18 @@ class SILVerifier : public SILVerifierBase { } void checkUncheckedRefCastInst(UncheckedRefCastInst *AI) { - require(AI->getOperand().getType().isObject(), + require(AI->getOperand()->getType().isObject(), "unchecked_ref_cast operand must be a value"); require(AI->getType().isObject(), "unchecked_ref_cast result must be an object"); - require(SILType::canRefCast(AI->getOperand().getType(), AI->getType(), + require(SILType::canRefCast(AI->getOperand()->getType(), AI->getType(), AI->getModule()), "unchecked_ref_cast requires a heap object reference type"); } void checkUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *AI) { - auto srcTy = AI->getSrc().getType(); - auto destTy = AI->getDest().getType(); + auto srcTy = AI->getSrc()->getType(); + auto destTy = AI->getDest()->getType(); require(srcTy.isAddress(), "unchecked_ref_cast_addr operand must be an address"); require(destTy.isAddress(), @@ -2204,14 +2207,14 @@ class SILVerifier : public SILVerifierBase { } void checkUncheckedAddrCastInst(UncheckedAddrCastInst *AI) { - require(AI->getOperand().getType().isAddress(), + require(AI->getOperand()->getType().isAddress(), "unchecked_addr_cast operand must be an address"); require(AI->getType().isAddress(), "unchecked_addr_cast result must be an address"); } void checkUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *BI) { - require(BI->getOperand().getType().isObject(), + require(BI->getOperand()->getType().isObject(), "unchecked_trivial_bit_cast must operate on a value"); require(BI->getType().isObject(), "unchecked_trivial_bit_cast must produce a value"); @@ -2220,14 +2223,14 @@ class SILVerifier : public SILVerifierBase { } void checkUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *BI) { - require(BI->getOperand().getType().isObject(), + require(BI->getOperand()->getType().isObject(), "unchecked_bitwise_cast must operate on a value"); require(BI->getType().isObject(), "unchecked_bitwise_cast must produce a value"); } void checkRefToRawPointerInst(RefToRawPointerInst *AI) { - require(AI->getOperand().getType().getSwiftType() + require(AI->getOperand()->getType().getSwiftType() ->isAnyClassReferenceType(), "ref-to-raw-pointer operand must be a class reference or" " NativeObject"); @@ -2244,18 +2247,18 @@ class SILVerifier : public SILVerifierBase { || AI->getType().getSwiftType()->isEqual( AI->getType().getASTContext().TheUnknownObjectType), "raw-pointer-to-ref result must be a class reference or NativeObject"); - require(AI->getOperand().getType().getSwiftType()->isEqual( + require(AI->getOperand()->getType().getSwiftType()->isEqual( AI->getType().getASTContext().TheRawPointerType), "raw-pointer-to-ref operand must be NativeObject"); } void checkRefToBridgeObjectInst(RefToBridgeObjectInst *RI) { - require(RI->getConverted().getType().isObject(), + require(RI->getConverted()->getType().isObject(), "ref_to_bridge_object must convert from a value"); - require(RI->getConverted().getType().getSwiftRValueType() + require(RI->getConverted()->getType().getSwiftRValueType() ->isBridgeableObjectType(), "ref_to_bridge_object must convert from a heap object ref"); - require(RI->getBitsOperand().getType() + require(RI->getBitsOperand()->getType() == SILType::getBuiltinWordType(F.getASTContext()), "ref_to_bridge_object must take a Builtin.Word bits operand"); require(RI->getType() == SILType::getBridgeObjectType(F.getASTContext()), @@ -2263,7 +2266,7 @@ class SILVerifier : public SILVerifierBase { } void checkBridgeObjectToRefInst(BridgeObjectToRefInst *RI) { - require(RI->getConverted().getType() + require(RI->getConverted()->getType() == SILType::getBridgeObjectType(F.getASTContext()), "bridge_object_to_ref must take a BridgeObject"); require(RI->getType().isObject(), @@ -2272,7 +2275,7 @@ class SILVerifier : public SILVerifierBase { "bridge_object_to_ref must produce a heap object reference"); } void checkBridgeObjectToWordInst(BridgeObjectToWordInst *RI) { - require(RI->getConverted().getType() + require(RI->getConverted()->getType() == SILType::getBridgeObjectType(F.getASTContext()), "bridge_object_to_word must take a BridgeObject"); require(RI->getType().isObject(), @@ -2313,7 +2316,7 @@ class SILVerifier : public SILVerifierBase { } void checkCondFailInst(CondFailInst *CFI) { - require(CFI->getOperand().getType() + require(CFI->getOperand()->getType() == SILType::getBuiltinIntegerType(1, F.getASTContext()), "cond_fail operand must be a Builtin.Int1"); } @@ -2324,7 +2327,7 @@ class SILVerifier : public SILVerifierBase { CanSILFunctionType ti = F.getLoweredFunctionType(); SILType functionResultType = F.mapTypeIntoContext(ti->getResult().getSILType()); - SILType instResultType = RI->getOperand().getType(); + SILType instResultType = RI->getOperand()->getType(); DEBUG(llvm::dbgs() << "function return type: "; functionResultType.dump(); llvm::dbgs() << "return inst type: "; @@ -2342,7 +2345,7 @@ class SILVerifier : public SILVerifierBase { SILType functionResultType = F.mapTypeIntoContext(fnType->getErrorResult().getSILType()); - SILType instResultType = TI->getOperand().getType(); + SILType instResultType = TI->getOperand()->getType(); DEBUG(llvm::dbgs() << "function error result type: "; functionResultType.dump(); llvm::dbgs() << "throw operand type: "; @@ -2352,7 +2355,7 @@ class SILVerifier : public SILVerifierBase { } void checkSelectEnumCases(SelectEnumInstBase *I) { - EnumDecl *eDecl = I->getEnumOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *eDecl = I->getEnumOperand()->getType().getEnumOrBoundGenericEnum(); require(eDecl, "select_enum operand must be an enum"); // Find the set of enum elements for the type so we can verify @@ -2376,7 +2379,7 @@ class SILVerifier : public SILVerifierBase { unswitchedElts.erase(elt); // The result value must match the type of the instruction. - requireSameType(result.getType(), I->getType(), + requireSameType(result->getType(), I->getType(), "select_enum case operand must match type of instruction"); } @@ -2384,20 +2387,20 @@ class SILVerifier : public SILVerifierBase { require(unswitchedElts.empty() || I->hasDefault(), "nonexhaustive select_enum must have a default destination"); if (I->hasDefault()) { - requireSameType(I->getDefaultResult().getType(), + requireSameType(I->getDefaultResult()->getType(), I->getType(), "select_enum default operand must match type of instruction"); } } void checkSelectEnumInst(SelectEnumInst *SEI) { - require(SEI->getEnumOperand().getType().isObject(), + require(SEI->getEnumOperand()->getType().isObject(), "select_enum operand must be an object"); checkSelectEnumCases(SEI); } void checkSelectEnumAddrInst(SelectEnumAddrInst *SEI) { - require(SEI->getEnumOperand().getType().isAddress(), + require(SEI->getEnumOperand()->getType().isAddress(), "select_enum_addr operand must be an address"); checkSelectEnumCases(SEI); @@ -2405,7 +2408,7 @@ class SILVerifier : public SILVerifierBase { void checkSwitchValueInst(SwitchValueInst *SVI) { // TODO: Type should be either integer or function - auto Ty = SVI->getOperand().getType(); + auto Ty = SVI->getOperand()->getType(); require(Ty.getAs() || Ty.getAs(), "switch_value operand should be either of an integer " "or function type"); @@ -2421,7 +2424,7 @@ class SILVerifier : public SILVerifierBase { SILBasicBlock *dest; std::tie(value, dest) = SVI->getCase(i); - require(value.getType() == Ty, + require(value->getType() == Ty, "switch_value case value should have the same type as its operand"); require(!cases.count(value), @@ -2462,29 +2465,29 @@ class SILVerifier : public SILVerifierBase { seenCaseValues.insert(elt); // The result value must match the type of the instruction. - requireSameType(result.getType(), I->getType(), + requireSameType(result->getType(), I->getType(), "select_value case operand must match type of instruction"); } require(I->hasDefault(), "select_value should always have a default"); - requireSameType(I->getDefaultResult().getType(), + requireSameType(I->getDefaultResult()->getType(), I->getType(), "select_value default operand must match type of instruction"); } void checkSelectValueInst(SelectValueInst *SVI) { - require(SVI->getOperand().getType().isObject(), + require(SVI->getOperand()->getType().isObject(), "select_value operand must be an object"); checkSelectValueCases(SVI); } void checkSwitchEnumInst(SwitchEnumInst *SOI) { - require(SOI->getOperand().getType().isObject(), + require(SOI->getOperand()->getType().isObject(), "switch_enum operand must be an object"); - SILType uTy = SOI->getOperand().getType(); + SILType uTy = SOI->getOperand()->getType(); EnumDecl *uDecl = uTy.getEnumOrBoundGenericEnum(); require(uDecl, "switch_enum operand is not an enum"); @@ -2541,10 +2544,10 @@ class SILVerifier : public SILVerifierBase { } void checkSwitchEnumAddrInst(SwitchEnumAddrInst *SOI){ - require(SOI->getOperand().getType().isAddress(), - "switch_enum_addr operand must be an object"); + require(SOI->getOperand()->getType().isAddress(), + "switch_enum_addr operand must be an address"); - SILType uTy = SOI->getOperand().getType(); + SILType uTy = SOI->getOperand()->getType(); EnumDecl *uDecl = uTy.getEnumOrBoundGenericEnum(); require(uDecl, "switch_enum_addr operand must be an enum"); @@ -2590,15 +2593,21 @@ class SILVerifier : public SILVerifierBase { require(std::equal(BI->getArgs().begin(), BI->getArgs().end(), BI->getDestBB()->bbarg_begin(), [](SILValue branchArg, SILArgument *bbArg) { - return branchArg.getType() == bbArg->getType(); + return branchArg->getType() == bbArg->getType(); }), "branch argument types do not match arguments for dest bb"); } void checkCondBranchInst(CondBranchInst *CBI) { - require(CBI->getCondition().getType() == + // It is important that cond_br keeps an i1 type. ARC Sequence Opts assumes + // that cond_br does not use reference counted values or decrement reference + // counted values under the assumption that the instruction that computes + // the i1 is the use/decrement that ARC cares about and that after that + // instruction is evaluated, the scalar i1 has a different identity and the + // object can be deallocated. + require(CBI->getCondition()->getType() == SILType::getBuiltinIntegerType(1, - CBI->getCondition().getType().getASTContext()), + CBI->getCondition()->getType().getASTContext()), "condition of conditional branch must have Int1 type"); require(CBI->getTrueArgs().size() == CBI->getTrueBB()->bbarg_size(), @@ -2608,7 +2617,7 @@ class SILVerifier : public SILVerifierBase { require(std::equal(CBI->getTrueArgs().begin(), CBI->getTrueArgs().end(), CBI->getTrueBB()->bbarg_begin(), [](SILValue branchArg, SILArgument *bbArg) { - return branchArg.getType() == bbArg->getType(); + return branchArg->getType() == bbArg->getType(); }), "true branch argument types do not match arguments for dest bb"); @@ -2617,13 +2626,13 @@ class SILVerifier : public SILVerifierBase { require(std::equal(CBI->getFalseArgs().begin(), CBI->getFalseArgs().end(), CBI->getFalseBB()->bbarg_begin(), [](SILValue branchArg, SILArgument *bbArg) { - return branchArg.getType() == bbArg->getType(); + return branchArg->getType() == bbArg->getType(); }), "false branch argument types do not match arguments for dest bb"); } void checkDynamicMethodBranchInst(DynamicMethodBranchInst *DMBI) { - SILType operandType = DMBI->getOperand().getType(); + SILType operandType = DMBI->getOperand()->getType(); require(DMBI->getMember().getDecl()->isObjC(), "method must be @objc"); if (!DMBI->getMember().getDecl()->isInstanceMember()) { @@ -2644,9 +2653,9 @@ class SILVerifier : public SILVerifierBase { } void checkProjectBlockStorageInst(ProjectBlockStorageInst *PBSI) { - require(PBSI->getOperand().getType().isAddress(), + require(PBSI->getOperand()->getType().isAddress(), "operand must be an address"); - auto storageTy = PBSI->getOperand().getType().getAs(); + auto storageTy = PBSI->getOperand()->getType().getAs(); require(storageTy, "operand must be a @block_storage type"); require(PBSI->getType().isAddress(), @@ -2657,16 +2666,16 @@ class SILVerifier : public SILVerifierBase { } void checkInitBlockStorageHeaderInst(InitBlockStorageHeaderInst *IBSHI) { - require(IBSHI->getBlockStorage().getType().isAddress(), + require(IBSHI->getBlockStorage()->getType().isAddress(), "block storage operand must be an address"); auto storageTy - = IBSHI->getBlockStorage().getType().getAs(); + = IBSHI->getBlockStorage()->getType().getAs(); require(storageTy, "block storage operand must be a @block_storage type"); - require(IBSHI->getInvokeFunction().getType().isObject(), + require(IBSHI->getInvokeFunction()->getType().isObject(), "invoke function operand must be a value"); auto invokeTy - = IBSHI->getInvokeFunction().getType().getAs(); + = IBSHI->getInvokeFunction()->getType().getAs(); require(invokeTy, "invoke function operand must be a function"); require(invokeTy->getRepresentation() == SILFunctionType::Representation::CFunctionPointer, @@ -2714,9 +2723,9 @@ class SILVerifier : public SILVerifierBase { } void checkObjCMetatypeToObjectInst(ObjCMetatypeToObjectInst *OMOI) { - require(OMOI->getOperand().getType().isObject(), + require(OMOI->getOperand()->getType().isObject(), "objc_metatype_to_object must take a value"); - auto fromMetaTy = OMOI->getOperand().getType().getAs(); + auto fromMetaTy = OMOI->getOperand()->getType().getAs(); require(fromMetaTy, "objc_metatype_to_object must take an @objc metatype value"); require(fromMetaTy->getRepresentation() == MetatypeRepresentation::ObjC, "objc_metatype_to_object must take an @objc metatype value"); @@ -2728,9 +2737,9 @@ class SILVerifier : public SILVerifierBase { void checkObjCExistentialMetatypeToObjectInst( ObjCExistentialMetatypeToObjectInst *OMOI) { - require(OMOI->getOperand().getType().isObject(), + require(OMOI->getOperand()->getType().isObject(), "objc_metatype_to_object must take a value"); - auto fromMetaTy = OMOI->getOperand().getType() + auto fromMetaTy = OMOI->getOperand()->getType() .getAs(); require(fromMetaTy, "objc_metatype_to_object must take an @objc existential metatype value"); require(fromMetaTy->getRepresentation() == MetatypeRepresentation::ObjC, @@ -2798,12 +2807,12 @@ class SILVerifier : public SILVerifierBase { bool FoundThrowBlock = false; for (auto &BB : *F) { if (isa(BB.getTerminator())) { - require(FoundReturnBlock == false, + require(!FoundReturnBlock, "more than one return block in function"); FoundReturnBlock = true; } if (isa(BB.getTerminator())) { - require(FoundThrowBlock == false, + require(!FoundThrowBlock, "more than one throw block in function"); FoundThrowBlock = true; } @@ -2864,11 +2873,9 @@ class SILVerifier : public SILVerifierBase { } if (i.isDeallocatingStack()) { SILValue op = i.getOperand(0); - require(op.getResultNumber() == 0, - "stack dealloc operand is not local storage of stack alloc"); require(!stack.empty(), "stack dealloc with empty stack"); - require(op.getDef() == stack.back(), + require(op == stack.back(), "stack dealloc does not match most recent stack alloc"); stack.pop_back(); } diff --git a/lib/SIL/SILWitnessTable.cpp b/lib/SIL/SILWitnessTable.cpp index d4b0b3fafab56..1df243656ff5a 100644 --- a/lib/SIL/SILWitnessTable.cpp +++ b/lib/SIL/SILWitnessTable.cpp @@ -1,8 +1,8 @@ -//===--- SILWitnessTable.h - Defines the SILWitnessTable class ------------===// +//===--- SILWitnessTable.cpp - Defines the SILWitnessTable class ----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,30 +26,27 @@ using namespace swift; -static void mangleConstant(NormalProtocolConformance *C, - llvm::raw_ostream &buffer) { +static std::string mangleConstant(NormalProtocolConformance *C) { using namespace Mangle; - Mangler mangler(buffer); + Mangler mangler; // mangled-name ::= '_T' global // global ::= 'WP' protocol-conformance - buffer << "_TWP"; + mangler.append("_TWP"); mangler.mangleProtocolConformance(C); - buffer.flush(); + return mangler.finalize(); + } SILWitnessTable * SILWitnessTable::create(SILModule &M, SILLinkage Linkage, bool IsFragile, NormalProtocolConformance *Conformance, ArrayRef entries) { - assert(Conformance && "Can not create a witness table for a null " + assert(Conformance && "Cannot create a witness table for a null " "conformance."); // Create the mangled name of our witness table... - llvm::SmallString<32> buffer; - llvm::raw_svector_ostream stream(buffer); - mangleConstant(Conformance, stream); - Identifier Name = M.getASTContext().getIdentifier(buffer); + Identifier Name = M.getASTContext().getIdentifier(mangleConstant(Conformance)); // Allocate the witness table and initialize it. void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable)); @@ -70,14 +67,12 @@ SILWitnessTable::create(SILModule &M, SILLinkage Linkage, bool IsFragile, SILWitnessTable * SILWitnessTable::create(SILModule &M, SILLinkage Linkage, NormalProtocolConformance *Conformance) { - assert(Conformance && "Can not create a witness table for a null " + assert(Conformance && "Cannot create a witness table for a null " "conformance."); // Create the mangled name of our witness table... - llvm::SmallString<32> buffer; - llvm::raw_svector_ostream stream(buffer); - mangleConstant(Conformance, stream); - Identifier Name = M.getASTContext().getIdentifier(buffer); + Identifier Name = M.getASTContext().getIdentifier(mangleConstant(Conformance)); + // Allocate the witness table and initialize it. void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable)); diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index d2104718a8cb0..e456b7affc8fe 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1,8 +1,8 @@ -//===--- TypeLowering.cpp - Type information for SILGen ---------*- C++ -*-===// +//===--- TypeLowering.cpp - Type information for SILGen -------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -150,17 +150,23 @@ enum class LoweredTypeKind { AddressOnly }; -static LoweredTypeKind classifyType(CanType type, SILModule &M); +static LoweredTypeKind classifyType(CanType type, SILModule &M, + CanGenericSignature sig, + ResilienceExpansion expansion); namespace { /// A CRTP helper class for doing things that depends on type /// classification. template class TypeClassifierBase : public CanTypeVisitor { - SILModule &M; Impl &asImpl() { return *static_cast(this); } protected: - TypeClassifierBase(SILModule &M) : M(M) {} + SILModule &M; + CanGenericSignature Sig; + ResilienceExpansion Expansion; + TypeClassifierBase(SILModule &M, CanGenericSignature Sig, + ResilienceExpansion Expansion) + : M(M), Sig(Sig), Expansion(Expansion) {} public: // The subclass should implement: @@ -218,10 +224,30 @@ namespace { // Dependent types should be contextualized before visiting. + CanGenericSignature getGenericSignature() { + if (Sig) + return Sig; + return M.Types.getCurGenericContext(); + } + RetTy visitGenericTypeParamType(CanGenericTypeParamType type) { + if (auto genericSig = getGenericSignature()) { + if (genericSig->requiresClass(type, *M.getSwiftModule())) { + return asImpl().handleReference(type); + } else { + return asImpl().handleAddressOnly(type); + } + } llvm_unreachable("should have substituted dependent type into context"); } RetTy visitDependentMemberType(CanDependentMemberType type) { + if (auto genericSig = getGenericSignature()) { + if (genericSig->requiresClass(type, *M.getSwiftModule())) { + return asImpl().handleReference(type); + } else { + return asImpl().handleAddressOnly(type); + } + } llvm_unreachable("should have substituted dependent type into context"); } @@ -229,9 +255,34 @@ namespace { return asImpl().handleTrivial(type); } - RetTy visitUnownedStorageType(CanUnownedStorageType type) { + bool hasNativeReferenceCounting(CanType type) { + if (type->isTypeParameter()) { + auto signature = getGenericSignature(); + assert(signature && "dependent type without generic signature?!"); + assert(signature->requiresClass(type, *M.getSwiftModule())); + + // If we have a superclass bound, recurse on that. This should + // always terminate: even if we allow + // + // at some point the type-checker should prove acyclic-ness. + auto bound = signature->getSuperclassBound(type, *M.getSwiftModule()); + if (bound) { + return hasNativeReferenceCounting(bound->getCanonicalType()); + } + + // Ask whether Builtin.UnknownObject uses native reference counting. + auto &ctx = M.getASTContext(); + return ctx.TheUnknownObjectType-> + usesNativeReferenceCounting(ResilienceExpansion::Maximal); + } + // FIXME: resilience - if (type->isLoadable(ResilienceExpansion::Maximal)) { + return type->usesNativeReferenceCounting(ResilienceExpansion::Maximal); + } + + RetTy visitUnownedStorageType(CanUnownedStorageType type) { + // FIXME: avoid this duplication of the behavior of isLoadable. + if (hasNativeReferenceCounting(type.getReferentType())) { return asImpl().visitLoadableUnownedStorageType(type); } else { return asImpl().visitAddressOnlyUnownedStorageType(type); @@ -290,6 +341,17 @@ namespace { return asImpl().visitAnyEnumType(type, type->getDecl()); } RetTy visitAnyEnumType(CanType type, EnumDecl *D) { + // If we're using a generic signature different from + // M.Types.getCurGenericContext(), we have to map the + // type into context first because the rest of type + // lowering doesn't have a generic signature plumbed + // through. + if (Sig && type->hasTypeParameter()) { + auto builder = M.getASTContext().getOrCreateArchetypeBuilder( + Sig, M.getSwiftModule()); + type = builder->substDependentType(type)->getCanonicalType(); + } + // Consult the type lowering. auto &lowering = M.Types.getTypeLowering(type); return handleClassificationFromLowering(type, lowering); @@ -313,6 +375,17 @@ namespace { } RetTy visitAnyStructType(CanType type, StructDecl *D) { + // If we're using a generic signature different from + // M.Types.getCurGenericContext(), we have to map the + // type into context first because the rest of type + // lowering doesn't have a generic signature plumbed + // through. + if (Sig && type->hasTypeParameter()) { + auto builder = M.getASTContext().getOrCreateArchetypeBuilder( + Sig, M.getSwiftModule()); + type = builder->substDependentType(type)->getCanonicalType(); + } + // Consult the type lowering. This means we implicitly get // caching, but that type lowering needs to override this case. auto &lowering = M.Types.getTypeLowering(type); @@ -327,7 +400,7 @@ namespace { // SIL lowering to catch unsupported recursive value types. bool isAddressOnly = false; for (auto eltType : type.getElementTypes()) { - switch (classifyType(eltType, M)) { + switch (classifyType(eltType, M, Sig, Expansion)) { case LoweredTypeKind::Trivial: continue; case LoweredTypeKind::AddressOnly: @@ -366,7 +439,9 @@ namespace { class TypeClassifier : public TypeClassifierBase { public: - TypeClassifier(SILModule &M) : TypeClassifierBase(M) {} + TypeClassifier(SILModule &M, CanGenericSignature Sig, + ResilienceExpansion Expansion) + : TypeClassifierBase(M, Sig, Expansion) {} LoweredTypeKind handleReference(CanType type) { return LoweredTypeKind::Reference; @@ -383,17 +458,20 @@ namespace { }; } -static LoweredTypeKind classifyType(CanType type, SILModule &M) { - if (type->hasTypeParameter()) - type = M.Types.getArchetypes().substDependentType(type)->getCanonicalType(); - return TypeClassifier(M).visit(type); +static LoweredTypeKind classifyType(CanType type, SILModule &M, + CanGenericSignature sig, + ResilienceExpansion expansion) { + return TypeClassifier(M, sig, expansion).visit(type); } /// True if the type, or the referenced type of an address /// type, is address-only. For example, it could be a resilient struct or /// something of unknown size. -bool SILType::isAddressOnly(CanType type, SILModule &M) { - return classifyType(type, M) == LoweredTypeKind::AddressOnly; +bool SILType::isAddressOnly(CanType type, SILModule &M, + CanGenericSignature sig, + ResilienceExpansion expansion) { + return classifyType(type, M, sig, expansion) + == LoweredTypeKind::AddressOnly; } namespace { @@ -976,8 +1054,11 @@ namespace { CanType OrigType; IsDependent_t Dependent; public: - LowerType(TypeConverter &TC, CanType OrigType, IsDependent_t Dependent) - : TypeClassifierBase(TC.M), TC(TC), OrigType(OrigType), + LowerType(TypeConverter &TC, CanType OrigType, + CanGenericSignature Sig, ResilienceExpansion Expansion, + IsDependent_t Dependent) + : TypeClassifierBase(TC.M, Sig, Expansion), + TC(TC), OrigType(OrigType), Dependent(Dependent) {} const TypeLowering *handleTrivial(CanType type) { @@ -1004,7 +1085,7 @@ namespace { auto unownedBaseType = CanUnownedStorageType::get( dynamicSelfType.getSelfType()); - return LowerType(TC, unownedBaseType, Dependent) + return LowerType(TC, unownedBaseType, Sig, Expansion, Dependent) .visit(unownedBaseType); } @@ -1024,7 +1105,7 @@ namespace { auto unmanagedBaseType = CanUnmanagedStorageType::get( dynamicSelfType.getSelfType()); - return LowerType(TC, unmanagedBaseType, Dependent) + return LowerType(TC, unmanagedBaseType, Sig, Expansion, Dependent) .visit(unmanagedBaseType); } @@ -1039,7 +1120,7 @@ namespace { ->getCanonicalType(); auto weakBaseType = CanWeakStorageType::get(optBaseType); - return LowerType(TC, weakBaseType, Dependent) + return LowerType(TC, weakBaseType, Sig, Expansion, Dependent) .visit(weakBaseType); } @@ -1086,7 +1167,7 @@ namespace { // For now, if the type does not have a fixed layout in all resilience // domains, we will treat it as address-only in SIL. - if (!D->hasFixedLayout()) + if (!D->hasFixedLayout(M.getSwiftModule(), Expansion)) isAddressOnly = true; // Classify the type according to its stored properties. @@ -1094,7 +1175,8 @@ namespace { for (auto field : D->getStoredProperties()) { auto substFieldType = structType->getTypeOfMember(D->getModuleContext(), field, nullptr); - switch (classifyType(substFieldType->getCanonicalType(), TC.M)) { + switch (classifyType(substFieldType->getCanonicalType(), + M, Sig, Expansion)) { case LoweredTypeKind::AddressOnly: isAddressOnly = true; break; @@ -1122,7 +1204,7 @@ namespace { // For now, if the type does not have a fixed layout in all resilience // domains, we will treat it as address-only in SIL. - if (!D->hasFixedLayout()) + if (!D->hasFixedLayout(M.getSwiftModule(), Expansion)) isAddressOnly = true; // Lower Self? as if it were Whatever? and Self! as if it were Whatever!. @@ -1182,7 +1264,8 @@ namespace { elt->getArgumentInterfaceType()) ->getCanonicalType(); - switch (classifyType(substEltType->getCanonicalType(), TC.M)) { + switch (classifyType(substEltType->getCanonicalType(), + M, Sig, Expansion)) { case LoweredTypeKind::AddressOnly: isAddressOnly = true; break; @@ -1204,7 +1287,7 @@ namespace { const TypeLowering *visitDynamicSelfType(CanDynamicSelfType type) { return LowerType(TC, cast(OrigType).getSelfType(), - Dependent) + Sig, Expansion, Dependent) .visit(type.getSelfType()); } @@ -1216,8 +1299,6 @@ TypeConverter::TypeConverter(SILModule &m) } TypeConverter::~TypeConverter() { - assert(!GenericArchetypes.hasValue() && "generic context was never popped?!"); - // The bump pointer allocator destructor will deallocate but not destroy all // our independent TypeLowerings. for (auto &ti : IndependentTypes) { @@ -1371,7 +1452,7 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, CanType substType = origSubstType->getCanonicalType(); auto key = getTypeKey(origType, substType, uncurryLevel); - assert(!key.isDependent() || GenericArchetypes.hasValue() + assert((!key.isDependent() || CurGenericContext) && "dependent type outside of generic context?!"); if (auto existing = find(key)) @@ -1393,7 +1474,7 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, auto origMeta = origType.getAs(); if (!origMeta) { // If the metatype matches a dependent type, it must be thick. - assert(origType.isOpaque()); + assert(origType.isTypeParameter()); repr = MetatypeRepresentation::Thick; } else { // Otherwise, we're thin if the metatype is thinnable both @@ -1454,12 +1535,14 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, AbstractionPattern origLoweredType = [&] { if (origType.isExactType(substType)) { - return AbstractionPattern(substLoweredType); - } else if (origType.isOpaque()) { + return AbstractionPattern(origType.getGenericSignature(), + substLoweredType); + } else if (origType.isTypeParameter()) { return origType; } else { auto origFnType = cast(origType.getType()); - return AbstractionPattern(getLoweredASTFunctionType(origFnType, + return AbstractionPattern(origType.getGenericSignature(), + getLoweredASTFunctionType(origFnType, uncurryLevel, None)); } @@ -1480,9 +1563,9 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, assert(uncurryLevel == 0); - // inout and lvalue types are a special case for lowering, because they get + // inout types are a special case for lowering, because they get // completely removed and represented as 'address' SILTypes. - if (isa(substType) || isa(substType)) { + if (isa(substType)) { // Derive SILType for InOutType from the object type. CanType substObjectType = substType.getLValueOrInOutObjectType(); AbstractionPattern origObjectType = origType.getLValueObjectType(); @@ -1496,22 +1579,6 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, return *theInfo; } - // Lower the object type of boxes. - if (auto substBoxType = dyn_cast(substType)) { - AbstractionPattern origBoxed(origType.getAs()->getBoxedType()); - SILType loweredBoxedType = getLoweredType(origBoxed, - substBoxType->getBoxedType()); - auto loweredBoxType - = SILBoxType::get(loweredBoxedType.getSwiftRValueType()); - auto loweredBoxSILType - = SILType::getPrimitiveObjectType(loweredBoxType); - - auto *theInfo = new (*this, key.isDependent()) - ReferenceTypeLowering(loweredBoxSILType); - insert(key, theInfo); - return *theInfo; - } - // We need to lower function and metatype types within tuples. if (auto substTupleType = dyn_cast(substType)) { auto loweredType = getLoweredTupleType(*this, origType, substTupleType); @@ -1536,7 +1603,8 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, const TypeLowering &TypeConverter::getTypeLowering(SILType type) { auto loweredType = type.getSwiftRValueType(); - auto key = getTypeKey(AbstractionPattern(loweredType), loweredType, 0); + auto key = getTypeKey(AbstractionPattern(getCurGenericContext(), loweredType), + loweredType, 0); return getTypeLoweringForLoweredType(key); } @@ -1586,12 +1654,11 @@ getTypeLoweringForUncachedLoweredFunctionType(TypeKey key) { // Construct the SILFunctionType. CanType silFnType = getNativeSILFunctionType(M, key.OrigType, - cast(key.SubstType), cast(key.SubstType)); // Do a cached lookup under yet another key, just so later lookups // using the SILType will find the same TypeLowering object. - auto loweredKey = getTypeKey(AbstractionPattern(key.OrigType), silFnType, 0); + auto loweredKey = getTypeKey(key.OrigType, silFnType, 0); auto &lowering = getTypeLoweringForLoweredType(loweredKey); insert(key, &lowering); return lowering; @@ -1609,10 +1676,10 @@ TypeConverter::getTypeLoweringForUncachedLoweredType(TypeKey key) { insert(key, nullptr); CanType contextType = key.SubstType; - if (contextType->hasTypeParameter()) - contextType = getArchetypes().substDependentType(contextType) - ->getCanonicalType(); + // FIXME: Get expansion from SILFunction auto *theInfo = LowerType(*this, key.SubstType, + CanGenericSignature(), + ResilienceExpansion::Minimal, key.isDependent()).visit(contextType); insert(key, theInfo); return *theInfo; @@ -1651,12 +1718,7 @@ mapArchetypeToInterfaceType(const PrimaryArchetypeMap &primaryArchetypes, CanType TypeConverter::getInterfaceTypeOutOfContext(CanType contextTy, DeclContext *context) const { - GenericParamList *genericParams; - do { - genericParams = context->getGenericParamsOfContext(); - context = context->getParent(); - } while (!genericParams && context); - + GenericParamList *genericParams = context->getGenericParamsOfContext(); return getInterfaceTypeOutOfContext(contextTy, genericParams); } @@ -1701,28 +1763,6 @@ static CanAnyFunctionType getGlobalGetterType(CanType varType) { return CanFunctionType::get(TupleType::getEmpty(C), varType); } -/// Get the type of a default argument generator, () -> T. -static CanAnyFunctionType getDefaultArgGeneratorType(TypeConverter &TC, - AbstractFunctionDecl *AFD, - unsigned DefaultArgIndex, - ASTContext &context) { - auto resultTy = AFD->getDefaultArg(DefaultArgIndex).second->getCanonicalType(); - assert(resultTy && "Didn't find default argument?"); - - // Get the generic parameters from the surrounding context. - auto genericParams - = TC.getConstantInfo(SILDeclRef(AFD)) - .ContextGenericParams; - - if (genericParams) - return CanPolymorphicFunctionType::get(TupleType::getEmpty(context), - resultTy, - genericParams, - AnyFunctionType::ExtInfo()); - - return CanFunctionType::get(TupleType::getEmpty(context), resultTy); -} - /// Get the type of a default argument generator, () -> T. static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( TypeConverter &TC, @@ -1750,37 +1790,6 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( return CanFunctionType::get(TupleType::getEmpty(context), resultTy); } -/// Get the type of a destructor function. -static CanAnyFunctionType getDestructorType(DestructorDecl *dd, - bool isDeallocating, - ASTContext &C, - bool isForeign) { - auto classType = dd->getDeclContext()->getDeclaredTypeInContext() - ->getCanonicalType(); - - - assert((!isForeign || isDeallocating) - && "There are no foreign destroying destructors"); - AnyFunctionType::ExtInfo extInfo = - AnyFunctionType::ExtInfo(FunctionTypeRepresentation::Thin, - /*noreturn*/ false, - /*throws*/ false); - if (isForeign) - extInfo = extInfo - .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod); - else - extInfo = extInfo - .withSILRepresentation(SILFunctionTypeRepresentation::Method); - - CanType resultTy = isDeallocating? TupleType::getEmpty(C)->getCanonicalType() - : C.TheNativeObjectType; - - if (auto params = dd->getDeclContext()->getGenericParamsOfContext()) - return CanPolymorphicFunctionType::get(classType, resultTy, params, extInfo); - - return CanFunctionType::get(classType, resultTy, extInfo); -} - /// Get the type of a destructor function. static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, bool isDeallocating, @@ -1813,30 +1822,6 @@ static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, return CanFunctionType::get(classType, resultTy, extInfo); } -/// Retrieve the type of the ivar initializer or destroyer method for -/// a class. -static CanAnyFunctionType getIVarInitDestroyerType(ClassDecl *cd, - bool isObjC, - ASTContext &ctx, - bool isDestroyer) { - auto classType = cd->getDeclaredTypeInContext()->getCanonicalType(); - - auto emptyTupleTy = TupleType::getEmpty(ctx)->getCanonicalType(); - CanType resultType = isDestroyer? emptyTupleTy : classType; - auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, - /*noreturn*/ false, - /*throws*/ false); - extInfo = extInfo - .withSILRepresentation(isObjC? SILFunctionTypeRepresentation::ObjCMethod - : SILFunctionTypeRepresentation::Method); - - resultType = CanFunctionType::get(emptyTupleTy, resultType, extInfo); - if (auto params = cd->getGenericParams()) - return CanPolymorphicFunctionType::get(classType, resultType, params, - extInfo); - return CanFunctionType::get(classType, resultType, extInfo); -} - /// Retrieve the type of the ivar initializer or destroyer method for /// a class. static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, @@ -1863,22 +1848,6 @@ static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, return CanFunctionType::get(classType, resultType, extInfo); } -GenericParamList * -TypeConverter::getEffectiveGenericParamsForContext(DeclContext *dc) { - - // FIXME: This is a clunky way of uncurrying nested type parameters from - // a function context. - if (auto func = dyn_cast(dc)) { - return getConstantInfo(SILDeclRef(func)).ContextGenericParams; - } - - if (auto closure = dyn_cast(dc)) { - return getConstantInfo(SILDeclRef(closure)).ContextGenericParams; - } - - return dc->getGenericParamsOfContext(); -} - GenericParamList * TypeConverter::getEffectiveGenericParams(AnyFunctionRef fn, CaptureInfo captureInfo) { @@ -1888,8 +1857,8 @@ TypeConverter::getEffectiveGenericParams(AnyFunctionRef fn, !captureInfo.hasGenericParamCaptures()) { return nullptr; } - - return getEffectiveGenericParamsForContext(dc); + + return dc->getGenericParamsOfContext(); } CanGenericSignature @@ -1897,107 +1866,19 @@ TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn, CaptureInfo captureInfo) { auto dc = fn.getAsDeclContext(); - if (auto sig = dc->getGenericSignatureOfContext()) - return sig->getCanonicalSignature(); - - dc = dc->getParent(); - - if (dc->isLocalContext() && + // If this is a non-generic local function that does not capture any + // generic type parameters from the outer context, don't need a + // signature at all. + if (!dc->isInnermostContextGeneric() && + dc->getParent()->isLocalContext() && !captureInfo.hasGenericParamCaptures()) { return nullptr; } - // Find the innermost context that has a generic parameter list. - // FIXME: This is wrong for generic local functions in generic contexts. - // Their GenericParamList is not semantically a child of the context - // GenericParamList because they "capture" their context's already-bound - // archetypes. - while (!dc->getGenericSignatureOfContext()) { - dc = dc->getParent(); - if (!dc) return nullptr; - } - - auto sig = dc->getGenericSignatureOfContext(); - if (!sig) - return nullptr; - return sig->getCanonicalSignature(); -} - -CanAnyFunctionType -TypeConverter::getFunctionTypeWithCaptures(CanAnyFunctionType funcType, - AnyFunctionRef theClosure) { - // Get transitive closure of value captured by this function, and any - // captured functions. - auto captureInfo = getLoweredLocalCaptures(theClosure); - - // Capture generic parameters from the enclosing context if necessary. - GenericParamList *genericParams = - getEffectiveGenericParams(theClosure, captureInfo); - - // If we don't have any local captures (including function captures), - // there's no context to apply. - if (!theClosure.getCaptureInfo().hasLocalCaptures()) { - if (!genericParams) - return adjustFunctionType(funcType, - FunctionType::Representation::Thin); - - auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, - /*noreturn*/ false, - funcType->throws()); - if (funcType->isNoEscape()) - extInfo = extInfo.withNoEscape(); - - return CanPolymorphicFunctionType::get(funcType.getInput(), - funcType.getResult(), - genericParams, extInfo); - - } - - SmallVector inputFields; - - for (auto capture : captureInfo.getCaptures()) { - auto VD = capture.getDecl(); - // A capture of a 'var' or 'inout' variable is done with the underlying - // object type. - auto captureType = - VD->getType()->getLValueOrInOutObjectType()->getCanonicalType(); - - switch (getDeclCaptureKind(capture)) { - case CaptureKind::None: - break; - - case CaptureKind::StorageAddress: - // No-escape stored decls are captured by their raw address. - inputFields.push_back(TupleTypeElt(CanLValueType::get(captureType))); - break; - - case CaptureKind::Constant: - // Capture the value directly. - inputFields.push_back(TupleTypeElt(captureType)); - break; - case CaptureKind::Box: { - // Capture the owning box. - CanType boxTy = SILBoxType::get(captureType); - inputFields.push_back(boxTy); - break; - } - } - } - - CanType capturedInputs = - TupleType::get(inputFields, Context)->getCanonicalType(); - - auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, - /*noreturn*/ false, - funcType->throws()); - if (funcType->isNoEscape()) - extInfo = extInfo.withNoEscape(); + if (auto sig = dc->getGenericSignatureOfContext()) + return sig->getCanonicalSignature(); - if (genericParams) - return CanPolymorphicFunctionType::get(capturedInputs, funcType, - genericParams, extInfo); - - return CanFunctionType::get(capturedInputs, funcType, extInfo); + return nullptr; } CanAnyFunctionType @@ -2019,7 +1900,7 @@ TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, FunctionType::Representation::Thin); auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, - /*noreturn*/ false, + funcType->isNoReturn(), funcType->throws()); return CanGenericFunctionType::get(genericSig, @@ -2028,57 +1909,18 @@ TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, extInfo); } - SmallVector inputFields; - - for (auto capture : captureInfo.getCaptures()) { - // A capture of a 'var' or 'inout' variable is done with the underlying - // object type. - auto vd = capture.getDecl(); - auto captureType = - vd->getType()->getLValueOrInOutObjectType()->getCanonicalType(); - - switch (getDeclCaptureKind(capture)) { - case CaptureKind::None: - break; - - case CaptureKind::StorageAddress: - // No-escape stored decls are captured by their raw address. - // Unlike 'inout', captures are allowed to have well-typed, synchronized - // aliasing references, so capture the raw lvalue type instead. - inputFields.push_back(TupleTypeElt(CanLValueType::get(captureType))); - break; - - case CaptureKind::Constant: - // Capture the value directly. - inputFields.push_back(TupleTypeElt(captureType)); - break; - case CaptureKind::Box: { - // Capture the owning box. - CanType boxTy = SILBoxType::get(captureType); - inputFields.push_back(boxTy); - break; - } - } - } - - CanType capturedInputs = - TupleType::get(inputFields, Context)->getCanonicalType(); - - // Map context archetypes out of the captures. - capturedInputs = - getInterfaceTypeOutOfContext(capturedInputs, - theClosure.getAsDeclContext()); - + // Add an extra empty tuple level to represent the captures. We'll append the + // lowered capture types here. auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, /*noreturn*/ false, funcType->throws()); if (genericSig) return CanGenericFunctionType::get(genericSig, - capturedInputs, funcType, + Context.TheEmptyTupleType, funcType, extInfo); - return CanFunctionType::get(capturedInputs, funcType, extInfo); + return CanFunctionType::get(Context.TheEmptyTupleType, funcType, extInfo); } /// Replace any DynamicSelf types with their underlying Self type. @@ -2105,7 +1947,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { // parameters. auto funcTy = cast(ACE->getType()->getCanonicalType()); funcTy = cast( - getInterfaceTypeOutOfContext(funcTy, ACE->getParent())); + getInterfaceTypeOutOfContext(funcTy, ACE->getParent())); return getFunctionInterfaceTypeWithCaptures(funcTy, ACE); } @@ -2114,7 +1956,7 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { func->getInterfaceType()->getCanonicalType()); if (func->getParent() && func->getParent()->isLocalContext()) funcTy = cast( - getInterfaceTypeOutOfContext(funcTy, func->getParent())); + getInterfaceTypeOutOfContext(funcTy, func->getParent())); funcTy = cast(replaceDynamicSelfWithSelf(funcTy)); return getFunctionInterfaceTypeWithCaptures(funcTy, func); } @@ -2174,11 +2016,24 @@ TypeConverter::getConstantContextGenericParams(SILDeclRef c) { return {getEffectiveGenericParams(ACE, captureInfo), nullptr}; } FuncDecl *func = cast(vd); - // FIXME: For local generic functions we need to chain the local generic - // context to the outer context. - if (auto GP = func->getGenericParamsOfContext()) - return {GP, func->getGenericParams()}; auto captureInfo = getLoweredLocalCaptures(func); + + // FIXME: This is really weird: + // 1) For generic functions, generic methods and generic + // local functions, we return the function's generic + // parameter list twice. + // 2) For non-generic methods inside generic types, we + // return the generic type's parameters and nullptr. + // 3) For non-generic local functions, we return the + // outer function's parameters and nullptr. + // + // Local generic functions could probably be modeled better + // at the SIL level. + if (func->isInnermostContextGeneric() || + func->getDeclContext()->isGenericTypeContext()) { + if (auto GP = func->getGenericParamsOfContext()) + return {GP, func->getGenericParams()}; + } return {getEffectiveGenericParams(func, captureInfo), func->getGenericParams()}; } @@ -2212,60 +2067,6 @@ TypeConverter::getConstantContextGenericParams(SILDeclRef c) { } } -CanAnyFunctionType TypeConverter::makeConstantType(SILDeclRef c) { - ValueDecl *vd = c.loc.dyn_cast(); - - switch (c.kind) { - case SILDeclRef::Kind::Func: { - if (auto *ACE = c.loc.dyn_cast()) { - auto funcTy = cast(ACE->getType()->getCanonicalType()); - return getFunctionTypeWithCaptures(funcTy, ACE); - } - - FuncDecl *func = cast(vd); - auto funcTy = cast(func->getType()->getCanonicalType()); - funcTy = cast(replaceDynamicSelfWithSelf(funcTy)); - return getFunctionTypeWithCaptures(funcTy, func); - } - - case SILDeclRef::Kind::Allocator: - case SILDeclRef::Kind::EnumElement: - return cast(vd->getType()->getCanonicalType()); - - case SILDeclRef::Kind::Initializer: - return cast(cast(vd) - ->getInitializerType()->getCanonicalType()); - - case SILDeclRef::Kind::Destroyer: - case SILDeclRef::Kind::Deallocator: - return getDestructorType(cast(vd), - c.kind == SILDeclRef::Kind::Deallocator, - Context, - c.isForeign); - - case SILDeclRef::Kind::GlobalAccessor: { - VarDecl *var = cast(vd); - assert(var->hasStorage() && "constant ref to computed global var"); - return getGlobalAccessorType(var->getType()->getCanonicalType()); - } - case SILDeclRef::Kind::GlobalGetter: { - VarDecl *var = cast(vd); - assert(var->hasStorage() && "constant ref to computed global var"); - return getGlobalGetterType(var->getType()->getCanonicalType()); - } - case SILDeclRef::Kind::DefaultArgGenerator: - return getDefaultArgGeneratorType(*this, - cast(vd), - c.defaultArgIndex, Context); - case SILDeclRef::Kind::IVarInitializer: - return getIVarInitDestroyerType(cast(vd), c.isForeign, - Context, false); - case SILDeclRef::Kind::IVarDestroyer: - return getIVarInitDestroyerType(cast(vd), c.isForeign, - Context, true); - } -} - SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType) { // The l-value type is the result of applying substitutions to @@ -2311,16 +2112,10 @@ void TypeConverter::pushGenericContext(CanGenericSignature sig) { return; // GenericFunctionTypes shouldn't nest. - assert(!GenericArchetypes.hasValue() && "already in generic context?!"); assert(DependentTypes.empty() && "already in generic context?!"); assert(!CurGenericContext && "already in generic context!"); CurGenericContext = sig; - - // Prepare the ArchetypeBuilder with the generic signature. - GenericArchetypes.emplace(*M.getSwiftModule(), M.getASTContext().Diags); - if (GenericArchetypes->addGenericSignature(sig, false)) - llvm_unreachable("error adding generic signature to archetype builder?!"); } void TypeConverter::popGenericContext(CanGenericSignature sig) { @@ -2328,7 +2123,6 @@ void TypeConverter::popGenericContext(CanGenericSignature sig) { if (!sig) return; - assert(GenericArchetypes.hasValue() && "not in generic context?!"); assert(CurGenericContext == sig && "unpaired push/pop"); // Erase our cached TypeLowering objects and associated mappings for dependent @@ -2345,7 +2139,6 @@ void TypeConverter::popGenericContext(CanGenericSignature sig) { } DependentTypes.clear(); DependentBPA.Reset(); - GenericArchetypes.reset(); CurGenericContext = nullptr; } diff --git a/lib/SILGen/ASTVisitor.h b/lib/SILGen/ASTVisitor.h index 1812175f45fe6..48c12e912b86a 100644 --- a/lib/SILGen/ASTVisitor.h +++ b/lib/SILGen/ASTVisitor.h @@ -1,8 +1,8 @@ -//===-- ASTVisitor.h - SILGen ASTVisitor specialization ---------*- C++ -*-===// +//===--- ASTVisitor.h - SILGen ASTVisitor specialization --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/ArgumentSource.cpp b/lib/SILGen/ArgumentSource.cpp index be59253d72ba2..0de8b0a0a8531 100644 --- a/lib/SILGen/ArgumentSource.cpp +++ b/lib/SILGen/ArgumentSource.cpp @@ -1,8 +1,8 @@ -//===--- ArgumentSource.cpp - Latent value representation -------*- C++ -*-===// +//===--- ArgumentSource.cpp - Latent value representation -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/ArgumentSource.h b/lib/SILGen/ArgumentSource.h index 3e88562cabb6c..548f81d8d859f 100644 --- a/lib/SILGen/ArgumentSource.h +++ b/lib/SILGen/ArgumentSource.h @@ -1,8 +1,8 @@ -//===--- ArgumentSource.h - Abstracted source of an argument 000-*- C++ -*-===// +//===--- ArgumentSource.h - Abstracted source of an argument ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/CMakeLists.txt b/lib/SILGen/CMakeLists.txt index 0b6d4836682a9..279df76d224e0 100644 --- a/lib/SILGen/CMakeLists.txt +++ b/lib/SILGen/CMakeLists.txt @@ -19,6 +19,7 @@ add_swift_library(swiftSILGen SILGenFunction.cpp SILGenGlobalVariable.cpp SILGenLValue.cpp + SILGenMaterializeForSet.cpp SILGenPattern.cpp SILGenPoly.cpp SILGenProfiling.cpp diff --git a/lib/SILGen/Cleanup.cpp b/lib/SILGen/Cleanup.cpp index 69eecdd4babcf..9f30ee118753a 100644 --- a/lib/SILGen/Cleanup.cpp +++ b/lib/SILGen/Cleanup.cpp @@ -1,8 +1,8 @@ -//===--- Cleanup.cpp - Implements the Cleanup mechanics --------------------==// +//===--- Cleanup.cpp - Implements the Cleanup mechanics -------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/Cleanup.h b/lib/SILGen/Cleanup.h index 444dd17ccc435..c1b498d9361e2 100644 --- a/lib/SILGen/Cleanup.h +++ b/lib/SILGen/Cleanup.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/Condition.cpp b/lib/SILGen/Condition.cpp index 305167c03266a..8351cc82f91d1 100644 --- a/lib/SILGen/Condition.cpp +++ b/lib/SILGen/Condition.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/Condition.h b/lib/SILGen/Condition.h index 5ccd88b8eb175..99cd03461f063 100644 --- a/lib/SILGen/Condition.h +++ b/lib/SILGen/Condition.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/ExitableFullExpr.h b/lib/SILGen/ExitableFullExpr.h index 2ca4983241cbb..2fbffbf3bfd89 100644 --- a/lib/SILGen/ExitableFullExpr.h +++ b/lib/SILGen/ExitableFullExpr.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/Initialization.h b/lib/SILGen/Initialization.h index ca8978791ede8..8dc59d0b70ee4 100644 --- a/lib/SILGen/Initialization.h +++ b/lib/SILGen/Initialization.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/JumpDest.h b/lib/SILGen/JumpDest.h index ce52061c2d19b..4cd11da99c04c 100644 --- a/lib/SILGen/JumpDest.h +++ b/lib/SILGen/JumpDest.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h index 74fcdf651fc6a..e6079655fe3b6 100644 --- a/lib/SILGen/LValue.h +++ b/lib/SILGen/LValue.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -334,6 +334,9 @@ class LValue { LValue &operator=(const LValue &) = delete; LValue &operator=(LValue &&) = default; + static LValue forValue(ManagedValue value, + CanType substFormalType); + static LValue forAddress(ManagedValue address, AbstractionPattern origFormalType, CanType substFormalType); diff --git a/lib/SILGen/ManagedValue.cpp b/lib/SILGen/ManagedValue.cpp index 248ac6b719864..8cc6d79c280a1 100644 --- a/lib/SILGen/ManagedValue.cpp +++ b/lib/SILGen/ManagedValue.cpp @@ -1,8 +1,8 @@ -//===--- ManagedValue.cpp - Value with cleanup ------------------*- C++ -*-===// +//===--- ManagedValue.cpp - Value with cleanup ----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -92,7 +92,7 @@ void ManagedValue::forwardInto(SILGenFunction &gen, SILLocation loc, SILValue address) { if (hasCleanup()) forwardCleanup(gen); - auto &addrTL = gen.getTypeLowering(address.getType()); + auto &addrTL = gen.getTypeLowering(address->getType()); gen.emitSemanticStore(loc, getValue(), address, addrTL, IsInitialization); } @@ -101,7 +101,7 @@ void ManagedValue::assignInto(SILGenFunction &gen, SILLocation loc, if (hasCleanup()) forwardCleanup(gen); - auto &addrTL = gen.getTypeLowering(address.getType()); + auto &addrTL = gen.getTypeLowering(address->getType()); gen.emitSemanticStore(loc, getValue(), address, addrTL, IsNotInitialization); } diff --git a/lib/SILGen/ManagedValue.h b/lib/SILGen/ManagedValue.h index d149fa345f832..88f6b32d87ad3 100644 --- a/lib/SILGen/ManagedValue.h +++ b/lib/SILGen/ManagedValue.h @@ -1,8 +1,8 @@ -//===--- RValue.h - Exploded RValue Representation --------------*- C++ -*-===// +//===--- ManagedValue.h - Exploded RValue Representation --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -79,7 +79,7 @@ class ManagedValue { /// Create a managed value for an l-value. static ManagedValue forLValue(SILValue value) { assert(value && "No value specified"); - assert(value.getType().isAddress() && + assert(value->getType().isAddress() && "lvalues always have isAddress() type"); return ManagedValue(value, true, CleanupHandle::invalid()); } @@ -119,7 +119,7 @@ class ManagedValue { } SILValue getValue() const { return valueAndFlag.getPointer(); } - SILType getType() const { return getValue().getType(); } + SILType getType() const { return getValue()->getType(); } CanType getSwiftType() const { diff --git a/lib/SILGen/RValue.cpp b/lib/SILGen/RValue.cpp index e2a6833a9f3aa..6cb4dad91cfc4 100644 --- a/lib/SILGen/RValue.cpp +++ b/lib/SILGen/RValue.cpp @@ -1,8 +1,8 @@ -//===--- RValue.cpp - Exploded RValue Representation ------------*- C++ -*-===// +//===--- RValue.cpp - Exploded RValue Representation ----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,7 @@ #include "Initialization.h" #include "RValue.h" +#include "swift/SIL/AbstractionPattern.h" #include "swift/SIL/SILArgument.h" #include "swift/AST/CanTypeVisitor.h" #include "swift/Basic/Fallthrough.h" @@ -33,6 +34,20 @@ static unsigned getTupleSize(CanType t) { return 1; } +static unsigned getRValueSize(AbstractionPattern pattern, CanType formalType) { + if (pattern.isTuple()) { + unsigned count = 0; + auto formalTupleType = cast(formalType); + for (auto i : indices(formalTupleType.getElementTypes())) { + count += getRValueSize(pattern.getTupleElementType(i), + formalTupleType.getElementType(i)); + } + return count; + } + + return 1; +} + /// Return the number of rvalue elements in the given canonical type. static unsigned getRValueSize(CanType type) { if (auto tupleType = dyn_cast(type)) { @@ -74,13 +89,13 @@ class ExplodeTupleValue CanType eltFormalType = tupleFormalType.getElementType(i); assert(eltFormalType->isMaterializable()); - auto eltTy = tuple.getType().getTupleElementType(i); - assert(eltTy.isAddress() == tuple.getType().isAddress()); + auto eltTy = tuple->getType().getTupleElementType(i); + assert(eltTy.isAddress() == tuple->getType().isAddress()); auto &eltTI = gen.getTypeLowering(eltTy); // Project the element. SILValue elt; - if (tuple.getType().isObject()) { + if (tuple->getType().isObject()) { assert(eltTI.isLoadable()); elt = gen.B.createTupleExtract(loc, tuple, i, eltTy); } else { @@ -279,7 +294,7 @@ class EmitBBArguments : public CanTypeVisitorgetAddressOrNull()) { if (isa(Address) && - gen.getTypeLowering(type).getLoweredType().isTrivial(gen.SGM.M)) { + gen.getTypeLowering(type).getLoweredType().isTrivial(gen.SGM.M)) { // Implode tuples in initialization of globals if they are // of trivial types. implodeTuple = true; @@ -393,6 +408,10 @@ RValue::RValue(CanType type) : type(type), elementsToBeAdded(getTupleSize(type)) { } +RValue::RValue(AbstractionPattern pattern, CanType type) + : type(type), elementsToBeAdded(getRValueSize(pattern, type)) { +} + void RValue::addElement(RValue &&element) & { assert(!element.isUsed() && "adding consumed value to r-value"); assert(!isComplete() && "rvalue already complete"); diff --git a/lib/SILGen/RValue.h b/lib/SILGen/RValue.h index 04cfcb85af924..946e73ce41ab3 100644 --- a/lib/SILGen/RValue.h +++ b/lib/SILGen/RValue.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -77,14 +77,14 @@ class RValue { return *this; } - /// Create a RValue from a single value. If the value is of tuple type, it + /// Create an RValue from a single value. If the value is of tuple type, it /// will be exploded. /// /// \param expr - the expression which yielded this r-value; its type /// will become the substituted formal type of this r-value RValue(SILGenFunction &gen, Expr *expr, ManagedValue v); - /// Create a RValue from a single value. If the value is of tuple type, it + /// Create an RValue from a single value. If the value is of tuple type, it /// will be exploded. RValue(SILGenFunction &gen, SILLocation l, CanType type, ManagedValue v); @@ -92,6 +92,12 @@ class RValue { /// ManagedValues. Used to implement the extractElement* methods. RValue(ArrayRef values, CanType type); + /// Create an RValue to which values will be subsequently added using + /// addElement(), with the level of tuple expansion in the input specified + /// by the abstraction pattern. The RValue will not be complete until all + /// the elements have been added. + explicit RValue(AbstractionPattern pattern, CanType type); + /// Create an RValue to which values will be subsequently added using /// addElement(). The RValue will not be complete until all the elements have /// been added. diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 27064d39300b7..4839f43fd9cbd 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/Basic/Timer.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "swift/Serialization/SerializedSILLoader.h" @@ -31,9 +32,9 @@ using namespace swift; using namespace Lowering; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // SILGenModule Class implementation -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// SILGenModule::SILGenModule(SILModule &M, Module *SM, bool makeModuleFragile) : M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr), @@ -405,10 +406,10 @@ void SILGenModule::postEmitFunction(SILDeclRef constant, void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) { // Emit any default argument generators. { - auto patterns = AFD->getBodyParamPatterns(); + auto paramLists = AFD->getParameterLists(); if (AFD->getDeclContext()->isTypeContext()) - patterns = patterns.slice(1); - emitDefaultArgGenerators(AFD, patterns); + paramLists = paramLists.slice(1); + emitDefaultArgGenerators(AFD, paramLists); } // If this is a function at global scope, it may close over a global variable. @@ -423,7 +424,7 @@ void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) { // Decls captured by value don't escape. auto It = TopLevelSGF->VarLocs.find(capture.getDecl()); if (It == TopLevelSGF->VarLocs.end() || - !It->getSecond().value.getType().isAddress()) + !It->getSecond().value->getType().isAddress()) continue; Captures.push_back(It->second.value); @@ -434,21 +435,29 @@ void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) { } } +static bool hasSILBody(FuncDecl *fd) { + if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet) + return !isa(fd->getDeclContext()); + + return fd->getBody(/*canSynthesize=*/false); +} + void SILGenModule::emitFunction(FuncDecl *fd) { SILDeclRef::Loc decl = fd; emitAbstractFuncDecl(fd); - // Emit the actual body of the function to a new SILFunction. Ignore - // prototypes and methods whose bodies weren't synthesized by now. - if (fd->getBody(/*canSynthesize=*/false)) { + if (hasSILBody(fd)) { PrettyStackTraceDecl stackTrace("emitting SIL for", fd); SILDeclRef constant(decl); emitOrDelayFunction(*this, constant, [this,constant,fd](SILFunction *f){ preEmitFunction(constant, fd, f, fd); - SILGenFunction(*this, *f).emitFunction(fd); + if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet) + SILGenFunction(*this, *f).emitMaterializeForSet(fd); + else + SILGenFunction(*this, *f).emitFunction(fd); postEmitFunction(constant, f); }); } @@ -768,21 +777,13 @@ void SILGenModule::emitGlobalGetter(VarDecl *global, } void SILGenModule::emitDefaultArgGenerators(SILDeclRef::Loc decl, - ArrayRef patterns) { + ArrayRef paramLists) { unsigned index = 0; - for (auto pattern : patterns) { - pattern = pattern->getSemanticsProvidingPattern(); - auto tuplePattern = dyn_cast(pattern); - if (!tuplePattern) { - ++index; - continue; - } - - for (auto &elt : tuplePattern->getElements()) { - if (auto handle = elt.getInit()) { - emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl,index), + for (auto paramList : paramLists) { + for (auto param : *paramList) { + if (auto handle = param->getDefaultValue()) + emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index), handle->getExpr()); - } ++index; } } @@ -906,6 +907,15 @@ void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) { void SILGenModule::visitVarDecl(VarDecl *vd) { if (vd->hasStorage()) addGlobalVariable(vd); + + if (vd->getStorageKind() == AbstractStorageDecl::StoredWithTrivialAccessors) { + // If the global variable has storage, it might also have synthesized + // accessors. Emit them here, since they won't appear anywhere else. + if (auto getter = vd->getGetter()) + emitFunction(getter); + if (auto setter = vd->getSetter()) + emitFunction(setter); + } } void SILGenModule::visitIfConfigDecl(IfConfigDecl *ICD) { @@ -969,11 +979,12 @@ static void emitTopLevelProlog(SILGenFunction &gen, SILLocation loc) { } } -void SILGenModule::useConformance(ProtocolConformance *conformance) { +void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) { // We don't need to emit dependent conformances. - if (!conformance) + if (conformanceRef.isAbstract()) return; + auto conformance = conformanceRef.getConcrete(); auto root = conformance->getRootNormalConformance(); // If we already emitted this witness table, we don't need to track the fact // we need it. @@ -995,7 +1006,7 @@ void SILGenModule::useConformance(ProtocolConformance *conformance) { void SILGenModule::useConformancesFromSubstitutions(ArrayRef subs) { for (auto &sub : subs) { - for (auto *conformance : sub.getConformances()) + for (auto conformance : sub.getConformances()) useConformance(conformance); } } @@ -1145,14 +1156,15 @@ void SILGenModule::emitSourceFile(SourceFile *sf, unsigned startElem) { visit(D); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // SILModule::constructSIL method implementation -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// std::unique_ptr SILModule::constructSIL(Module *mod, SILOptions &options, FileUnit *SF, Optional startElem, bool makeModuleFragile, bool isWholeModule) { + SharedTimer timer("SILGen"); const DeclContext *DC; if (startElem) { assert(SF && "cannot have a start element without a source file"); diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index f8f86de5138bd..11d5e1d1abc5f 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -227,7 +227,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { void emitFunction(FuncDecl *fd); /// \brief Generates code for the given closure expression and adds the - /// SILFunction to the current SILModule under the nane SILDeclRef(ce). + /// SILFunction to the current SILModule under the name SILDeclRef(ce). SILFunction *emitClosure(AbstractClosureExpr *ce); /// Generates code for the given ConstructorDecl and adds /// the SILFunction to the current SILModule under the name SILDeclRef(decl). @@ -247,7 +247,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emits the default argument generator for the given function. void emitDefaultArgGenerators(SILDeclRef::Loc decl, - ArrayRef patterns); + ArrayRef paramLists); /// Emits the curry thunk between two uncurry levels of a function. void emitCurryThunk(ValueDecl *fd, @@ -363,7 +363,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Mark a protocol conformance as used, so we know we need to emit it if /// it's in our TU. - void useConformance(ProtocolConformance *conformance); + void useConformance(ProtocolConformanceRef conformance); /// Mark protocol conformances from the given set of substitutions as used. void useConformancesFromSubstitutions(ArrayRef subs); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 19fa326764107..736b9299acd3c 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -29,44 +29,6 @@ using namespace swift; using namespace Lowering; -static SILDeclRef::Loc getLocForFunctionRef(AnyFunctionRef fn) { - if (auto afd = fn.getAbstractFunctionDecl()) { - return afd; - } else { - auto closure = fn.getAbstractClosureExpr(); - assert(closure); - return closure; - } -} - -/// Collect the captures necessary to invoke a local function into an -/// ArgumentSource. -static std::pair -emitCapturesAsArgumentSource(SILGenFunction &gen, - SILLocation loc, - AnyFunctionRef fn) { - SmallVector captures; - gen.emitCaptures(loc, fn, captures); - - // The capture array should match the explosion schema of the closure's - // first formal argument type. - auto info = gen.SGM.Types.getConstantInfo(SILDeclRef(getLocForFunctionRef(fn))); - auto subs = info.getForwardingSubstitutions(gen.getASTContext()); - auto origFormalTy = info.FormalInterfaceType; - CanFunctionType formalTy; - if (!subs.empty()) { - auto genericOrigFormalTy = cast(origFormalTy); - auto substTy = genericOrigFormalTy - ->substGenericArgs(gen.SGM.SwiftModule, subs) - ->getCanonicalType(); - formalTy = cast(substTy); - } else { - formalTy = cast(origFormalTy); - } - RValue rv(captures, formalTy.getInput()); - return {ArgumentSource(loc, std::move(rv)), formalTy}; -} - /// Retrieve the type to use for a method found via dynamic lookup. static CanAnyFunctionType getDynamicMethodFormalType(SILGenModule &SGM, SILValue proto, @@ -78,7 +40,7 @@ static CanAnyFunctionType getDynamicMethodFormalType(SILGenModule &SGM, if (member->isInstanceMember()) { selfTy = ctx.TheUnknownObjectType; } else { - selfTy = proto.getType().getSwiftType(); + selfTy = proto->getType().getSwiftType(); } auto extInfo = FunctionType::ExtInfo() .withRepresentation(FunctionType::Representation::Thin); @@ -121,7 +83,7 @@ replaceSelfTypeForDynamicLookup(ASTContext &ctx, } static Type getExistentialArchetype(SILValue existential) { - CanType ty = existential.getType().getSwiftRValueType(); + CanType ty = existential->getType().getSwiftRValueType(); if (ty->is()) return ty; return cast(ty)->getDecl()->getProtocolSelf()->getArchetype(); @@ -138,7 +100,7 @@ static CanSILFunctionType getDynamicMethodLoweredType(SILGenFunction &gen, if (methodName.getDecl()->isInstanceMember()) { selfTy = getExistentialArchetype(proto)->getCanonicalType(); } else { - selfTy = proto.getType().getSwiftType(); + selfTy = proto->getType().getSwiftType(); } // Replace the 'self' parameter type in the method type with it. @@ -146,6 +108,13 @@ static CanSILFunctionType getDynamicMethodLoweredType(SILGenFunction &gen, return replaceSelfTypeForDynamicLookup(ctx, methodTy, selfTy, methodName); } +static bool canUseStaticDispatch(SILGenFunction &gen, + SILDeclRef constant) { + auto *funcDecl = cast(constant.getDecl()); + auto thisModule = gen.SGM.M.getSwiftModule(); + return funcDecl->isFinal() || (thisModule == funcDecl->getModuleContext()); +} + namespace { /// Abstractly represents a callee, which may be a constant or function value, @@ -190,16 +159,15 @@ class Callee { }; SILValue SelfValue; ArrayRef Substitutions; - CanType OrigFormalOldType; CanType OrigFormalInterfaceType; CanAnyFunctionType SubstFormalType; Optional SpecializeLoc; bool HasSubstitutions = false; + Optional> Captures; // The pointer back to the AST node that produced the callee. SILLocation Loc; - private: Callee(ManagedValue indirectValue, @@ -208,21 +176,12 @@ class Callee { SILLocation L) : kind(Kind::IndirectValue), IndirectValue(indirectValue), - OrigFormalOldType(origFormalType), OrigFormalInterfaceType(origFormalType), SubstFormalType(substFormalType), Loc(L) {} - static CanAnyFunctionType getConstantFormalType(SILGenFunction &gen, - SILValue selfValue, - SILDeclRef fn) - SIL_FUNCTION_TYPE_DEPRECATED { - return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0)).FormalType; - } - static CanAnyFunctionType getConstantFormalInterfaceType(SILGenFunction &gen, - SILValue selfValue, SILDeclRef fn) { return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0)) .FormalInterfaceType; @@ -232,9 +191,7 @@ class Callee { CanAnyFunctionType substFormalType, SILLocation l) : kind(Kind::StandaloneFunction), Constant(standaloneFunction), - OrigFormalOldType(getConstantFormalType(gen, SILValue(), - standaloneFunction)), - OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, SILValue(), + OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, standaloneFunction)), SubstFormalType(substFormalType), Loc(l) @@ -248,22 +205,12 @@ class Callee { CanAnyFunctionType substFormalType, SILLocation l) : kind(methodKind), Constant(methodName), SelfValue(selfValue), - OrigFormalOldType(getConstantFormalType(gen, selfValue, methodName)), - OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, selfValue, - methodName)), + OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, methodName)), SubstFormalType(substFormalType), Loc(l) { } - static CanArchetypeType getArchetypeForSelf(CanType selfType) { - if (auto mt = dyn_cast(selfType)) { - return cast(mt.getInstanceType()); - } else { - return cast(selfType); - } - } - /// Build a clause that looks like 'origParamType' but uses 'selfType' /// in place of the underlying archetype. static CanType buildSubstSelfType(CanType origParamType, CanType selfType, @@ -282,49 +229,25 @@ class Callee { return CanType(TupleType::get(field, ctx)); } - // These first two asserts will crash before they return if - // they're actually wrong. - assert(getArchetypeForSelf(origParamType)); - assert(getArchetypeForSelf(selfType)); assert(isa(origParamType) == isa(selfType)); + assert(origParamType->getRValueInstanceType()->isTypeParameter()); + assert(selfType->getRValueInstanceType()->is()); + return selfType; } - CanType getWitnessMethodSelfType() const { - CanType type = SubstFormalType.getInput(); - if (auto tuple = dyn_cast(type)) { - assert(tuple->getNumElements() == 1); - type = tuple.getElementType(0); - } - if (auto lv = dyn_cast(type)) { - type = lv.getObjectType(); - } - assert(getArchetypeForSelf(type)); - return type; + CanArchetypeType getWitnessMethodSelfType() const { + return cast(SubstFormalType.getInput() + ->getRValueInstanceType() + ->getCanonicalType()); } CanSILFunctionType getSubstFunctionType(SILGenModule &SGM, - CanSILFunctionType origFnType, - CanAnyFunctionType origLoweredType, - unsigned uncurryLevel, - Optional constant, - const Optional &foreignError) const { + CanSILFunctionType origFnType) const { if (!HasSubstitutions) return origFnType; - - assert(origLoweredType); - auto substLoweredType = - SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel, - origLoweredType->getExtInfo(), - constant); - auto substLoweredInterfaceType = - SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel, - origLoweredType->getExtInfo(), - constant); - - return SGM.Types.substFunctionType(origFnType, origLoweredType, - substLoweredType, - substLoweredInterfaceType, - foreignError); + + return origFnType->substGenericArgs(SGM.M, SGM.SwiftModule, + Substitutions); } /// Add the 'self' clause back to the substituted formal type of @@ -341,13 +264,13 @@ class Callee { // Add the 'self' parameter back. We want it to look like a // substitution of the appropriate clause from the original type. - auto polyFormalType = cast(OrigFormalOldType); + auto origFormalType = cast(OrigFormalInterfaceType); auto substSelfType = - buildSubstSelfType(polyFormalType.getInput(), protocolSelfType, ctx); + buildSubstSelfType(origFormalType.getInput(), protocolSelfType, ctx); auto extInfo = FunctionType::ExtInfo(FunctionType::Representation::Thin, /*noreturn*/ false, - /*throws*/ polyFormalType->throws()); + /*throws*/ origFormalType->throws()); SubstFormalType = CanFunctionType::get(substSelfType, SubstFormalType, extInfo); @@ -359,17 +282,18 @@ class Callee { assert(kind == Kind::DynamicMethod); // Drop the original self clause. - CanType methodType = OrigFormalOldType; + CanType methodType = OrigFormalInterfaceType; methodType = cast(methodType).getResult(); // Replace it with the dynamic self type. - OrigFormalOldType = OrigFormalInterfaceType + OrigFormalInterfaceType = getDynamicMethodFormalType(SGM, SelfValue, Constant.getDecl(), Constant, methodType); + assert(!OrigFormalInterfaceType->hasTypeParameter()); // Add a self clause to the substituted type. - auto origFormalType = cast(OrigFormalOldType); + auto origFormalType = cast(OrigFormalInterfaceType); auto selfType = origFormalType.getInput(); SubstFormalType = CanFunctionType::get(selfType, SubstFormalType, @@ -452,9 +376,23 @@ class Callee { SpecializeLoc = loc; HasSubstitutions = true; } + + void setCaptures(SmallVectorImpl &&captures) { + Captures = std::move(captures); + } + + ArrayRef getCaptures() const { + if (Captures) + return *Captures; + return {}; + } + + bool hasCaptures() const { + return Captures.hasValue(); + } CanType getOrigFormalType() const { - return OrigFormalOldType; + return OrigFormalInterfaceType; } CanAnyFunctionType getSubstFormalType() const { @@ -585,8 +523,9 @@ class Callee { } // Look up the witness for the archetype. - auto selfType = getWitnessMethodSelfType(); - auto archetype = getArchetypeForSelf(selfType); + auto proto = Constant.getDecl()->getDeclContext() + ->isProtocolOrProtocolExtensionContext(); + auto archetype = getWitnessMethodSelfType(); // Get the openend existential value if the archetype is an opened // existential type. SILValue OpenedExistential; @@ -595,7 +534,7 @@ class Callee { SILValue fn = gen.B.createWitnessMethod(Loc, archetype, - /*conformance*/ nullptr, + ProtocolConformanceRef(proto), *constant, constantInfo.getSILType(), OpenedExistential, @@ -615,7 +554,7 @@ class Callee { auto closureType = replaceSelfTypeForDynamicLookup(gen.getASTContext(), constantInfo.SILFnType, - SelfValue.getType().getSwiftRValueType(), + SelfValue->getType().getSwiftRValueType(), Constant); SILValue fn = gen.B.createDynamicMethod(Loc, @@ -635,9 +574,7 @@ class Callee { } CanSILFunctionType substFnType = - getSubstFunctionType(gen.SGM, mv.getType().castTo(), - constantInfo.LoweredType, level, constant, - foreignError); + getSubstFunctionType(gen.SGM, mv.getType().castTo()); return std::make_tuple(mv, substFnType, foreignError, options); } @@ -759,7 +696,7 @@ static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc, // Store the reference into a temporary. auto temp = - gen.emitTemporaryAllocation(selfLoc, ref.getValue().getType()); + gen.emitTemporaryAllocation(selfLoc, ref.getValue()->getType()); gen.B.createStore(selfLoc, ref.getValue(), temp); // If we had a cleanup, create a cleanup at the new address. @@ -789,7 +726,7 @@ static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc, constant, substFnType, loc); } -/// An ASTVisitor for decomposing a a nesting of ApplyExprs into an initial +/// An ASTVisitor for decomposing a nesting of ApplyExprs into an initial /// Callee and a list of CallSites. The CallEmission class below uses these /// to generate the actual SIL call. /// @@ -1175,29 +1112,20 @@ class SILGenApply : public Lowering::ExprVisitor { CanFunctionType substFnType = getSubstFnType(); ArrayRef subs; - // If the decl ref requires captures, emit the capture params. - // The capture params behave like a "self" parameter as the first curry - // level of the function implementation. auto afd = dyn_cast(e->getDecl()); if (afd) { - if (afd->getCaptureInfo().hasLocalCaptures()) { - assert(!e->getDeclRef().isSpecialized() - && "generic local fns not implemented"); - - auto captures = emitCapturesAsArgumentSource(SGF, e, afd); - substFnType = captures.second; - setSelfParam(std::move(captures.first), captures.second.getInput()); - } - - // FIXME: We should be checking hasLocalCaptures() on the lowered - // captures in the constant info too, to generate more efficient - // code for mutually recursive local functions which otherwise - // capture no state. auto constantInfo = SGF.getConstantInfo(constant); // Forward local substitutions to a non-generic local function. if (afd->getParent()->isLocalContext() && !afd->getGenericParams()) subs = constantInfo.getForwardingSubstitutions(SGF.getASTContext()); + + // If there are captures, put the placeholder curry level in the formal + // type. + // TODO: Eliminate the need for this. + if (afd->getCaptureInfo().hasLocalCaptures()) + substFnType = CanFunctionType::get( + SGF.getASTContext().TheEmptyTupleType, substFnType); } if (e->getDeclRef().isSpecialized()) { @@ -1205,11 +1133,31 @@ class SILGenApply : public Lowering::ExprVisitor { subs = e->getDeclRef().getSubstitutions(); } + // Enum case constructor references are open-coded. if (isa(e->getDecl())) setCallee(Callee::forEnumElement(SGF, constant, substFnType, e)); else setCallee(Callee::forDirect(SGF, constant, substFnType, e)); + + // If the decl ref requires captures, emit the capture params. + if (afd) { + if (afd->getCaptureInfo().hasLocalCaptures()) { + assert(!e->getDeclRef().isSpecialized() + && "generic local fns not implemented"); + + SmallVector captures; + SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication, + captures); + ApplyCallee->setCaptures(std::move(captures)); + } + + // FIXME: We should be checking hasLocalCaptures() on the lowered + // captures in the constant info too, to generate more efficient + // code for mutually recursive local functions which otherwise + // capture no state. + + } // If there are substitutions, add them, always at depth 0. if (!subs.empty()) @@ -1224,16 +1172,8 @@ class SILGenApply : public Lowering::ExprVisitor { if (!SGF.SGM.hasFunction(constant)) SGF.SGM.emitClosure(e); - // If the closure requires captures, emit them. - // The capture params behave like a "self" parameter as the first curry - // level of the function implementation. ArrayRef subs; CanFunctionType substFnType = getSubstFnType(); - if (e->getCaptureInfo().hasLocalCaptures()) { - auto captures = emitCapturesAsArgumentSource(SGF, e, e); - substFnType = captures.second; - setSelfParam(std::move(captures.first), captures.second.getInput()); - } // FIXME: We should be checking hasLocalCaptures() on the lowered // captures in the constant info above, to generate more efficient @@ -1242,7 +1182,22 @@ class SILGenApply : public Lowering::ExprVisitor { auto constantInfo = SGF.getConstantInfo(constant); subs = constantInfo.getForwardingSubstitutions(SGF.getASTContext()); + // If there are captures, put the placeholder curry level in the formal + // type. + // TODO: Eliminate the need for this. + if (e->getCaptureInfo().hasLocalCaptures()) + substFnType = CanFunctionType::get( + SGF.getASTContext().TheEmptyTupleType, substFnType); + setCallee(Callee::forDirect(SGF, constant, substFnType, e)); + + // If the closure requires captures, emit them. + if (e->getCaptureInfo().hasLocalCaptures()) { + SmallVector captures; + SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication, + captures); + ApplyCallee->setCaptures(std::move(captures)); + } // If there are substitutions, add them, always at depth 0. if (!subs.empty()) ApplyCallee->setSubstitutions(SGF, e, subs, 0); @@ -1266,21 +1221,6 @@ class SILGenApply : public Lowering::ExprVisitor { visit(e->getRHS()); } - /// Skip over all of the 'Self'-related substitutions within the given set - /// of substitutions. - ArrayRef getNonSelfSubstitutions(ArrayRef subs) { - unsigned innerIdx = 0, n = subs.size(); - for (; innerIdx != n; ++innerIdx) { - auto archetype = subs[innerIdx].getArchetype(); - while (archetype->getParent()) - archetype = archetype->getParent(); - if (!archetype->getSelfProtocol()) - break; - } - - return subs.slice(innerIdx); - } - void visitFunctionConversionExpr(FunctionConversionExpr *e) { // FIXME: Check whether this function conversion requires us to build a // thunk. @@ -1331,12 +1271,7 @@ class SILGenApply : public Lowering::ExprVisitor { setSelfParam(ArgumentSource(arg, RValue(SGF, apply, superFormalType, super)), apply); - SILValue superMethod; - auto *funcDecl = cast(constant.getDecl()); - - auto Opts = SGF.B.getModule().getOptions(); - if (constant.isForeign || - (Opts.UseNativeSuperMethod && !funcDecl->isFinal())) { + if (constant.isForeign || !canUseStaticDispatch(SGF, constant)) { // All Objective-C methods and // non-final native Swift methods use dynamic dispatch. SILValue Input = super.getValue(); @@ -1423,7 +1358,7 @@ class SILGenApply : public Lowering::ExprVisitor { // Determine whether we'll need to use an allocating constructor (vs. the // initializing constructor). auto nominal = ctorRef->getDecl()->getDeclContext() - ->getDeclaredTypeOfContext()->getAnyNominal(); + ->isNominalTypeOrNominalTypeExtensionContext(); bool useAllocatingCtor; // Value types only have allocating initializers. @@ -1760,7 +1695,7 @@ static SILValue emitRawApply(SILGenFunction &gen, // Add the buffer for the indirect return if needed. assert(bool(resultAddr) == substFnType->hasIndirectResult()); if (substFnType->hasIndirectResult()) { - assert(resultAddr.getType() == + assert(resultAddr->getType() == substFnType->getIndirectResult().getSILType().getAddressType()); argValues.push_back(resultAddr); } @@ -1773,12 +1708,12 @@ static SILValue emitRawApply(SILGenFunction &gen, auto argValue = (inputTypes[i].isConsumed() ? args[i].forward(gen) : args[i].getValue()); #ifndef NDEBUG - if (argValue.getType() != inputTypes[i].getSILType()) { + if (argValue->getType() != inputTypes[i].getSILType()) { auto &out = llvm::errs(); out << "TYPE MISMATCH IN ARGUMENT " << i << " OF APPLY AT "; printSILLocationDescription(out, loc, gen.getASTContext()); out << " argument value: "; - argValue.print(out); + argValue->print(out); out << " parameter type: "; inputTypes[i].print(out); out << "\n"; @@ -1821,7 +1756,7 @@ static SILValue emitRawApply(SILGenFunction &gen, continue; SILValue argValue = args[i].forward(gen); - SILType argType = argValue.getType(); + SILType argType = argValue->getType(); CleanupLocation cleanupLoc = CleanupLocation::get(loc); if (!argType.isAddress()) gen.getTypeLowering(argType).emitDestroyRValue(gen.B, cleanupLoc, argValue); @@ -1960,7 +1895,7 @@ ManagedValue SILGenFunction::emitApply( } } - // If there's an foreign error parameter, fill it in. + // If there's a foreign error parameter, fill it in. Optional errorTempWriteback; ManagedValue errorTemp; if (foreignError) { @@ -2046,7 +1981,7 @@ ManagedValue SILGenFunction::emitApply( case ResultConvention::UnownedInnerPointer: // Autorelease the 'self' value to lifetime-extend it. - assert(lifetimeExtendedSelf.isValid() + assert(lifetimeExtendedSelf && "did not save lifetime-extended self param"); B.createAutoreleaseValue(loc, lifetimeExtendedSelf); SWIFT_FALLTHROUGH; @@ -2110,7 +2045,7 @@ static unsigned getFlattenedValueCount(AbstractionPattern origType, // If the original type is opaque and the substituted type is // materializable, the count is 1 anyway. - if (origType.isOpaque() && substTuple->isMaterializable()) + if (origType.isTypeParameter() && substTuple->isMaterializable()) return 1; // Otherwise, add up the elements. @@ -2264,7 +2199,7 @@ namespace { destAddr = gen.B.createIndexAddr(loc, destAddr, index); } - assert(destAddr.getType() == loweredSubstParamType.getAddressType()); + assert(destAddr->getType() == loweredSubstParamType.getAddressType()); auto &destTL = SharedInfo->getBaseTypeLowering(); Cleanup = gen.enterDormantTemporaryCleanup(destAddr, destTL); @@ -2334,7 +2269,7 @@ namespace { // materializable, the convention is actually to break it up // into materializable chunks. See the comment in SILType.cpp. if (isUnmaterializableTupleType(substArgType)) { - assert(origParamType.isOpaque()); + assert(origParamType.isTypeParameter()); emitExpanded(std::move(arg), origParamType); return; } @@ -2578,8 +2513,8 @@ namespace { arg.getType(), ctxt); break; case SILFunctionLanguage::C: - value = SGF.emitNativeToBridgedValue(loc, value, Rep, origParamType, - arg.getType(), param.getType()); + value = SGF.emitNativeToBridgedValue(loc, value, Rep, + param.getType()); break; } Args.push_back(value); @@ -2783,7 +2718,7 @@ void ArgEmitter::emitShuffle(Expr *inner, // opaque pattern; otherwise, it's a tuple of the de-shuffled // tuple elements. innerOrigParamType = origParamType; - if (!origParamType.isOpaque()) { + if (!origParamType.isTypeParameter()) { // That "tuple" might not actually be a tuple. if (innerElts.size() == 1 && !innerElts[0].hasName()) { innerOrigParamType = origInnerElts[0]; @@ -3015,7 +2950,8 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, } ManagedValue payloadMV; - AbstractionPattern origFormalType(element->getArgumentType()); + AbstractionPattern origFormalType = + SGM.M.Types.getAbstractionPattern(element); auto &payloadTL = getTypeLowering(origFormalType, payload.getSubstType()); @@ -3028,14 +2964,14 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, // throws, we know to deallocate the uninitialized box. if (element->isIndirect() || element->getParentEnum()->isIndirect()) { - auto box = B.createAllocBox(loc, payloadTL.getLoweredType()); + auto *box = B.createAllocBox(loc, payloadTL.getLoweredType()); + auto *addr = B.createProjectBox(loc, box); CleanupHandle initCleanup = enterDestroyCleanup(box); Cleanups.setCleanupState(initCleanup, CleanupState::Dormant); CleanupHandle uninitCleanup = enterDeallocBoxCleanup(*this, box); - BoxInitialization dest(box, box->getAddressResult(), - uninitCleanup, initCleanup); + BoxInitialization dest(box, addr, uninitCleanup, initCleanup); std::move(payload).forwardInto(*this, origFormalType, &dest, payloadTL); @@ -3111,6 +3047,24 @@ namespace { Params = Params.slice(0, Params.size() - count); return result; } + + ArrayRef + claimCaptureParams(ArrayRef captures) { + auto firstCapture = Params.size() - captures.size(); +#ifndef NDEBUG + assert(Params.size() >= captures.size() + && "more captures than params?!"); + for (unsigned i = 0; i < captures.size(); ++i) { + assert(Params[i + firstCapture].getSILType() + == captures[i].getType() + && "capture doesn't match param type"); + } +#endif + + auto result = Params.slice(firstCapture, captures.size()); + Params = Params.slice(0, firstCapture); + return result; + } ~ParamLowering() { assert(Params.empty() && "didn't consume all the parameters"); @@ -3190,7 +3144,7 @@ namespace { assert(isArgPlusZeroOrTrivialRValue() && "Must have a plus zero or " "trivial rvalue as an argument."); SILValue ArgSILValue = ArgValue.peekRValue().peekScalarValue(); - SILType ArgTy = ArgSILValue.getType(); + SILType ArgTy = ArgSILValue->getType(); // If we are trivial, there is no difference in between +1 and +0 since // a trivial object is not reference counted. @@ -3246,7 +3200,14 @@ namespace { uncurries(callee.getNaturalUncurryLevel() + 1), applied(false), AssumedPlusZeroSelf(assumedPlusZeroSelf) - {} + { + // Subtract an uncurry level for captures, if any. + // TODO: Encapsulate this better in Callee. + if (this->callee.hasCaptures()) { + assert(uncurries > 0 && "captures w/o uncurry level?"); + --uncurries; + } + } /// Add a level of function application by passing in its possibly /// unevaluated arguments and their formal type. @@ -3431,6 +3392,19 @@ namespace { if (!uncurriedSites.back().throws()) { initialOptions |= ApplyOptions::DoesNotThrow; } + + // Collect the captures, if any. + if (callee.hasCaptures()) { + // The captures are represented as a placeholder curry level in the + // formal type. + // TODO: Remove this hack. + paramLowering.claimCaptureParams(callee.getCaptures()); + claimNextParamClause(origFormalType); + claimNextParamClause(formalType); + args.push_back({}); + args.back().append(callee.getCaptures().begin(), + callee.getCaptures().end()); + } // Collect the arguments to the uncurried call. for (auto &site : uncurriedSites) { @@ -3461,13 +3435,13 @@ namespace { for (auto &argSet : reversed(args)) uncurriedArgs.append(argSet.begin(), argSet.end()); args = {}; - + // Emit the uncurried call. // Special case for superclass method calls. if (isPartiallyAppliedSuperMethod(uncurryLevel)) { assert(uncurriedArgs.size() == 1 && - "Can only partially apply the self parameater of a super method call"); + "Can only partially apply the self parameter of a super method call"); auto constant = callee.getMethodName(); auto loc = uncurriedLoc.getValue(); @@ -3505,7 +3479,7 @@ namespace { closureTy); result = ManagedValue::forUnmanaged(partialApply); // Handle a regular call. - } else if (!specializedEmitter) { + } else if (!specializedEmitter) { result = gen.emitApply(uncurriedLoc.getValue(), mv, callee.getSubstitutions(), uncurriedArgs, @@ -3648,11 +3622,11 @@ SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, ArrayRef args, SGFContext ctx) { auto origFormalType = - cast(fn->getType()->getCanonicalType()); + cast(fn->getInterfaceType()->getCanonicalType()); auto substFormalType = origFormalType; if (!subs.empty()) { - auto polyFnType = cast(substFormalType); - auto applied = polyFnType->substGenericArgs(SGM.SwiftModule, subs); + auto genericFnType = cast(substFormalType); + auto applied = genericFnType->substGenericArgs(SGM.SwiftModule, subs); substFormalType = cast(applied->getCanonicalType()); } @@ -3671,7 +3645,7 @@ SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, == SILFunctionLanguage::Swift); return emitApply(loc, mv, subs, args, substFnType, - AbstractionPattern(origFormalType.getResult()), + AbstractionPattern(origFormalType).getFunctionResultType(), substFormalType.getResult(), options, None, None, ctx); } @@ -3685,13 +3659,12 @@ SILGenFunction::emitUninitializedArrayAllocation(Type ArrayTy, SILLocation Loc) { auto &Ctx = getASTContext(); auto allocate = Ctx.getAllocateUninitializedArray(nullptr); - auto allocateArchetypes = allocate->getGenericParams()->getAllArchetypes(); auto arrayElementTy = ArrayTy->castTo() ->getGenericArgs()[0]; // Invoke the intrinsic, which returns a tuple. - Substitution sub{allocateArchetypes[0], arrayElementTy, {}}; + Substitution sub{arrayElementTy, {}}; auto result = emitApplyOfLibraryIntrinsic(Loc, allocate, sub, ManagedValue::forUnmanaged(Length), @@ -3712,13 +3685,12 @@ void SILGenFunction::emitUninitializedArrayDeallocation(SILLocation loc, SILValue array) { auto &Ctx = getASTContext(); auto deallocate = Ctx.getDeallocateUninitializedArray(nullptr); - auto archetypes = deallocate->getGenericParams()->getAllArchetypes(); CanType arrayElementTy = - array.getType().castTo().getGenericArgs()[0]; + array->getType().castTo().getGenericArgs()[0]; // Invoke the intrinsic. - Substitution sub{archetypes[0], arrayElementTy, {}}; + Substitution sub{arrayElementTy, {}}; emitApplyOfLibraryIntrinsic(loc, deallocate, sub, ManagedValue::forUnmanaged(array), SGFContext()); @@ -3775,7 +3747,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen, } } - // Dispatch in a struct/enum or to an final method is always direct. + // Dispatch in a struct/enum or to a final method is always direct. if (!isClassDispatch || decl->isFinal()) return Callee::forDirect(gen, constant, substAccessorType, loc); @@ -3791,8 +3763,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen, while (auto *upcast = dyn_cast(self)) self = upcast->getOperand(); - auto Opts = gen.B.getModule().getOptions(); - if (constant.isForeign || (Opts.UseNativeSuperMethod && !decl->isFinal())) + if (constant.isForeign || !canUseStaticDispatch(gen, constant)) return Callee::forSuperMethod(gen, self, constant, substAccessorType,loc); return Callee::forDirect(gen, constant, substAccessorType, loc); @@ -3809,18 +3780,11 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &gen, { SILConstantInfo constantInfo = gen.getConstantInfo(constant); - // Collect captures if the accessor has them. - auto accessorFn = cast(constant.getDecl()); - if (accessorFn->getCaptureInfo().hasLocalCaptures()) { - assert(!selfValue && "local property has self param?!"); - selfValue = emitCapturesAsArgumentSource(gen, loc, accessorFn).first; - } - // Apply substitutions to the callee type. - CanAnyFunctionType substAccessorType = constantInfo.FormalType; + CanAnyFunctionType substAccessorType = constantInfo.FormalInterfaceType; if (!substitutions.empty()) { - auto polyFn = cast(substAccessorType); - auto substFn = polyFn->substGenericArgs(gen.SGM.SwiftModule, substitutions); + auto genericFn = cast(substAccessorType); + auto substFn = genericFn->substGenericArgs(gen.SGM.SwiftModule, substitutions); substAccessorType = cast(substFn->getCanonicalType()); } @@ -3829,6 +3793,16 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &gen, Callee callee = getBaseAccessorFunctionRef(gen, loc, constant, selfValue, isSuper, isDirectUse, substAccessorType, substitutions); + + // Collect captures if the accessor has them. + auto accessorFn = cast(constant.getDecl()); + if (accessorFn->getCaptureInfo().hasLocalCaptures()) { + assert(!selfValue && "local property has self param?!"); + SmallVector captures; + gen.emitCaptures(loc, accessorFn, CaptureEmission::ImmediateApplication, + captures); + callee.setCaptures(std::move(captures)); + } // If there are substitutions, specialize the generic accessor. // FIXME: Generic subscript operator could add another layer of @@ -3981,12 +3955,17 @@ emitGetAccessor(SILLocation loc, SILDeclRef get, Callee getter = emitSpecializedAccessorFunctionRef(*this, loc, get, substitutions, selfValue, isSuper, isDirectUse); + bool hasCaptures = getter.hasCaptures(); + bool hasSelf = (bool)selfValue; CanAnyFunctionType accessType = getter.getSubstFormalType(); CallEmission emission(*this, std::move(getter), std::move(writebackScope)); // Self -> - if (selfValue) { + if (hasSelf) { emission.addCallSite(loc, std::move(selfValue), accessType); + } + // TODO: Have Callee encapsulate the captures better. + if (hasSelf || hasCaptures) { accessType = cast(accessType.getResult()); } // Index or () if none. @@ -4019,12 +3998,17 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set, Callee setter = emitSpecializedAccessorFunctionRef(*this, loc, set, substitutions, selfValue, isSuper, isDirectUse); + bool hasCaptures = setter.hasCaptures(); + bool hasSelf = (bool)selfValue; CanAnyFunctionType accessType = setter.getSubstFormalType(); CallEmission emission(*this, std::move(setter), std::move(writebackScope)); // Self -> - if (selfValue) { + if (hasSelf) { emission.addCallSite(loc, std::move(selfValue), accessType); + } + // TODO: Have Callee encapsulate the captures better. + if (hasSelf || hasCaptures) { accessType = cast(accessType.getResult()); } @@ -4074,12 +4058,17 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet, materializeForSet, substitutions, selfValue, isSuper, isDirectUse); + bool hasCaptures = callee.hasCaptures(); + bool hasSelf = (bool)selfValue; CanAnyFunctionType accessType = callee.getSubstFormalType(); CallEmission emission(*this, std::move(callee), std::move(writebackScope)); // Self -> - if (selfValue) { + if (hasSelf) { emission.addCallSite(loc, std::move(selfValue), accessType); + } + // TODO: Have Callee encapsulate the captures better. + if (hasSelf || hasCaptures) { accessType = cast(accessType.getResult()); } @@ -4106,7 +4095,7 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet, // Project out the materialized address. SILValue address = B.createTupleExtract(loc, pointerAndOptionalCallback, 0); - address = B.createPointerToAddress(loc, address, buffer.getType()); + address = B.createPointerToAddress(loc, address, buffer->getType()); // Project out the optional callback. SILValue optionalCallback = @@ -4143,12 +4132,17 @@ emitAddressorAccessor(SILLocation loc, SILDeclRef addressor, emitSpecializedAccessorFunctionRef(*this, loc, addressor, substitutions, selfValue, isSuper, isDirectUse); + bool hasCaptures = callee.hasCaptures(); + bool hasSelf = (bool)selfValue; CanAnyFunctionType accessType = callee.getSubstFormalType(); CallEmission emission(*this, std::move(callee), std::move(writebackScope)); // Self -> - if (selfValue) { + if (hasSelf) { emission.addCallSite(loc, std::move(selfValue), accessType); + } + // TODO: Have Callee encapsulate the captures better. + if (hasSelf || hasCaptures) { accessType = cast(accessType.getResult()); } // Index or () if none. @@ -4183,7 +4177,7 @@ emitAddressorAccessor(SILLocation loc, SILDeclRef addressor, // Drill down to the raw pointer using intrinsic knowledge of those types. auto pointerType = - pointer.getType().castTo()->getDecl(); + pointer->getType().castTo()->getDecl(); auto props = pointerType->getStoredProperties(); assert(props.begin() != props.end()); assert(std::next(props.begin()) == props.end()); @@ -4239,7 +4233,7 @@ static SILValue emitDynamicPartialApply(SILGenFunction &gen, // Pop the self type off of the function type. // Just to be weird, partially applying an objc method produces a native // function (?!) - auto fnTy = method.getType().castTo(); + auto fnTy = method->getType().castTo(); // If the original method has an @unowned_inner_pointer return, the partial // application thunk will lifetime-extend 'self' for us. auto resultInfo = fnTy->getResult(); @@ -4262,11 +4256,11 @@ static SILValue emitDynamicPartialApply(SILGenFunction &gen, CastConsumptionKind::CopyOnSuccess); self = gen.getManagedValue(loc, CMV).forward(gen); #else - if (!self.getType().isAddress()) + if (!self->getType().isAddress()) gen.B.emitRetainValueOperation(loc, self); #endif - SILValue result = gen.B.createPartialApply(loc, method, method.getType(), {}, + SILValue result = gen.B.createPartialApply(loc, method, method->getType(), {}, self, SILType::getPrimitiveObjectType(partialApplyTy)); // If necessary, thunk to the native ownership conventions and bridged types. auto nativeTy = gen.getLoweredLoadableType(methodTy).castTo(); @@ -4286,7 +4280,7 @@ RValue SILGenFunction::emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, SILValue operand = base.getValue(); if (!e->getMember().getDecl()->isInstanceMember()) { - auto metatype = operand.getType().castTo(); + auto metatype = operand->getType().castTo(); assert(metatype->getRepresentation() == MetatypeRepresentation::Thick); metatype = CanMetatypeType::get(metatype.getInstanceType(), MetatypeRepresentation::ObjC); @@ -4345,7 +4339,7 @@ RValue SILGenFunction::emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, SILValue result = emitDynamicPartialApply(*this, e, memberArg, operand, cast(methodTy)); if (isa(e->getMember().getDecl())) { - result = B.createApply(e, result, result.getType(), + result = B.createApply(e, result, result->getType(), getLoweredType(valueTy), {}, {}); } @@ -4430,7 +4424,7 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, llvm::SmallVector indexArgs; std::move(index).forwardAll(*this, indexArgs); auto &valueTL = getTypeLowering(valueTy); - result = B.createApply(e, result, result.getType(), + result = B.createApply(e, result, result->getType(), valueTL.getLoweredType(), {}, indexArgs); // Package up the result in an optional. diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 92d7442123e63..974f91bfae675 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,6 +15,7 @@ #include "Scope.h" #include "swift/AST/AST.h" #include "swift/AST/ForeignErrorConvention.h" +#include "swift/AST/ParameterList.h" #include "swift/Basic/Fallthrough.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/TypeLowering.h" @@ -30,7 +31,7 @@ static ManagedValue emitBridgeStringToNSString(SILGenFunction &gen, = gen.emitGlobalFunctionRef(loc, gen.SGM.getStringToNSStringFn()); SILValue nsstr = gen.B.createApply(loc, stringToNSStringFn, - stringToNSStringFn.getType(), + stringToNSStringFn->getType(), gen.getLoweredType(gen.SGM.Types.getNSStringType()), {}, str.forward(gen)); return gen.emitManagedRValueWithCleanup(nsstr); @@ -52,7 +53,7 @@ static ManagedValue emitBridgeNSStringToString(SILGenFunction &gen, } SILType nativeTy = gen.getLoweredType(gen.SGM.Types.getStringType()); - SILValue str = gen.B.createApply(loc, bridgeFn, bridgeFn.getType(), nativeTy, + SILValue str = gen.B.createApply(loc, bridgeFn, bridgeFn->getType(), nativeTy, {}, { nsstr.forward(gen) }); return gen.emitManagedRValueWithCleanup(str); @@ -76,7 +77,7 @@ static ManagedValue emitBridgeCollectionFromNative(SILGenFunction &gen, auto inputTy = collection.getType().getSwiftRValueType()->castTo(); auto subs = inputTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); - auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); + auto substFnType = bridgeFn->getType().substGenericArgs(gen.SGM.M, subs); SILValue bridged = gen.B.createApply(loc, bridgeFn, substFnType, bridgedTy, @@ -102,7 +103,7 @@ static ManagedValue emitBridgeCollectionToNative(SILGenFunction &gen, auto collectionTy = nativeTy.getSwiftRValueType()->castTo(); auto subs = collectionTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); - auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); + auto substFnType = bridgeFn->getType().substGenericArgs(gen.SGM.M, subs); Type inputType = collection.getType().getSwiftRValueType(); if (!inputType->getOptionalObjectType()) { @@ -132,7 +133,7 @@ static ManagedValue emitBridgeBoolToObjCBool(SILGenFunction &gen, SILType resultTy =gen.getLoweredLoadableType(gen.SGM.Types.getObjCBoolType()); SILValue result = gen.B.createApply(loc, boolToObjCBoolFn, - boolToObjCBoolFn.getType(), + boolToObjCBoolFn->getType(), resultTy, {}, swiftBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); } @@ -148,7 +149,7 @@ static ManagedValue emitBridgeBoolToDarwinBoolean(SILGenFunction &gen, gen.getLoweredLoadableType(gen.SGM.Types.getDarwinBooleanType()); SILValue result = gen.B.createApply(loc, boolToDarwinBooleanFn, - boolToDarwinBooleanFn.getType(), + boolToDarwinBooleanFn->getType(), resultTy, {}, swiftBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); } @@ -162,7 +163,7 @@ static ManagedValue emitBridgeForeignBoolToBool(SILGenFunction &gen, SILType resultTy = gen.getLoweredLoadableType(gen.SGM.Types.getBoolType()); - SILValue result = gen.B.createApply(loc, bridgingFn, bridgingFn.getType(), + SILValue result = gen.B.createApply(loc, bridgingFn, bridgingFn->getType(), resultTy, {}, foreignBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); } @@ -264,8 +265,6 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &gen, // Bridge the result back to ObjC. result = gen.emitNativeToBridgedValue(loc, result, SILFunctionTypeRepresentation::CFunctionPointer, - AbstractionPattern(result.getType().getSwiftRValueType()), - result.getType().getSwiftRValueType(), blockTy->getSILResult().getSwiftRValueType()); auto resultVal = result.forward(gen); @@ -275,7 +274,7 @@ static void buildFuncToBlockInvokeBody(SILGenFunction &gen, switch (blockTy->getResult().getConvention()) { case ResultConvention::UnownedInnerPointer: case ResultConvention::Unowned: - assert(gen.getTypeLowering(resultVal.getType()).isTrivial() + assert(gen.getTypeLowering(resultVal->getType()).isTrivial() && "nontrivial result is returned unowned?!"); gen.B.createReturn(loc, resultVal); break; @@ -440,8 +439,6 @@ static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen, ManagedValue SILGenFunction::emitNativeToBridgedValue(SILLocation loc, ManagedValue v, SILFunctionTypeRepresentation destRep, - AbstractionPattern origNativeTy, - CanType substNativeTy, CanType loweredBridgedTy){ switch (getSILFunctionLanguage(destRep)) { case SILFunctionLanguage::Swift: @@ -480,8 +477,6 @@ static void buildBlockToFuncThunkBody(SILGenFunction &gen, auto mv = gen.emitManagedRValueWithCleanup(v, tl); args.push_back(gen.emitNativeToBridgedValue(loc, mv, SILFunctionTypeRepresentation::Block, - AbstractionPattern(param.getType()), - param.getType(), blockParam.getType())); } @@ -658,13 +653,13 @@ ManagedValue SILGenFunction::emitBridgedToNativeError(SILLocation loc, #endif auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getNSErrorToErrorTypeFn()); - auto bridgeFnType = bridgeFn.getType().castTo(); + auto bridgeFnType = bridgeFn->getType().castTo(); auto nativeErrorType = bridgeFnType->getResult().getSILType(); assert(bridgeFnType->getResult().getConvention() == ResultConvention::Owned); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Owned); - SILValue nativeError = B.createApply(loc, bridgeFn, bridgeFn.getType(), + SILValue nativeError = B.createApply(loc, bridgeFn, bridgeFn->getType(), nativeErrorType, {}, bridgedError.forward(*this)); return emitManagedRValueWithCleanup(nativeError); @@ -678,12 +673,12 @@ ManagedValue SILGenFunction::emitNativeToBridgedError(SILLocation loc, "only handling NSError for now"); auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getErrorTypeToNSErrorFn()); - auto bridgeFnType = bridgeFn.getType().castTo(); + auto bridgeFnType = bridgeFn->getType().castTo(); assert(bridgeFnType->getResult().getConvention() == ResultConvention::Owned); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Owned); - SILValue bridgedError = B.createApply(loc, bridgeFn, bridgeFn.getType(), + SILValue bridgedError = B.createApply(loc, bridgeFn, bridgeFn->getType(), bridgeFnType->getResult().getSILType(), {}, nativeError.forward(*this)); return emitManagedRValueWithCleanup(bridgedError); @@ -697,14 +692,12 @@ static SILValue emitBridgeReturnValue(SILGenFunction &gen, SILLocation loc, SILValue result, SILFunctionTypeRepresentation fnTypeRepr, - AbstractionPattern origNativeTy, - CanType substNativeTy, CanType bridgedTy) { Scope scope(gen.Cleanups, CleanupLocation::get(loc)); ManagedValue native = gen.emitManagedRValueWithCleanup(result); ManagedValue bridged = gen.emitNativeToBridgedValue(loc, native, fnTypeRepr, - origNativeTy, substNativeTy, bridgedTy); + bridgedTy); return bridged.forward(gen); } @@ -714,13 +707,13 @@ static void emitObjCReturnValue(SILGenFunction &gen, SILLocation loc, SILValue result, SILResultInfo resultInfo) { - assert(result.getType() == resultInfo.getSILType()); + assert(result->getType() == resultInfo.getSILType()); // Autorelease the bridged result if necessary. switch (resultInfo.getConvention()) { case ResultConvention::UnownedInnerPointer: case ResultConvention::Unowned: - assert(gen.getTypeLowering(result.getType()).isTrivial() + assert(gen.getTypeLowering(result->getType()).isTrivial() && "nontrivial result is returned unowned?!"); SWIFT_FALLTHROUGH; case ResultConvention::Autoreleased: @@ -734,10 +727,10 @@ static void emitObjCReturnValue(SILGenFunction &gen, static SILValue emitObjCUnconsumedArgument(SILGenFunction &gen, SILLocation loc, SILValue arg) { - auto &lowering = gen.getTypeLowering(arg.getType()); + auto &lowering = gen.getTypeLowering(arg->getType()); // If address-only, make a +1 copy and operate on that. if (lowering.isAddressOnly()) { - auto tmp = gen.emitTemporaryAllocation(loc, arg.getType().getObjectType()); + auto tmp = gen.emitTemporaryAllocation(loc, arg->getType().getObjectType()); gen.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization); return tmp; } @@ -805,7 +798,7 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen, // If this parameter is deallocating, emit an unmanaged rvalue and // continue. The object has the deallocating bit set so retain, release is - // irrelevent. + // irrelevant. if (inputs[i].isDeallocating()) { bridgedArgs.push_back(ManagedValue::forUnmanaged(arg)); continue; @@ -889,9 +882,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { SGM.M, SGM.M.getSwiftModule(), subs); SILType substSILTy = SILType::getPrimitiveObjectType(substTy); - CanType substNativeResultType = nativeInfo.LoweredType.getResult(); - AbstractionPattern origNativeResultType = - AbstractionPattern(substNativeResultType); CanType bridgedResultType = objcResultTy.getType(); SILValue result; @@ -908,8 +898,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { // Now bridge the return value. result = emitBridgeReturnValue(*this, loc, result, objcFnTy->getRepresentation(), - origNativeResultType, - substNativeResultType, bridgedResultType); } else { SILBasicBlock *contBB = createBasicBlock(); @@ -930,8 +918,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { SILValue bridgedResult = emitBridgeReturnValueForForeignError(loc, nativeResult, objcFnTy->getRepresentation(), - origNativeResultType, - substNativeResultType, objcResultTy.getSILType(), foreignErrorSlot, *foreignError); B.createBranch(loc, contBB, bridgedResult); @@ -984,7 +970,8 @@ getThunkedForeignFunctionRef(SILGenFunction &gen, SILValue OpenedExistential; if (!cast(thisType)->getOpenedExistentialType().isNull()) OpenedExistential = thisArg; - return gen.B.createWitnessMethod(loc, thisType, nullptr, foreign, + auto conformance = ProtocolConformanceRef(cast(dc)); + return gen.B.createWitnessMethod(loc, thisType, conformance, foreign, foreignCI.getSILType(), OpenedExistential); @@ -1023,19 +1010,19 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { } // Forward the arguments. - auto forwardedPatterns = fd->getBodyParamPatterns(); + auto forwardedParameters = fd->getParameterLists(); // For allocating constructors, 'self' is a metatype, not the 'self' value // formally present in the constructor body. Type allocatorSelfType; if (thunk.kind == SILDeclRef::Kind::Allocator) { - allocatorSelfType = forwardedPatterns[0]->getType(); - forwardedPatterns = forwardedPatterns.slice(1); + allocatorSelfType = forwardedParameters[0]->getType(getASTContext()); + forwardedParameters = forwardedParameters.slice(1); } SmallVector params; - for (auto *paramPattern : reversed(forwardedPatterns)) - bindParametersForForwarding(paramPattern, params); + for (auto *paramList : reversed(forwardedParameters)) + bindParametersForForwarding(paramList, params); if (allocatorSelfType) { auto selfMetatype = CanMetatypeType::get(allocatorSelfType->getCanonicalType(), @@ -1109,8 +1096,6 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { foreignFnTy->getParameters()[foreignArgIndex++].getSILType(); args.push_back(emitNativeToBridgedValue(fd, param, SILFunctionTypeRepresentation::CFunctionPointer, - AbstractionPattern(param.getSwiftType()), - param.getSwiftType(), foreignArgTy.getSwiftRValueType())); } @@ -1121,7 +1106,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, subs, foreignCI); - auto fnType = fn.getType().castTo(); + auto fnType = fn->getType().castTo(); fnType = fnType->substGenericArgs(SGM.M, SGM.SwiftModule, subs); result = emitApply(fd, ManagedValue::forUnmanaged(fn), diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 51e847c979421..7402b7e31e474 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -532,7 +532,7 @@ emitBuiltinCastReference(SILGenFunction &gen, // dest are RC identical, store the reference into the source temp without // a retain. The cast will load the reference from the source temp and // store it into a dest temp effectively forwarding the cleanup. - fromAddr = gen.emitTemporaryAllocation(loc, srcVal.getType()); + fromAddr = gen.emitTemporaryAllocation(loc, srcVal->getType()); gen.B.createStore(loc, srcVal, fromAddr); } else { // The cast loads directly from the source address. @@ -570,7 +570,7 @@ static ManagedValue emitBuiltinReinterpretCast(SILGenFunction &gen, // If the from value is loadable, move it to a buffer. if (fromTL.isLoadable()) { - fromAddr = gen.emitTemporaryAllocation(loc, args[0].getValue().getType()); + fromAddr = gen.emitTemporaryAllocation(loc, args[0].getValue()->getType()); gen.B.createStore(loc, args[0].getValue(), fromAddr); } else { fromAddr = args[0].getValue(); @@ -693,223 +693,6 @@ static ManagedValue emitBuiltinCastBitPatternFromBridgeObject( return ManagedValue::forUnmanaged(result); } -static ManagedValue emitBuiltinMarkDependence(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - ArrayRef args, - CanFunctionType formalApplyType, - SGFContext C) { - assert(args.size() == 2 && "markDependence should have two value args"); - assert(subs.size() == 2 && "markDependence should have two generic args"); - - SILValue result = - gen.B.createMarkDependence(loc, args[0].forward(gen), args[1].getValue()); - return gen.emitManagedRValueWithCleanup(result); -} - - -using ValueBufferOperation = - llvm::function_ref; - -static ManagedValue -emitValueBufferOperation(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - Expr *tupleArg, - CanFunctionType formalApplyType, - SGFContext C, - const ValueBufferOperation &operation) { - - assert(subs.size() == 1); - auto args = decomposeArguments(gen, tupleArg, 2); - - // It's really not safe if we ever need to do writeback for this, - // but go ahead and satisfy the rules, and bound the cleanups while - // we're at it. - FullExpr fullExpr(gen.Cleanups, CleanupLocation::get(loc)); - WritebackScope writebackScope(gen); - - LValue bufferLV = gen.emitLValue(args[0], AccessKind::ReadWrite); - - // Ignore the metatype argument. - gen.emitIgnoredExpr(args[1]); - - ManagedValue bufferAddr = - gen.emitAddressOfLValue(args[0], std::move(bufferLV), - AccessKind::ReadWrite); - - // Like Builtin.load/initialize, we use the current abstraction level. - // (This is crucial, because we expect the result to be passed to - // those builtins!) - SILType valueTy = gen.getLoweredType(subs[0].getReplacement()); - - return operation(bufferAddr.getValue(), valueTy); -} - - -static ManagedValue -emitBuiltinAllocValueBuffer(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - Expr *tupleArg, - CanFunctionType formalApplyType, - SGFContext C) { - return emitValueBufferOperation(gen, loc, subs, tupleArg, formalApplyType, C, - [&](SILValue bufferAddr, SILType valueTy) - -> ManagedValue { - SILValue result = - gen.B.createAllocValueBuffer(loc, valueTy, bufferAddr); - result = gen.B.createAddressToPointer(loc, result, - SILType::getRawPointerType(gen.getASTContext())); - return ManagedValue::forUnmanaged(result); - }); -} - -static ManagedValue -emitBuiltinProjectValueBuffer(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - Expr *tupleArg, - CanFunctionType formalApplyType, - SGFContext C) { - return emitValueBufferOperation(gen, loc, subs, tupleArg, formalApplyType, C, - [&](SILValue bufferAddr, SILType valueTy) - -> ManagedValue { - SILValue result = - gen.B.createProjectValueBuffer(loc, valueTy, bufferAddr); - result = gen.B.createAddressToPointer(loc, result, - SILType::getRawPointerType(gen.getASTContext())); - return ManagedValue::forUnmanaged(result); - }); -} - -static ManagedValue -emitBuiltinDeallocValueBuffer(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - Expr *tupleArg, - CanFunctionType formalApplyType, - SGFContext C) { - return emitValueBufferOperation(gen, loc, subs, tupleArg, formalApplyType, C, - [&](SILValue bufferAddr, SILType valueTy) - -> ManagedValue { - gen.B.createDeallocValueBuffer(loc, valueTy, bufferAddr); - return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); - }); -} - -static CanType makeThick(CanMetatypeType oldMetatype) { - return CanMetatypeType::get(oldMetatype.getInstanceType(), - MetatypeRepresentation::Thick); -} - -static SILFunction * -adjustMetatypeArgumentToThick(SILGenModule &SGM, SILFunction *fn) { - assert(fn->canBeDeleted() && "cannot adjust type of function with uses!"); - auto oldLoweredType = fn->getLoweredFunctionType(); - - auto oldMetatypeParam = oldLoweredType->getParameters().back(); - assert(oldMetatypeParam.getConvention() - == ParameterConvention::Direct_Unowned); - auto oldMetatypeType = cast(oldMetatypeParam.getType()); - - switch (oldMetatypeType->getRepresentation()) { - // If the metatype is already thick, we're fine. - case MetatypeRepresentation::Thick: - return fn; - - // If it's thin, we need to rewrite it to be thick. - case MetatypeRepresentation::Thin: - break; - - case MetatypeRepresentation::ObjC: - llvm_unreachable("unexpected objc metatype!"); - } - - SmallVector newParamTypes; - newParamTypes.append(oldLoweredType->getParameters().begin(), - oldLoweredType->getParameters().end()); - newParamTypes.back() = - SILParameterInfo(makeThick(oldMetatypeType), - ParameterConvention::Direct_Unowned); - - // Unsafely replace the old lowered type. - CanSILFunctionType newLoweredType = - SILFunctionType::get(oldLoweredType->getGenericSignature(), - oldLoweredType->getExtInfo(), - oldLoweredType->getCalleeConvention(), - newParamTypes, - oldLoweredType->getResult(), - oldLoweredType->getOptionalErrorResult(), - SGM.getASTContext()); - fn->rewriteLoweredTypeUnsafe(newLoweredType); - - // Replace the old BB argument. - SILBasicBlock *entryBB = &fn->front(); - auto argIndex = entryBB->bbarg_size() - 1; - SILArgument *oldArg = entryBB->getBBArg(argIndex); - SILType oldArgType = oldArg->getType(); - const ValueDecl *oldArgDecl = oldArg->getDecl(); - SILType newArgType = SILType::getPrimitiveObjectType( - makeThick(cast(oldArgType.getSwiftRValueType()))); - // If we need a thin metatype anywhere, synthesize it. - if (!oldArg->use_empty()) { - SILLocation loc = const_cast(oldArgDecl); - loc.markAsPrologue(); - - SILBuilder builder(entryBB, entryBB->begin()); - auto newThinMetatype = builder.createMetatype(loc, oldArgType); - oldArg->replaceAllUsesWith(newThinMetatype); - } - entryBB->replaceBBArg(argIndex, newArgType, oldArgDecl); - - return fn; -} - -static ManagedValue -emitBuiltinMakeMaterializeForSetCallback(SILGenFunction &gen, - SILLocation loc, - ArrayRef subs, - Expr *arg, - CanFunctionType formalApplyType, - SGFContext C) { - assert(subs.size() == 1); - - // The argument must be a closure. This should also catch the - // possibility of captures. - auto closure = dyn_cast(arg->getSemanticsProvidingExpr()); - if (!closure) { - gen.SGM.diagnose(loc, diag::invalid_sil_builtin, - "argument to Builtin.makeMaterializeForSetCallback must be a closure."); - return gen.emitUndef(loc, gen.getLoweredType(arg->getType())); - } - - // FIXME: just emit the closure with a specific abstraction pattern. - SILFunction *fn = gen.SGM.emitClosure(closure); - fn = adjustMetatypeArgumentToThick(gen.SGM, fn); - - SILValue result = gen.B.createFunctionRef(loc, fn); - - // If the closure is polymorphic, get a monomorphic value. - if (fn->getLoweredFunctionType()->isPolymorphic()) { - // FIXME: use some sort of partial_apply_thin_recoverable - // instruction that relies on there being a thick metatype - // argument instead of all these unsafe casts. - - // Convert to Builtin.RawPointer. - result = gen.B.createThinFunctionToPointer(loc, result, - SILType::getRawPointerType(gen.getASTContext())); - - // Convert back to a partial-applied thin function type. - auto &resultTL = gen.getTypeLowering(formalApplyType.getResult()); - result = gen.B.createPointerToThinFunction(loc, result, - resultTL.getLoweredType()); - } - - return ManagedValue::forUnmanaged(result); -} - // This should only accept as an operand type single-refcounted-pointer types, // class existentials, or single-payload enums (optional). Type checking must be // deferred until IRGen so Builtin.isUnique can be called from a transparent diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 0ab0a995945f7..1bada802510f1 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,7 +30,7 @@ static SILValue emitConstructorMetatypeArg(SILGenFunction &gen, // the metatype as its first argument, like a static function. Type metatype = ctor->getType()->castTo()->getInput(); auto &AC = gen.getASTContext(); - auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), + auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), AC.getIdentifier("$metatype"), SourceLoc(), AC.getIdentifier("$metatype"), metatype, ctor->getDeclContext()); @@ -52,7 +52,7 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &gen, return tuple; } else { auto &AC = gen.getASTContext(); - auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), + auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), AC.getIdentifier("$implicit_value"), SourceLoc(), AC.getIdentifier("$implicit_value"), ty, DC); @@ -68,7 +68,7 @@ static void emitImplicitValueConstructor(SILGenFunction &gen, RegularLocation Loc(ctor); Loc.markAutoGenerated(); // FIXME: Handle 'self' along with the other arguments. - auto *TP = cast(ctor->getBodyParamPatterns()[1]); + auto *paramList = ctor->getParameterList(1); auto selfTyCan = ctor->getImplicitSelfDecl()->getType()->getInOutObjectType(); SILType selfTy = gen.getLoweredType(selfTyCan); @@ -76,7 +76,7 @@ static void emitImplicitValueConstructor(SILGenFunction &gen, SILValue resultSlot; if (selfTy.isAddressOnly(gen.SGM.M)) { auto &AC = gen.getASTContext(); - auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), + auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), selfTyCan, @@ -86,12 +86,13 @@ static void emitImplicitValueConstructor(SILGenFunction &gen, // Emit the elementwise arguments. SmallVector elements; - for (size_t i = 0, size = TP->getNumElements(); i < size; ++i) { - auto *P = cast(TP->getElement(i).getPattern()); + for (size_t i = 0, size = paramList->size(); i < size; ++i) { + auto ¶m = paramList->get(i); elements.push_back( emitImplicitValueConstructorArg(gen, Loc, - P->getType()->getCanonicalType(), ctor)); + param->getType()->getCanonicalType(), + ctor)); } emitConstructorMetatypeArg(gen, ctor); @@ -165,13 +166,6 @@ static void emitImplicitValueConstructor(SILGenFunction &gen, return; } -static unsigned countSwiftArgs(ArrayRef Patterns) { - unsigned N = 0; - for (auto p : Patterns) - p->forEachVariable([&](VarDecl *) { ++N; }); - return N; -} - void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { MagicFunctionName = SILGenModule::getMagicFunctionName(ctor); @@ -191,7 +185,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { && "can't emit a class ctor here"); // Self is a curried argument and thus comes last. - unsigned N = countSwiftArgs(ctor->getBodyParamPatterns()[1]) + 1; + unsigned N = ctor->getParameterList(1)->size() + 1; // Allocate the local variable for 'self'. emitLocalVariableWithCleanup(selfDecl, false, N)->finishInitialization(*this); @@ -207,7 +201,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { } // Emit the prolog. - emitProlog(ctor->getBodyParamPatterns()[1], ctor->getResultType(), ctor); + emitProlog(ctor->getParameterList(1), ctor->getResultType(), ctor); emitConstructorMetatypeArg(*this, ctor); // Create a basic block to jump to for the implicit 'self' return. @@ -306,7 +300,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { case OTK_ImplicitlyUnwrappedOptional: returnAddress = B.createInitEnumDataAddr(ctor, IndirectReturnAddress, getASTContext().getOptionalSomeDecl(ctor->getFailability()), - selfLV.getType()); + selfLV->getType()); break; } @@ -359,7 +353,7 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) { std::unique_ptr dest; if (enumTI.isAddressOnly()) { auto &AC = getASTContext(); - auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), + auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), @@ -429,7 +423,7 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) { // Forward the constructor arguments. // FIXME: Handle 'self' along with the other body patterns. SmallVector args; - bindParametersForForwarding(ctor->getBodyParamPatterns()[1], args); + bindParametersForForwarding(ctor->getParameterList(1), args); SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor); @@ -459,7 +453,7 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) { // When using Objective-C allocation, convert the metatype // argument to an Objective-C metatype. if (useObjCAllocation) { - auto metaTy = allocArg.getType().castTo(); + auto metaTy = allocArg->getType().castTo(); metaTy = CanMetatypeType::get(metaTy.getInstanceType(), MetatypeRepresentation::ObjC); allocArg = B.createThickToObjCMetatype(Loc, allocArg, @@ -566,7 +560,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { // Emit the prolog for the non-self arguments. // FIXME: Handle self along with the other body patterns. - emitProlog(ctor->getBodyParamPatterns()[1], + emitProlog(ctor->getParameterList(1), TupleType::getEmpty(F.getASTContext()), ctor); SILType selfTy = getLoweredLoadableType(selfDecl->getType()); diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp index 3bf879a9a00db..5d48c6b9914cf 100644 --- a/lib/SILGen/SILGenConvert.cpp +++ b/lib/SILGen/SILGenConvert.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -87,10 +87,7 @@ void SILGenFunction::emitInjectOptionalValueInto(SILLocation loc, someDecl, loweredPayloadTy.getAddressType()); - CanType formalOptType = optType.getSwiftRValueType(); - auto archetype = formalOptType->getNominalOrBoundGenericNominal() - ->getGenericParams()->getPrimaryArchetypes()[0]; - AbstractionPattern origType(archetype); + AbstractionPattern origType = AbstractionPattern::getOpaque(); // Emit the value into the payload area. TemporaryInitialization emitInto(destPayload, CleanupHandle::invalid()); @@ -141,11 +138,8 @@ getOptionalSomeValue(SILLocation loc, ManagedValue value, assert(OTK != OTK_None); auto someDecl = getASTContext().getOptionalSomeDecl(OTK); - auto archetype = formalOptType->getNominalOrBoundGenericNominal() - ->getGenericParams()->getPrimaryArchetypes()[0]; - AbstractionPattern origType(archetype); + AbstractionPattern origType = AbstractionPattern::getOpaque(); - // Reabstract input value to the type expected by the enum. value = emitSubstToOrigValue(loc, value, origType, formalObjectType); @@ -155,19 +149,18 @@ getOptionalSomeValue(SILLocation loc, ManagedValue value, return emitManagedRValueWithCleanup(result, optTL); } -static Substitution getSimpleSubstitution(GenericParamList &generics, +static Substitution getSimpleSubstitution(GenericSignature *genericSig, CanType typeArg) { - assert(generics.getParams().size() == 1); - auto typeParamDecl = generics.getParams().front(); - return Substitution{typeParamDecl->getArchetype(), typeArg, {}}; + assert(genericSig->getGenericParams().size() == 1); + return Substitution{typeArg, {}}; } /// Create the correct substitution for calling the given function at /// the given type. static Substitution getSimpleSubstitution(FuncDecl *fn, CanType typeArg) { - auto polyFnType = - cast(fn->getType()->getCanonicalType()); - return getSimpleSubstitution(polyFnType->getGenericParams(), typeArg); + auto genericFnType = + cast(fn->getInterfaceType()->getCanonicalType()); + return getSimpleSubstitution(genericFnType->getGenericSignature(), typeArg); } static CanType getOptionalValueType(SILType optType, @@ -181,7 +174,7 @@ static CanType getOptionalValueType(SILType optType, void SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc, SILValue addr) { OptionalTypeKind OTK; - getOptionalValueType(addr.getType().getObjectType(), OTK); + getOptionalValueType(addr->getType().getObjectType(), OTK); // Generate code to the optional is present, and if not abort with a message // (provided by the stdlib). @@ -208,7 +201,7 @@ void SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc, SILValue SILGenFunction::emitDoesOptionalHaveValue(SILLocation loc, SILValue addrOrValue) { - SILType optType = addrOrValue.getType().getObjectType(); + SILType optType = addrOrValue->getType().getObjectType(); OptionalTypeKind optionalKind; getOptionalValueType(optType, optionalKind); @@ -217,7 +210,7 @@ SILValue SILGenFunction::emitDoesOptionalHaveValue(SILLocation loc, SILValue no = B.createIntegerLiteral(loc, boolTy, 0); auto someDecl = getASTContext().getOptionalSomeDecl(optionalKind); - if (addrOrValue.getType().isAddress()) + if (addrOrValue->getType().isAddress()) return B.createSelectEnumAddr(loc, addrOrValue, boolTy, no, std::make_pair(someDecl, yes)); return B.createSelectEnum(loc, addrOrValue, boolTy, no, @@ -373,7 +366,7 @@ SILGenFunction::emitOptionalToOptional(SILLocation loc, void SILGenFunction::OpaqueValueState::destroy(SILGenFunction &gen, SILLocation loc) { if (isConsumable && !hasBeenConsumed) { - auto &lowering = gen.getTypeLowering(value.getType().getSwiftRValueType()); + auto &lowering = gen.getTypeLowering(value->getType().getSwiftRValueType()); lowering.emitDestroyRValue(gen.B, loc, value); } } @@ -418,11 +411,11 @@ ManagedValue SILGenFunction::emitExistentialErasure( CanType concreteFormalType, const TypeLowering &concreteTL, const TypeLowering &existentialTL, - const ArrayRef &conformances, + ArrayRef conformances, SGFContext C, llvm::function_ref F) { // Mark the needed conformances as used. - for (auto *conformance : conformances) + for (auto conformance : conformances) SGM.useConformance(conformance); switch (existentialTL.getLoweredType().getObjectType() @@ -433,7 +426,7 @@ ManagedValue SILGenFunction::emitExistentialErasure( assert(existentialTL.isLoadable()); SILValue metatype = F(SGFContext()).getUnmanagedValue(); - assert(metatype.getType().castTo()->getRepresentation() + assert(metatype->getType().castTo()->getRepresentation() == MetatypeRepresentation::Thick); auto upcast = @@ -455,14 +448,13 @@ ManagedValue SILGenFunction::emitExistentialErasure( } case ExistentialRepresentation::Boxed: { // Allocate the existential. - auto box = B.createAllocExistentialBox(loc, + auto *existential = B.createAllocExistentialBox(loc, existentialTL.getLoweredType(), concreteFormalType, - concreteTL.getLoweredType(), conformances); - auto existential = box->getExistentialResult(); - auto valueAddr = box->getValueAddressResult(); - + auto *valueAddr = B.createProjectExistentialBox(loc, + concreteTL.getLoweredType(), + existential); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, @@ -509,7 +501,7 @@ ManagedValue SILGenFunction::emitClassMetatypeToObject(SILLocation loc, SILValue value = v.getUnmanagedValue(); // Convert the metatype to objc representation. - auto metatypeTy = value.getType().castTo(); + auto metatypeTy = value->getType().castTo(); auto objcMetatypeTy = CanMetatypeType::get(metatypeTy.getInstanceType(), MetatypeRepresentation::ObjC); value = B.createThickToObjCMetatype(loc, value, @@ -527,7 +519,7 @@ ManagedValue SILGenFunction::emitExistentialMetatypeToObject(SILLocation loc, SILValue value = v.getUnmanagedValue(); // Convert the metatype to objc representation. - auto metatypeTy = value.getType().castTo(); + auto metatypeTy = value->getType().castTo(); auto objcMetatypeTy = CanExistentialMetatypeType::get( metatypeTy.getInstanceType(), MetatypeRepresentation::ObjC); diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index f7eed83383e1c..4877db432528b 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -75,13 +75,13 @@ void TupleInitialization::copyOrInitValueInto(ManagedValue valueMV, // and assign/init each element in turn. SILValue value = valueMV.forward(SGF); auto sourceType = cast(valueMV.getSwiftType()); - auto sourceSILType = value.getType(); + auto sourceSILType = value->getType(); for (unsigned i = 0, e = sourceType->getNumElements(); i != e; ++i) { SILType fieldTy = sourceSILType.getTupleElementType(i); auto &fieldTL = SGF.getTypeLowering(fieldTy); SILValue member; - if (value.getType().isAddress()) { + if (value->getType().isAddress()) { member = SGF.B.createTupleElementAddr(loc, value, i, fieldTy); if (!fieldTL.isAddressOnly()) member = SGF.B.createLoad(loc, member); @@ -172,7 +172,7 @@ class ReleaseValueCleanup : public Cleanup { ReleaseValueCleanup(SILValue v) : v(v) {} void emit(SILGenFunction &gen, CleanupLocation l) override { - if (v.getType().isAddress()) + if (v->getType().isAddress()) gen.B.emitDestroyAddrAndFold(l, v); else gen.B.emitReleaseValueOperation(l, v); @@ -252,8 +252,7 @@ class LocalVariableInitialization : public SingleBufferInitialization { // it using a box. AllocBoxInst *allocBox = SGF.B.createAllocBox(decl, lType, {decl->isLet(), ArgNo}); - auto box = SILValue(allocBox, 0); - auto addr = SILValue(allocBox, 1); + SILValue addr = SGF.B.createProjectBox(decl, allocBox); // Mark the memory as uninitialized, so DI will track it for us. if (NeedsMarkUninit) @@ -261,7 +260,7 @@ class LocalVariableInitialization : public SingleBufferInitialization { /// Remember that this is the memory location that we're emitting the /// decl to. - SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(addr, box); + SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(addr, allocBox); // Push a cleanup to destroy the local variable. This has to be // inactive until the variable is initialized. @@ -359,7 +358,7 @@ class LetValueInitialization : public Initialization { assert(DidFinish && "did not call LetValueInit::finishInitialization!"); } - bool hasAddress() const { return address.isValid(); } + bool hasAddress() const { return (bool)address; } // SingleBufferInitializations always have an address. SILValue getAddressForInPlaceInitialization() const override { @@ -409,7 +408,7 @@ class LetValueInitialization : public Initialization { // If we're binding an address to this let value, then we can use it as an // address later. This happens when binding an address only parameter to // an argument, for example. - if (value.getType().isAddress()) + if (value->getType().isAddress()) address = value; gen.VarLocs[vd] = SILGenFunction::VarLoc::get(value); @@ -417,7 +416,7 @@ class LetValueInitialization : public Initialization { // lifetime. SILLocation PrologueLoc(vd); PrologueLoc.markAsPrologue(); - if (address.isValid()) + if (address) gen.B.createDebugValueAddr(PrologueLoc, value); else gen.B.createDebugValue(PrologueLoc, value); @@ -682,7 +681,7 @@ emitEnumMatch(ManagedValue value, EnumElementDecl *ElementDecl, // If the payload is indirect, project it out of the box. if (ElementDecl->isIndirect() || ElementDecl->getParentEnum()->isIndirect()) { SILValue boxedValue = SGF.B.createProjectBox(loc, eltMV.getValue()); - auto &boxedTL = SGF.getTypeLowering(boxedValue.getType()); + auto &boxedTL = SGF.getTypeLowering(boxedValue->getType()); if (boxedTL.isLoadable()) boxedValue = SGF.B.createLoad(loc, boxedValue); @@ -701,8 +700,8 @@ emitEnumMatch(ManagedValue value, EnumElementDecl *ElementDecl, ->getCanonicalType(); eltMV = SGF.emitOrigToSubstValue(loc, eltMV, - AbstractionPattern(ElementDecl->getArgumentType()), - substEltTy); + SGF.SGM.M.Types.getAbstractionPattern(ElementDecl), + substEltTy); // Pass the +1 value down into the sub initialization. subInit->copyOrInitValueInto(eltMV, /*is an init*/true, loc, SGF); @@ -918,6 +917,7 @@ InitializationPtr SILGenFunction::emitInitializationForVarDecl(VarDecl *vd) { InitializationPtr Result; if (!vd->getDeclContext()->isLocalContext()) { auto *silG = SGM.getSILGlobalVariable(vd, NotForDefinition); + B.createAllocGlobal(vd, silG); SILValue addr = B.createGlobalAddr(vd, silG); if (isUninitialized) addr = B.createMarkUninitializedVar(vd, addr); @@ -1040,7 +1040,7 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, } // Now that we have a boolean test as a Builtin.i1, emit the branch. - assert(booleanTestValue.getType(). + assert(booleanTestValue->getType(). castTo()->isFixedWidth(1) && "Sema forces conditions to have Builtin.i1 type"); @@ -1064,8 +1064,7 @@ SILGenFunction::emitPatternBindingInitialization(Pattern *P, /// Enter a cleanup to deallocate the given location. CleanupHandle SILGenFunction::enterDeallocStackCleanup(SILValue temp) { - assert(temp.getType().isLocalStorage() && - "must deallocate container operand, not address operand!"); + assert(temp->getType().isAddress() && "dealloc must have an address type"); Cleanups.pushCleanup(temp); return Cleanups.getTopCleanup(); } @@ -1135,17 +1134,11 @@ void SILGenModule::emitExternalWitnessTable(ProtocolConformance *c) { void SILGenModule::emitExternalDefinition(Decl *d) { switch (d->getKind()) { case DeclKind::Func: { - // We'll emit all the members of an enum when we visit the enum. - if (isa(d->getDeclContext())) - break; emitFunction(cast(d)); break; } case DeclKind::Constructor: { auto C = cast(d); - // We'll emit all the members of an enum when we visit the enum. - if (isa(d->getDeclContext())) - break; // For factories, we don't need to emit a special thunk; the normal // foreign-to-native thunk is sufficient. if (C->isFactoryInit()) @@ -1154,21 +1147,7 @@ void SILGenModule::emitExternalDefinition(Decl *d) { emitConstructor(C); break; } - case DeclKind::Enum: { - auto ed = cast(d); - // Emit derived conformance methods for the type. - for (auto member : ed->getMembers()) { - if (auto func = dyn_cast(member)) - emitFunction(func); - else if (auto ctor = dyn_cast(member)) - emitConstructor(ctor); - } - // Emit derived global decls. - for (auto derived : ed->getDerivedGlobalDecls()) { - emitFunction(cast(derived)); - } - SWIFT_FALLTHROUGH; - } + case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: { // Emit witness tables. @@ -1190,9 +1169,6 @@ void SILGenModule::emitExternalDefinition(Decl *d) { // Imported static vars are handled solely in IRGen. break; - case DeclKind::Module: - break; - case DeclKind::IfConfig: case DeclKind::Extension: case DeclKind::PatternBinding: @@ -1209,6 +1185,7 @@ void SILGenModule::emitExternalDefinition(Decl *d) { case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: + case DeclKind::Module: llvm_unreachable("Not a valid external definition for SILGen"); } } @@ -1267,7 +1244,7 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) { // For 'let' bindings, we emit a release_value or destroy_addr, depending on // whether we have an address or not. SILValue Val = loc.value; - if (!Val.getType().isAddress()) + if (!Val->getType().isAddress()) B.emitReleaseValueOperation(silLoc, Val); else B.emitDestroyAddrAndFold(silLoc, Val); @@ -1284,10 +1261,10 @@ void SILGenFunction::deallocateUninitializedLocalVariable(SILLocation silLoc, auto loc = VarLocs[vd]; // Ignore let values captured without a memory location. - if (!loc.value.getType().isAddress()) return; + if (!loc.value->getType().isAddress()) return; assert(loc.box && "captured var should have been given a box"); - B.createDeallocBox(silLoc, loc.value.getType().getObjectType(), + B.createDeallocBox(silLoc, loc.value->getType().getObjectType(), loc.box); } @@ -1475,18 +1452,18 @@ class SILGenConformance : public SILWitnessVisitor { assert(protos.size() == witness.getConformances().size() && "number of conformances in assoc type substitution do not match " "number of requirements on assoc type"); - // The conformances should be all null or all nonnull. + // The conformances should be all abstract or all concrete. assert(witness.getConformances().empty() - || (witness.getConformances()[0] + || (witness.getConformances()[0].isConcrete() ? std::all_of(witness.getConformances().begin(), witness.getConformances().end(), - [&](const ProtocolConformance *C) -> bool { - return C; + [&](const ProtocolConformanceRef C) -> bool { + return C.isConcrete(); }) : std::all_of(witness.getConformances().begin(), witness.getConformances().end(), - [&](const ProtocolConformance *C) -> bool { - return !C; + [&](const ProtocolConformanceRef C) -> bool { + return C.isAbstract(); }))); for (auto *protocol : protos) { @@ -1494,14 +1471,14 @@ class SILGenConformance : public SILWitnessVisitor { if (!SGM.Types.protocolRequiresWitnessTable(protocol)) continue; - ProtocolConformance *conformance = nullptr; + ProtocolConformanceRef conformance(protocol); // If the associated type requirement is satisfied by an associated type, // these will all be null. - if (witness.getConformances()[0]) { + if (witness.getConformances()[0].isConcrete()) { auto foundConformance = std::find_if(witness.getConformances().begin(), witness.getConformances().end(), - [&](ProtocolConformance *c) { - return c->getProtocol() == protocol; + [&](ProtocolConformanceRef c) { + return c.getRequirement() == protocol; }); assert(foundConformance != witness.getConformances().end()); conformance = *foundConformance; @@ -1569,34 +1546,6 @@ SILGenModule::getWitnessTable(ProtocolConformance *conformance) { return table; } -/// FIXME: This should just be a call down to Types.getLoweredType(), but I -/// really don't want to thread an old-type/interface-type pair through all -/// of TypeLowering. -static SILType -getWitnessFunctionType(SILModule &M, - AbstractionPattern origRequirementTy, - CanAnyFunctionType witnessSubstTy, - CanAnyFunctionType witnessSubstIfaceTy, - unsigned uncurryLevel) { - // Lower the types to uncurry and get ExtInfo. - AbstractionPattern origLoweredTy = origRequirementTy; - if (auto origFTy = origRequirementTy.getAs()) - origLoweredTy = - AbstractionPattern(M.Types.getLoweredASTFunctionType(origFTy, - uncurryLevel, - None)); - auto witnessLoweredTy - = M.Types.getLoweredASTFunctionType(witnessSubstTy, uncurryLevel, None); - auto witnessLoweredIfaceTy - = M.Types.getLoweredASTFunctionType(witnessSubstIfaceTy, uncurryLevel, None); - - // Convert to SILFunctionType. - auto fnTy = getNativeSILFunctionType(M, origLoweredTy, - witnessLoweredTy, - witnessLoweredIfaceTy); - return SILType::getPrimitiveObjectType(fnTy); -} - SILFunction * SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, SILLinkage linkage, @@ -1604,54 +1553,9 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, SILDeclRef witness, IsFreeFunctionWitness_t isFree, ArrayRef witnessSubs) { - // Get the type of the protocol requirement and the original type of the - // witness. - // FIXME: Rework for interface types. auto requirementInfo = Types.getConstantInfo(requirement); - auto requirementTy - = cast(requirementInfo.FormalType); unsigned witnessUncurryLevel = witness.uncurryLevel; - // Substitute the 'self' type into the requirement to get the concrete - // witness type. - auto witnessSubstTy = cast( - requirementTy - ->substGenericArgs(conformance->getDeclContext()->getParentModule(), - conformance->getType()) - ->getCanonicalType()); - - GenericParamList *conformanceParams = conformance->getGenericParams(); - - // If the requirement is generic, reparent its generic parameter list to - // the generic parameters of the conformance. - CanType methodTy = witnessSubstTy.getResult(); - if (auto pft = dyn_cast(methodTy)) { - auto &reqtParams = pft->getGenericParams(); - // Preserve the depth of generic arguments by adding an empty outer generic - // param list if the conformance is concrete. - GenericParamList *outerParams = conformanceParams; - if (!outerParams) - outerParams = GenericParamList::getEmpty(getASTContext()); - auto methodParams - = reqtParams.cloneWithOuterParameters(getASTContext(), outerParams); - methodTy = CanPolymorphicFunctionType::get(pft.getInput(), pft.getResult(), - methodParams, - pft->getExtInfo()); - } - - // If the conformance is generic, its generic parameters apply to - // the witness as its outer generic param list. - if (conformanceParams) { - witnessSubstTy = CanPolymorphicFunctionType::get(witnessSubstTy.getInput(), - methodTy, - conformanceParams, - witnessSubstTy->getExtInfo()); - } else { - witnessSubstTy = CanFunctionType::get(witnessSubstTy.getInput(), - methodTy, - witnessSubstTy->getExtInfo()); - } - // If the witness is a free function, consider the self argument // uncurry level. if (isFree) @@ -1664,8 +1568,8 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, // Work out the interface type for the witness. auto reqtIfaceTy - = cast(requirementInfo.FormalInterfaceType); - // Substitute the 'self' type into the requirement to get the concrete witness + = cast(requirementInfo.LoweredInterfaceType); + // Substitute the 'Self' type into the requirement to get the concrete witness // type, leaving the other generic parameters open. CanAnyFunctionType witnessSubstIfaceTy = cast( reqtIfaceTy->partialSubstGenericArgs(conformance->getDeclContext()->getParentModule(), @@ -1673,8 +1577,7 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, ->getCanonicalType()); // If the conformance is generic, its generic parameters apply to the witness. - GenericSignature *sig - = conformance->getGenericSignature(); + GenericSignature *sig = conformance->getGenericSignature(); if (sig) { if (auto gft = dyn_cast(witnessSubstIfaceTy)) { SmallVector allParams(sig->getGenericParams().begin(), @@ -1685,72 +1588,55 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, sig->getRequirements().end()); allReqts.append(gft->getRequirements().begin(), gft->getRequirements().end()); - GenericSignature *witnessSig = GenericSignature::get(allParams, allReqts); - - witnessSubstIfaceTy = cast( - GenericFunctionType::get(witnessSig, - gft.getInput(), gft.getResult(), - gft->getExtInfo()) - ->getCanonicalType()); - } else { - assert(isa(witnessSubstIfaceTy)); - witnessSubstIfaceTy = cast( - GenericFunctionType::get(sig, - witnessSubstIfaceTy.getInput(), - witnessSubstIfaceTy.getResult(), - witnessSubstIfaceTy->getExtInfo()) - ->getCanonicalType()); + sig = GenericSignature::get(allParams, allReqts); } + + witnessSubstIfaceTy = cast( + GenericFunctionType::get(sig, + witnessSubstIfaceTy.getInput(), + witnessSubstIfaceTy.getResult(), + witnessSubstIfaceTy->getExtInfo()) + ->getCanonicalType()); } + // Lower the witness type with the requirement's abstraction level. - // FIXME: We should go through TypeConverter::getLoweredType once we settle - // on interface types. - /* - SILType witnessSILType = Types.getLoweredType( - AbstractionPattern(requirementTy), - witnessSubstTy, - requirement.uncurryLevel); - */ - SILType witnessSILType = getWitnessFunctionType(M, - AbstractionPattern(requirementTy), - witnessSubstTy, - witnessSubstIfaceTy, - requirement.uncurryLevel); + auto witnessSILFnType = getNativeSILFunctionType(M, + AbstractionPattern(reqtIfaceTy), + witnessSubstIfaceTy); // Mangle the name of the witness thunk. - llvm::SmallString<128> nameBuffer; + std::string nameBuffer; { - llvm::raw_svector_ostream nameStream(nameBuffer); - nameStream << "_TTW"; - Mangler mangler(nameStream); + Mangler mangler; + mangler.append("_TTW"); mangler.mangleProtocolConformance(conformance); if (auto ctor = dyn_cast(requirement.getDecl())) { mangler.mangleConstructorEntity(ctor, /*isAllocating=*/true, - ResilienceExpansion::Minimal, requirement.uncurryLevel); } else { assert(isa(requirement.getDecl()) && "need to handle mangling of non-Func SILDeclRefs here"); auto requiredDecl = cast(requirement.getDecl()); - mangler.mangleEntity(requiredDecl, ResilienceExpansion::Minimal, - requirement.uncurryLevel); + mangler.mangleEntity(requiredDecl, requirement.uncurryLevel); } + + nameBuffer = mangler.finalize(); } // Collect the context generic parameters for the witness. - GenericParamList *witnessContextParams = conformanceParams; + GenericParamList *witnessContextParams = conformance->getGenericParams(); // If the requirement is generic, reparent its parameters to the conformance // parameters. if (auto reqtParams = requirementInfo.InnerGenericParams) { // Preserve the depth of generic arguments by adding an empty outer generic // param list if the conformance is concrete. - GenericParamList *outerParams = conformanceParams; - if (!outerParams) - outerParams = GenericParamList::getEmpty(getASTContext()); + if (!witnessContextParams) + witnessContextParams = GenericParamList::getEmpty(getASTContext()); witnessContextParams - = reqtParams->cloneWithOuterParameters(getASTContext(), outerParams); + = reqtParams->cloneWithOuterParameters(getASTContext(), + witnessContextParams); } // If the thunked-to function is set to be always inlined, do the @@ -1764,7 +1650,7 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance, InlineStrategy = AlwaysInline; auto *f = M.getOrCreateFunction( - linkage, nameBuffer, witnessSILType.castTo(), + linkage, nameBuffer, witnessSILFnType, witnessContextParams, SILLocation(witness.getDecl()), IsNotBare, IsTransparent, makeModuleFragile ? IsFragile : IsNotFragile, IsThunk, SILFunction::NotRelevant, InlineStrategy); @@ -1788,19 +1674,17 @@ getOrCreateReabstractionThunk(GenericParamList *thunkContextParams, CanSILFunctionType toType, IsFragile_t Fragile) { // Mangle the reabstraction thunk. - llvm::SmallString<256> buffer; + std::string name ; { - llvm::raw_svector_ostream stream(buffer); - Mangler mangler(stream); + Mangler mangler; // This is actually the SIL helper function. For now, IR-gen // makes the actual thunk. - stream << "_TTR"; + mangler.append("_TTR"); if (auto generics = thunkType->getGenericSignature()) { - stream << 'G'; + mangler.append('G'); mangler.setModuleContext(M.getSwiftModule()); - mangler.mangleGenericSignature(generics, - ResilienceExpansion::Minimal); + mangler.mangleGenericSignature(generics); } // Substitute context parameters out of the "from" and "to" types. @@ -1809,16 +1693,13 @@ getOrCreateReabstractionThunk(GenericParamList *thunkContextParams, auto toInterfaceType = Types.getInterfaceTypeOutOfContext(toType, thunkContextParams); - mangler.mangleType(fromInterfaceType, - ResilienceExpansion::Minimal, /*uncurry*/ 0); - mangler.mangleType(toInterfaceType, - ResilienceExpansion::Minimal, /*uncurry*/ 0); + mangler.mangleType(fromInterfaceType, /*uncurry*/ 0); + mangler.mangleType(toInterfaceType, /*uncurry*/ 0); + name = mangler.finalize(); } auto loc = RegularLocation::getAutoGeneratedLocation(); - return M.getOrCreateSharedFunction(loc, - buffer.str(), - thunkType, - IsBare, IsTransparent, - Fragile, IsReabstractionThunk); + return M.getOrCreateSharedFunction(loc, name, thunkType, IsBare, + IsTransparent, Fragile, + IsReabstractionThunk); } diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 53118db785453..b1c8c2a547d26 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/SILGenDynamicCast.cpp b/lib/SILGen/SILGenDynamicCast.cpp index 31593e5d26979..f7826ead46f36 100644 --- a/lib/SILGen/SILGenDynamicCast.cpp +++ b/lib/SILGen/SILGenDynamicCast.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -87,7 +87,6 @@ namespace { // If we're using checked_cast_addr, take the operand (which // should be an address) and build into the destination buffer. - ManagedValue abstractResult; if (Strategy == CastStrategy::Address) { SILValue resultBuffer = createAbstractResultBuffer(hasAbstraction, origTargetTL, ctx); @@ -140,7 +139,7 @@ namespace { // Tolerate being passed an address here. It comes up during switch //emission. scalarOperandValue = operand.forward(SGF); - if (scalarOperandValue.getType().isAddress()) { + if (scalarOperandValue->getType().isAddress()) { scalarOperandValue = SGF.B.createLoad(Loc, scalarOperandValue); } SGF.B.createCheckedCastBranch(Loc, /*exact*/ false, scalarOperandValue, @@ -330,18 +329,12 @@ static RValue emitCollectionDowncastExpr(SILGenFunction &SGF, auto toSubsts = toCollection->getSubstitutions(SGF.SGM.SwiftModule,nullptr); assert(fnArcheTypes.size() == fromSubsts.size() + toSubsts.size() && "wrong number of generic collection parameters"); + (void) fnArcheTypes; // Form type parameter substitutions. - int aIdx = 0; SmallVector subs; - for (auto sub: fromSubsts){ - subs.push_back(Substitution{fnArcheTypes[aIdx++], sub.getReplacement(), - sub.getConformances()}); - } - for (auto sub: toSubsts){ - subs.push_back(Substitution{fnArcheTypes[aIdx++], sub.getReplacement(), - sub.getConformances()}); - } + subs.append(fromSubsts.begin(), fromSubsts.end()); + subs.append(toSubsts.begin(), toSubsts.end()); auto emitApply = SGF.emitApplyOfLibraryIntrinsic(loc, fn, subs, {source}, C); diff --git a/lib/SILGen/SILGenDynamicCast.h b/lib/SILGen/SILGenDynamicCast.h index b2495ed09e991..9477e6f6a5c34 100644 --- a/lib/SILGen/SILGenDynamicCast.h +++ b/lib/SILGen/SILGenDynamicCast.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/SILGenEpilog.cpp b/lib/SILGen/SILGenEpilog.cpp index 0b5de20758421..8695fd589cf23 100644 --- a/lib/SILGen/SILGenEpilog.cpp +++ b/lib/SILGen/SILGenEpilog.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -95,7 +95,7 @@ SILGenFunction::emitEpilogBB(SILLocation TopLevel) { if (needsArg) { returnValue = predBranch->getArgs()[0]; // RAUW the old BB argument (if any) with the new value. - SILValue(*epilogBB->bbarg_begin(),0).replaceAllUsesWith(returnValue); + (*epilogBB->bbarg_begin())->replaceAllUsesWith(returnValue); } // If we are optimizing, we should use the return location from the single, diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 08525f2aea58c..c0ad80f93640a 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -48,14 +48,14 @@ using namespace Lowering; ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc, SILValue v) { - auto &lowering = getTypeLowering(v.getType().getSwiftRValueType()); + auto &lowering = getTypeLowering(v->getType().getSwiftRValueType()); return emitManagedRetain(loc, v, lowering); } ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc, SILValue v, const TypeLowering &lowering) { - assert(lowering.getLoweredType() == v.getType()); + assert(lowering.getLoweredType() == v->getType()); if (lowering.isTrivial()) return ManagedValue::forUnmanaged(v); assert(!lowering.isAddressOnly() && "cannot retain an unloadable type"); @@ -65,13 +65,13 @@ ManagedValue SILGenFunction::emitManagedRetain(SILLocation loc, } ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v) { - auto &lowering = getTypeLowering(v.getType()); + auto &lowering = getTypeLowering(v->getType()); return emitManagedRValueWithCleanup(v, lowering); } ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v, const TypeLowering &lowering) { - assert(lowering.getLoweredType() == v.getType()); + assert(lowering.getLoweredType() == v->getType()); if (lowering.isTrivial()) return ManagedValue::forUnmanaged(v); @@ -79,13 +79,13 @@ ManagedValue SILGenFunction::emitManagedRValueWithCleanup(SILValue v, } ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v) { - auto &lowering = getTypeLowering(v.getType()); + auto &lowering = getTypeLowering(v->getType()); return emitManagedBufferWithCleanup(v, lowering); } ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v, const TypeLowering &lowering) { - assert(lowering.getLoweredType().getAddressType() == v.getType()); + assert(lowering.getLoweredType().getAddressType() == v->getType()); if (lowering.isTrivial()) return ManagedValue::forUnmanaged(v); @@ -197,6 +197,7 @@ namespace { SGFContext C); RValue visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C); RValue visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C); + RValue visitObjCSelectorExpr(ObjCSelectorExpr *E, SGFContext C); RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C); RValue visitCollectionExpr(CollectionExpr *E, SGFContext C); @@ -255,7 +256,7 @@ ManagedValue SILGenFunction::emitLValueForDecl(SILLocation loc, VarDecl *var, if (It != VarLocs.end()) { // If this has an address, return it. By-value let's have no address. SILValue ptr = It->second.value; - if (ptr.getType().isAddress()) + if (ptr->getType().isAddress()) return ManagedValue::forLValue(ptr); // Otherwise, it is an RValue let. @@ -293,7 +294,7 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType, // Any writebacks for this access are tightly scoped. WritebackScope scope(*this); - // If this is an decl that we have an lvalue for, produce and return it. + // If this is a decl that we have an lvalue for, produce and return it. ValueDecl *decl = declRef.getDecl(); if (!ncRefType) ncRefType = decl->getType(); @@ -367,14 +368,14 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType, auto It = VarLocs.find(decl); if (It != VarLocs.end()) { // Mutable lvalue and address-only 'let's are LValues. - assert(!It->second.value.getType().isAddress() && + assert(!It->second.value->getType().isAddress() && "LValue cases should be handled above"); SILValue Scalar = It->second.value; // For weak and unowned types, convert the reference to the right // pointer. - if (Scalar.getType().is()) { + if (Scalar->getType().is()) { Scalar = emitConversionToSemanticRValue(loc, Scalar, getTypeLowering(refType)); // emitConversionToSemanticRValue always produces a +1 strong result. @@ -442,14 +443,22 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType, // Get the lowered AST types: // - the original type - auto origLoweredFormalType = AbstractionPattern(constantInfo.LoweredType); + auto origLoweredFormalType = + AbstractionPattern(constantInfo.LoweredInterfaceType); if (hasLocalCaptures) { - auto formalTypeWithoutCaptures = - cast(constantInfo.FormalType.getResult()); + // Get the unlowered formal type of the constant, stripping off + // the first level of function application, which applies captures. + origLoweredFormalType = + AbstractionPattern(constantInfo.FormalInterfaceType) + .getFunctionResultType(); + + // Lower it, being careful to use the right generic signature. origLoweredFormalType = AbstractionPattern( - SGM.Types.getLoweredASTFunctionType(formalTypeWithoutCaptures,0, - silDeclRef)); + origLoweredFormalType.getGenericSignature(), + SGM.Types.getLoweredASTFunctionType( + cast(origLoweredFormalType.getType()), + 0, silDeclRef)); } // - the substituted type @@ -822,6 +831,9 @@ RValue RValueEmitter::emitStringLiteral(Expr *E, StringRef Str, case StringLiteralInst::Encoding::UTF8: Elts = EltsArray; break; + + case StringLiteralInst::Encoding::ObjCSelector: + llvm_unreachable("Objective-C selectors cannot be formed here"); } return RValue(Elts, ty); @@ -842,8 +854,8 @@ SILValue SILGenFunction::emitTemporaryAllocation(SILLocation loc, SILType ty) { ty = ty.getObjectType(); auto alloc = B.createAllocStack(loc, ty); - enterDeallocStackCleanup(alloc->getContainerResult()); - return alloc->getAddressResult(); + enterDeallocStackCleanup(alloc); + return alloc; } // Return an initialization address we can emit directly into. @@ -1039,7 +1051,7 @@ RValue RValueEmitter::visitMetatypeConversionExpr(MetatypeConversionExpr *E, // such in the SIL type system, for example, a cast from DynamicSelf.Type // directly to its own Self.Type. auto loweredResultTy = SGF.getLoweredLoadableType(E->getType()); - if (metaBase.getType() == loweredResultTy) + if (metaBase->getType() == loweredResultTy) return RValue(SGF, E, ManagedValue::forUnmanaged(metaBase)); auto upcast = SGF.B.createUpcast(E, metaBase, loweredResultTy); @@ -1081,18 +1093,12 @@ visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E, auto toSubsts = toCollection->getSubstitutions(SGF.SGM.SwiftModule,nullptr); assert(fnArcheTypes.size() == fromSubsts.size() + toSubsts.size() && "wrong number of generic collection parameters"); + (void) fnArcheTypes; // Form type parameter substitutions. - int aIdx = 0; SmallVector subs; - for (auto sub: fromSubsts){ - subs.push_back(Substitution{fnArcheTypes[aIdx++], sub.getReplacement(), - sub.getConformances()}); - } - for (auto sub: toSubsts){ - subs.push_back(Substitution{fnArcheTypes[aIdx++], sub.getReplacement(), - sub.getConformances()}); - } + subs.append(fromSubsts.begin(), fromSubsts.end()); + subs.append(toSubsts.begin(), toSubsts.end()); auto emitApply = SGF.emitApplyOfLibraryIntrinsic(loc, fn, subs, {mv}, C); @@ -1599,30 +1605,6 @@ class NominalTypeMemberRefRValueEmitter { ~NominalTypeMemberRefRValueEmitter() = default; private: - bool hasStructWithAtMostOneNonTrivialField(SILGenFunction &SGF) const { - auto *S = dyn_cast(Base); - if (!S) - return false; - - bool FoundNonTrivialField = false; - - for (auto Field : S->getStoredProperties()) { - SILType Ty = SGF.getLoweredType(Field->getType()->getCanonicalType()); - if (Ty.isTrivial(SGF.F.getModule())) - continue; - - // We already found a non-trivial field, so we have two. Return false. - if (FoundNonTrivialField) - return false; - - // We found one non-trivial field. - FoundNonTrivialField = true; - } - - // We found at most one non-trivial field. - return true; - } - RValue emitStructDecl(SILGenFunction &SGF) { ManagedValue base = SGF.emitRValueAsSingleValue(Expr->getBase(), @@ -1920,6 +1902,8 @@ RValue RValueEmitter::visitDynamicTypeExpr(DynamicTypeExpr *E, SGFContext C) { } RValue RValueEmitter::visitCaptureListExpr(CaptureListExpr *E, SGFContext C) { + // Ensure that weak captures are in a separate scope. + DebugScope scope(SGF, CleanupLocation(E)); // ClosureExpr's evaluate their bound variables. for (auto capture : E->getCaptureList()) { SGF.visit(capture.Var); @@ -1962,6 +1946,46 @@ visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C) { return visit(E->getSemanticExpr(), C); } +RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) { + SILType loweredSelectorTy = SGF.getLoweredType(e->getType()); + + // Dig out the declaration of the Selector type. + auto selectorDecl = e->getType()->getAs()->getDecl(); + + // Dig out the type of its pointer. + Type selectorMemberTy; + for (auto member : selectorDecl->getMembers()) { + if (auto var = dyn_cast(member)) { + if (!var->isStatic() && var->hasStorage()) { + selectorMemberTy = var->getInterfaceType()->getRValueType(); + break; + } + } + } + if (!selectorMemberTy) { + SGF.SGM.diagnose(e, diag::objc_selector_malformed); + return RValue(SGF, e, SGF.emitUndef(e, loweredSelectorTy)); + } + + // Form the selector string. + llvm::SmallString<64> selectorScratch; + auto selectorString = + e->getMethod()->getObjCSelector().getString(selectorScratch); + + // Create an Objective-C selector string literal. + auto selectorLiteral = + SGF.B.createStringLiteral(e, selectorString, + StringLiteralInst::Encoding::ObjCSelector); + + // Create the pointer struct from the raw pointer. + SILType loweredPtrTy = SGF.getLoweredType(selectorMemberTy); + auto ptrValue = SGF.B.createStruct(e, loweredPtrTy, { selectorLiteral }); + + // Wrap that up in a Selector and return it. + auto selectorValue = SGF.B.createStruct(e, loweredSelectorTy, { ptrValue }); + return RValue(SGF, e, ManagedValue::forUnmanaged(selectorValue)); +} + static StringRef getMagicFunctionString(SILGenFunction &gen) { assert(gen.MagicFunctionName @@ -2371,7 +2395,7 @@ RValue RValueEmitter::visitLValueToPointerExpr(LValueToPointerExpr *E, SILType abstractedTy = SGF.getLoweredType(AbstractionPattern(E->getAbstractionPatternType()), E->getSubExpr()->getType()->getLValueOrInOutObjectType()); - if (address.getType().getObjectType() != abstractedTy) + if (address->getType().getObjectType() != abstractedTy) SGF.SGM.diagnose(E, diag::not_implemented, "abstraction difference in inout conversion"); @@ -3074,8 +3098,7 @@ ProtocolDecl *SILGenFunction::getPointerProtocol() { /// Produce a Substitution for a type that conforms to the standard library /// _Pointer protocol. -Substitution SILGenFunction::getPointerSubstitution(Type pointerType, - ArchetypeType *archetype) { +Substitution SILGenFunction::getPointerSubstitution(Type pointerType) { auto &Ctx = getASTContext(); ProtocolDecl *pointerProto = getPointerProtocol(); auto conformance @@ -3085,10 +3108,12 @@ Substitution SILGenFunction::getPointerSubstitution(Type pointerType, && "not a _Pointer type"); // FIXME: Cache this - ProtocolConformance *conformances[] = {conformance.getPointer()}; + ProtocolConformanceRef conformances[] = { + ProtocolConformanceRef(conformance.getPointer()) + }; auto conformancesCopy = Ctx.AllocateCopy(conformances); - return Substitution{archetype, pointerType, conformancesCopy}; + return Substitution{pointerType, conformancesCopy}; } namespace { @@ -3114,7 +3139,7 @@ class AutoreleasingWritebackComponent : public LogicalPathComponent { // Convert the value back to a +1 strong reference. auto unowned = std::move(value).getAsSingleValue(gen, loc).getUnmanagedValue(); auto strongType = SILType::getPrimitiveObjectType( - unowned.getType().castTo().getReferentType()); + unowned->getType().castTo().getReferentType()); auto owned = gen.B.createUnmanagedToRef(loc, unowned, strongType); gen.B.createRetainValue(loc, owned); auto ownedMV = gen.emitManagedRValueWithCleanup(owned); @@ -3129,7 +3154,7 @@ class AutoreleasingWritebackComponent : public LogicalPathComponent { SILValue owned = gen.B.createLoad(loc, base.getUnmanagedValue()); // Convert it to unowned. auto unownedType = SILType::getPrimitiveObjectType( - CanUnmanagedStorageType::get(owned.getType().getSwiftRValueType())); + CanUnmanagedStorageType::get(owned->getType().getSwiftRValueType())); SILValue unowned = gen.B.createRefToUnmanaged(loc, owned, unownedType); return ManagedValue::forUnmanaged(unowned); @@ -3226,12 +3251,7 @@ ManagedValue SILGenFunction::emitLValueToPointer(SILLocation loc, // Invoke the conversion intrinsic. FuncDecl *converter = getASTContext().getConvertInOutToPointerArgument(nullptr); - auto firstParam - = converter->getGenericSignatureOfContext()->getGenericParams()[0]; - auto firstArchetype = ArchetypeBuilder::mapTypeIntoContext(converter, - firstParam) - ->castTo(); - Substitution sub = getPointerSubstitution(pointerType, firstArchetype); + Substitution sub = getPointerSubstitution(pointerType); return emitApplyOfLibraryIntrinsic(loc, converter, sub, ManagedValue::forUnmanaged(address), SGFContext()); @@ -3256,25 +3276,15 @@ RValue RValueEmitter::visitArrayToPointerExpr(ArrayToPointerExpr *E, orig = SGF.emitRValueAsSingleValue(subExpr); } - auto converterGenericParams - = converter->getGenericSignatureOfContext()->getGenericParams(); - auto firstArchetype - = ArchetypeBuilder::mapTypeIntoContext(converter, converterGenericParams[0]) - ->castTo(); - auto secondArchetype - = ArchetypeBuilder::mapTypeIntoContext(converter, converterGenericParams[1]) - ->castTo(); - // Invoke the conversion intrinsic, which will produce an owner-pointer pair. Substitution subs[2] = { Substitution{ - firstArchetype, subExpr->getType()->getInOutObjectType() ->castTo() ->getGenericArgs()[0], {} }, - SGF.getPointerSubstitution(E->getType(), secondArchetype), + SGF.getPointerSubstitution(E->getType()), }; auto result = SGF.emitApplyOfLibraryIntrinsic(E, converter, subs, orig, C); @@ -3289,17 +3299,11 @@ RValue RValueEmitter::visitStringToPointerExpr(StringToPointerExpr *E, auto &Ctx = SGF.getASTContext(); FuncDecl *converter = Ctx.getConvertConstStringToUTF8PointerArgument(nullptr); - auto converterGenericParams - = converter->getGenericSignatureOfContext()->getGenericParams(); - auto firstArchetype - = ArchetypeBuilder::mapTypeIntoContext(converter, converterGenericParams[0]) - ->castTo(); - // Get the original value. ManagedValue orig = SGF.emitRValueAsSingleValue(E->getSubExpr()); // Invoke the conversion intrinsic, which will produce an owner-pointer pair. - Substitution sub = SGF.getPointerSubstitution(E->getType(), firstArchetype); + Substitution sub = SGF.getPointerSubstitution(E->getType()); auto result = SGF.emitApplyOfLibraryIntrinsic(E, converter, sub, orig, C); // Lifetime-extend the owner, and pass on the pointer. @@ -3313,15 +3317,6 @@ RValue RValueEmitter::visitPointerToPointerExpr(PointerToPointerExpr *E, auto &Ctx = SGF.getASTContext(); auto converter = Ctx.getConvertPointerToPointerArgument(nullptr); - auto converterGenericParams - = converter->getGenericSignatureOfContext()->getGenericParams(); - auto firstArchetype - = ArchetypeBuilder::mapTypeIntoContext(converter, converterGenericParams[0]) - ->castTo(); - auto secondArchetype - = ArchetypeBuilder::mapTypeIntoContext(converter, converterGenericParams[1]) - ->castTo(); - // Get the original pointer value, abstracted to the converter function's // expected level. AbstractionPattern origTy(converter->getType()->castTo() @@ -3336,8 +3331,8 @@ RValue RValueEmitter::visitPointerToPointerExpr(PointerToPointerExpr *E, // Invoke the conversion intrinsic to convert to the destination type. Substitution subs[2] = { - SGF.getPointerSubstitution(E->getSubExpr()->getType(), firstArchetype), - SGF.getPointerSubstitution(E->getType(), secondArchetype), + SGF.getPointerSubstitution(E->getSubExpr()->getType()), + SGF.getPointerSubstitution(E->getType()), }; auto result = SGF.emitApplyOfLibraryIntrinsic(E, converter, subs, orig, C); diff --git a/lib/SILGen/SILGenForeignError.cpp b/lib/SILGen/SILGenForeignError.cpp index 89510c06381a0..59c2f85840cd1 100644 --- a/lib/SILGen/SILGenForeignError.cpp +++ b/lib/SILGen/SILGenForeignError.cpp @@ -1,8 +1,8 @@ -//===--- SILGenError.cpp - Error-handling code emission -------------------===// +//===--- SILGenForeignError.cpp - Error-handling code emission ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,7 +50,7 @@ static void emitStoreToForeignErrorSlot(SILGenFunction &gen, // be optional, as opposed to simply having a null inhabitant. OptionalTypeKind errorPtrOptKind; if (SILType errorPtrObjectTy = - foreignErrorSlot.getType() + foreignErrorSlot->getType() .getAnyOptionalObjectType(gen.SGM.M, errorPtrOptKind)) { SILBasicBlock *contBB = gen.createBasicBlock(); SILBasicBlock *noSlotBB = gen.createBasicBlock(); @@ -78,7 +78,7 @@ static void emitStoreToForeignErrorSlot(SILGenFunction &gen, // Okay, break down the components of SomePointer. // TODO: this should really be an unlowered AST type? CanType bridgedErrorPtrType = - foreignErrorSlot.getType().getSwiftRValueType(); + foreignErrorSlot->getType().getSwiftRValueType(); PointerTypeKind ptrKind; CanType bridgedErrorType = @@ -213,8 +213,6 @@ SILValue SILGenFunction:: emitBridgeReturnValueForForeignError(SILLocation loc, SILValue result, SILFunctionTypeRepresentation repr, - AbstractionPattern origNativeType, - CanType substNativeType, SILType bridgedType, SILValue foreignErrorSlot, const ForeignErrorConvention &foreignError) { @@ -242,8 +240,7 @@ emitBridgeReturnValueForForeignError(SILLocation loc, bridgedType.getSwiftRValueType().getAnyOptionalObjectType(optKind); ManagedValue bridgedResult = emitNativeToBridgedValue(loc, emitManagedRValueWithCleanup(result), - repr, origNativeType, substNativeType, - bridgedObjectType); + repr, bridgedObjectType); auto someResult = B.createOptionalSome(loc, bridgedResult.forward(*this), optKind, @@ -260,8 +257,7 @@ emitBridgeReturnValueForForeignError(SILLocation loc, // The actual result value just needs to be bridged normally. ManagedValue bridgedValue = emitNativeToBridgedValue(loc, emitManagedRValueWithCleanup(result), - repr, origNativeType, substNativeType, - bridgedType.getSwiftRValueType()); + repr, bridgedType.getSwiftRValueType()); return bridgedValue.forward(*this); } } @@ -296,8 +292,8 @@ void SILGenFunction::emitForeignErrorBlock(SILLocation loc, static SILValue emitUnwrapIntegerResult(SILGenFunction &gen, SILLocation loc, SILValue value) { - while (!value.getType().is()) { - auto structDecl = value.getType().getStructOrBoundGenericStruct(); + while (!value->getType().is()) { + auto structDecl = value->getType().getStructOrBoundGenericStruct(); assert(structDecl && "value for error result wasn't of struct type!"); assert(std::next(structDecl->getStoredProperties().begin()) == structDecl->getStoredProperties().end()); @@ -323,13 +319,13 @@ emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc, SILValue resultValue = emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue()); SILValue zero = - gen.B.createIntegerLiteral(loc, resultValue.getType(), 0); + gen.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = gen.getASTContext(); SILValue resultIsError = gen.B.createBuiltinBinaryFunction(loc, zeroIsError ? "cmp_eq" : "cmp_ne", - resultValue.getType(), + resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); @@ -355,7 +351,7 @@ emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc, OptionalTypeKind optKind; SILType resultObjectType = - optionalResult.getType().getAnyOptionalObjectType(gen.SGM.M, optKind); + optionalResult->getType().getAnyOptionalObjectType(gen.SGM.M, optKind); ASTContext &ctx = gen.getASTContext(); @@ -395,7 +391,7 @@ emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc, SILValue optionalError = gen.B.createLoad(loc, errorSlot.getValue()); OptionalTypeKind optKind; - optionalError.getType().getAnyOptionalObjectType(gen.SGM.M, optKind); + optionalError->getType().getAnyOptionalObjectType(gen.SGM.M, optKind); ASTContext &ctx = gen.getASTContext(); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index d9919b39c204e..fd6215d220d51 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,9 +28,9 @@ using namespace swift; using namespace Lowering; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // SILGenFunction Class implementation -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F) : SGM(SGM), F(F), @@ -55,9 +55,9 @@ SILGenFunction::~SILGenFunction() { freeWritebackStack(); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Function emission -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Get the __FUNCTION__ name for a declaration. DeclName SILGenModule::getMagicFunctionName(DeclContext *dc) { @@ -189,7 +189,7 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc, else methodValue = emitGlobalFunctionRef(loc, methodConstant); - SILType methodTy = methodValue.getType(); + SILType methodTy = methodValue->getType(); if (!subs.empty()) { // Specialize the generic method. @@ -220,12 +220,28 @@ ManagedValue SILGenFunction::emitFunctionRef(SILLocation loc, void SILGenFunction::emitCaptures(SILLocation loc, AnyFunctionRef TheClosure, + CaptureEmission purpose, SmallVectorImpl &capturedArgs) { auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); // For boxed captures, we need to mark the contained variables as having // escaped for DI diagnostics. SmallVector escapesToMark; + // Partial applications take ownership of the context parameters, so we'll + // need to pass ownership rather than merely guaranteeing parameters. + bool canGuarantee; + switch (purpose) { + case CaptureEmission::PartialApplication: + canGuarantee = false; + break; + case CaptureEmission::ImmediateApplication: + canGuarantee = true; + break; + } + // TODO: Or we always retain them when guaranteed contexts aren't enabled. + if (!SGM.M.getOptions().EnableGuaranteedClosureContexts) + canGuarantee = false; + for (auto capture : captureInfo.getCaptures()) { auto *vd = capture.getDecl(); @@ -237,11 +253,18 @@ void SILGenFunction::emitCaptures(SILLocation loc, // let declarations. auto Entry = VarLocs[vd]; - // Non-address-only constants are passed at +1. auto &tl = getTypeLowering(vd->getType()->getReferenceStorageReferent()); SILValue Val = Entry.value; - if (!Val.getType().isAddress()) { + if (!Val->getType().isAddress()) { + // Our 'let' binding can guarantee the lifetime for the callee, + // if we don't need to do anything more to it. + if (canGuarantee && !vd->getType()->is()) { + auto guaranteed = ManagedValue::forUnmanaged(Val); + capturedArgs.push_back(guaranteed); + break; + } + // Just retain a by-val let. B.emitRetainValueOperation(loc, Val); } else { @@ -250,20 +273,15 @@ void SILGenFunction::emitCaptures(SILLocation loc, Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this); } - // Use an RValue to explode Val if it is a tuple. - RValue RV(*this, loc, vd->getType()->getCanonicalType(), - ManagedValue::forUnmanaged(Val)); - // If we're capturing an unowned pointer by value, we will have just // loaded it into a normal retained class pointer, but we capture it as // an unowned pointer. Convert back now. if (vd->getType()->is()) { auto type = getTypeLowering(vd->getType()).getLoweredType(); - auto val = std::move(RV).forwardAsSingleStorageValue(*this, type,loc); - capturedArgs.push_back(emitManagedRValueWithCleanup(val)); - } else { - std::move(RV).getAll(capturedArgs); + Val = emitConversionFromSemanticValue(loc, Val, type); } + + capturedArgs.push_back(emitManagedRValueWithCleanup(Val)); break; } @@ -272,7 +290,7 @@ void SILGenFunction::emitCaptures(SILLocation loc, // address of the value. assert(VarLocs.count(vd) && "no location for captured var!"); VarLoc vl = VarLocs[vd]; - assert(vl.value.getType().isAddress() && "no address for captured var!"); + assert(vl.value->getType().isAddress() && "no address for captured var!"); capturedArgs.push_back(ManagedValue::forLValue(vl.value)); break; } @@ -282,24 +300,34 @@ void SILGenFunction::emitCaptures(SILLocation loc, // address of the value. assert(VarLocs.count(vd) && "no location for captured var!"); VarLoc vl = VarLocs[vd]; - assert(vl.value.getType().isAddress() && "no address for captured var!"); + assert(vl.value->getType().isAddress() && "no address for captured var!"); // If this is a boxed variable, we can use it directly. if (vl.box) { - B.createStrongRetain(loc, vl.box); - capturedArgs.push_back(emitManagedRValueWithCleanup(vl.box)); + // We can guarantee our own box to the callee. + if (canGuarantee) { + capturedArgs.push_back(ManagedValue::forUnmanaged(vl.box)); + } else { + B.createStrongRetain(loc, vl.box); + capturedArgs.push_back(emitManagedRValueWithCleanup(vl.box)); + } escapesToMark.push_back(vl.value); } else { // Address only 'let' values are passed by box. This isn't great, in // that a variable captured by multiple closures will be boxed for each // one. This could be improved by doing an "isCaptured" analysis when - // emitting address-only let constants, and emit them into a alloc_box + // emitting address-only let constants, and emit them into an alloc_box // like a variable instead of into an alloc_stack. + // + // TODO: This might not be profitable anymore with guaranteed captures, + // since we could conceivably forward the copied value into the + // closure context and pass it down to the partially applied function + // in-place. AllocBoxInst *allocBox = - B.createAllocBox(loc, vl.value.getType().getObjectType()); - auto boxAddress = SILValue(allocBox, 1); + B.createAllocBox(loc, vl.value->getType().getObjectType()); + ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox); B.createCopyAddr(loc, vl.value, boxAddress, IsNotTake,IsInitialization); - capturedArgs.push_back(emitManagedRValueWithCleanup(SILValue(allocBox, 0))); + capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox)); } break; @@ -325,7 +353,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, auto constantInfo = getConstantInfo(constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); - SILType functionTy = functionRef.getType(); + SILType functionTy = functionRef->getType(); auto expectedType = cast(TheClosure.getType()->getCanonicalType()); @@ -353,16 +381,16 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, } SmallVector capturedArgs; - emitCaptures(loc, TheClosure, capturedArgs); + emitCaptures(loc, TheClosure, CaptureEmission::PartialApplication, + capturedArgs); - // Currently all capture arguments are captured at +1. - // TODO: Ideally this would be +0. + // The partial application takes ownership of the context parameters. SmallVector forwardedArgs; for (auto capture : capturedArgs) forwardedArgs.push_back(capture.forward(*this)); SILType closureTy = - SILGenBuilder::getPartialApplyResultType(functionRef.getType(), + SILGenBuilder::getPartialApplyResultType(functionRef->getType(), capturedArgs.size(), SGM.M, forwardSubs); auto toClosure = @@ -379,7 +407,7 @@ void SILGenFunction::emitFunction(FuncDecl *fd) { MagicFunctionName = SILGenModule::getMagicFunctionName(fd); Type resultTy = fd->getResultType(); - emitProlog(fd, fd->getBodyParamPatterns(), resultTy); + emitProlog(fd, fd->getParameterLists(), resultTy); prepareEpilog(resultTy, fd->isBodyThrowing(), CleanupLocation(fd)); emitProfilerIncrement(fd->getBody()); @@ -391,7 +419,7 @@ void SILGenFunction::emitFunction(FuncDecl *fd) { void SILGenFunction::emitClosure(AbstractClosureExpr *ace) { MagicFunctionName = SILGenModule::getMagicFunctionName(ace); - emitProlog(ace, ace->getParams(), ace->getResultType()); + emitProlog(ace, ace->getParameters(), ace->getResultType()); prepareEpilog(ace->getResultType(), ace->isBodyThrowing(), CleanupLocation(ace)); if (auto *ce = dyn_cast(ace)) { @@ -430,10 +458,10 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { MetatypeRepresentation::ObjC); ProtocolDecl *anyObjectProtocol = getASTContext().getProtocol(KnownProtocolKind::AnyObject); - auto mainClassAnyObjectConformance = + auto mainClassAnyObjectConformance = ProtocolConformanceRef( SGM.M.getSwiftModule()->lookupConformance(mainClassTy, anyObjectProtocol, nullptr) - .getPointer(); + .getPointer()); CanType anyObjectTy = anyObjectProtocol ->getDeclaredTypeInContext() ->getCanonicalType(); @@ -473,9 +501,9 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { // Call UIApplicationMain. SILParameterInfo argTypes[] = { - SILParameterInfo(argc.getType().getSwiftRValueType(), + SILParameterInfo(argc->getType().getSwiftRValueType(), ParameterConvention::Direct_Unowned), - SILParameterInfo(argv.getType().getSwiftRValueType(), + SILParameterInfo(argv->getType().getSwiftRValueType(), ParameterConvention::Direct_Unowned), SILParameterInfo(IUOptNSStringTy, ParameterConvention::Direct_Unowned), SILParameterInfo(IUOptNSStringTy, ParameterConvention::Direct_Unowned), @@ -486,7 +514,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { CFunctionPointer), ParameterConvention::Direct_Unowned, argTypes, - SILResultInfo(argc.getType().getSwiftRValueType(), + SILResultInfo(argc->getType().getSwiftRValueType(), ResultConvention::Unowned), /*error result*/ None, getASTContext()); @@ -506,10 +534,10 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { B.createApply(mainClass, UIApplicationMain, UIApplicationMain->getType(), - argc.getType(), {}, args); + argc->getType(), {}, args); SILValue r = B.createIntegerLiteral(mainClass, SILType::getBuiltinIntegerType(32, getASTContext()), 0); - if (r.getType() != F.getLoweredFunctionType()->getResult().getSILType()) + if (r->getType() != F.getLoweredFunctionType()->getResult().getSILType()) r = B.createStruct(mainClass, F.getLoweredFunctionType()->getResult().getSILType(), r); @@ -522,9 +550,9 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { // return NSApplicationMain(C_ARGC, C_ARGV); SILParameterInfo argTypes[] = { - SILParameterInfo(argc.getType().getSwiftRValueType(), + SILParameterInfo(argc->getType().getSwiftRValueType(), ParameterConvention::Direct_Unowned), - SILParameterInfo(argv.getType().getSwiftRValueType(), + SILParameterInfo(argv->getType().getSwiftRValueType(), ParameterConvention::Direct_Unowned), }; auto NSApplicationMainType = SILFunctionType::get(nullptr, @@ -534,7 +562,7 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { .withRepresentation(SILFunctionType::Representation::Thin), ParameterConvention::Direct_Unowned, argTypes, - SILResultInfo(argc.getType().getSwiftRValueType(), + SILResultInfo(argc->getType().getSwiftRValueType(), ResultConvention::Unowned), /*error result*/ None, getASTContext()); @@ -550,10 +578,10 @@ void SILGenFunction::emitArtificialTopLevel(ClassDecl *mainClass) { B.createApply(mainClass, NSApplicationMain, NSApplicationMain->getType(), - argc.getType(), {}, args); + argc->getType(), {}, args); SILValue r = B.createIntegerLiteral(mainClass, SILType::getBuiltinIntegerType(32, getASTContext()), 0); - if (r.getType() != F.getLoweredFunctionType()->getResult().getSILType()) + if (r->getType() != F.getLoweredFunctionType()->getResult().getSILType()) r = B.createStruct(mainClass, F.getLoweredFunctionType()->getResult().getSILType(), r); B.createReturn(mainClass, r); @@ -636,7 +664,10 @@ static SILValue getNextUncurryLevelRef(SILGenFunction &gen, SILValue OpenedExistential; if (!cast(thisType)->getOpenedExistentialType().isNull()) OpenedExistential = thisArg; - return gen.B.createWitnessMethod(loc, thisType, nullptr, next, + auto protocol = + next.getDecl()->getDeclContext()->isProtocolOrProtocolExtensionContext(); + auto conformance = ProtocolConformanceRef(protocol); + return gen.B.createWitnessMethod(loc, thisType, conformance, next, constantInfo.getSILType(), OpenedExistential); } @@ -670,7 +701,7 @@ void SILGenFunction::emitCurryThunk(ValueDecl *vd, --paramCount; // Forward the curried formal arguments. - auto forwardedPatterns = fd->getBodyParamPatterns().slice(0, paramCount); + auto forwardedPatterns = fd->getParameterLists().slice(0, paramCount); for (auto *paramPattern : reversed(forwardedPatterns)) bindParametersForForwarding(paramPattern, curriedArgs); @@ -696,18 +727,18 @@ void SILGenFunction::emitCurryThunk(ValueDecl *vd, = SGM.getConstantType(from).castTo() ->getResult().getSILType(); resultTy = F.mapTypeIntoContext(resultTy); - auto toTy = toFn.getType(); + auto toTy = toFn->getType(); // Forward archetypes and specialize if the function is generic. if (!subs.empty()) { - auto toFnTy = toFn.getType().castTo(); + auto toFnTy = toFn->getType().castTo(); toTy = getLoweredLoadableType( toFnTy->substGenericArgs(SGM.M, SGM.SwiftModule, subs)); } // Partially apply the next uncurry level and return the result closure. auto closureTy = - SILGenBuilder::getPartialApplyResultType(toFn.getType(), curriedArgs.size(), + SILGenBuilder::getPartialApplyResultType(toFn->getType(), curriedArgs.size(), SGM.M, subs); SILInstruction *toClosure = B.createPartialApply(vd, toFn, toTy, subs, curriedArgs, closureTy); @@ -815,8 +846,8 @@ SILGenBuilder::createInitExistentialAddr(SILLocation Loc, SILValue Existential, CanType FormalConcreteType, SILType LoweredConcreteType, - ArrayRef Conformances){ - for (auto *conformance : Conformances) + ArrayRef Conformances) { + for (auto conformance : Conformances) SGM.useConformance(conformance); return SILBuilder::createInitExistentialAddr(Loc, Existential, @@ -829,8 +860,8 @@ InitExistentialMetatypeInst * SILGenBuilder::createInitExistentialMetatype(SILLocation loc, SILValue metatype, SILType existentialType, - ArrayRef conformances){ - for (auto *conformance : conformances) + ArrayRef conformances) { + for (auto conformance : conformances) SGM.useConformance(conformance); return SILBuilder::createInitExistentialMetatype(loc, metatype, @@ -843,8 +874,8 @@ SILGenBuilder::createInitExistentialRef(SILLocation Loc, SILType ExistentialType, CanType FormalConcreteType, SILValue Concrete, - ArrayRef Conformances) { - for (auto *conformance : Conformances) + ArrayRef Conformances) { + for (auto conformance : Conformances) SGM.useConformance(conformance); return SILBuilder::createInitExistentialRef(Loc, ExistentialType, @@ -856,13 +887,11 @@ AllocExistentialBoxInst * SILGenBuilder::createAllocExistentialBox(SILLocation Loc, SILType ExistentialType, CanType ConcreteType, - SILType ConcreteLoweredType, - ArrayRef Conformances) { - for (auto *conformance : Conformances) + ArrayRef Conformances) { + for (auto conformance : Conformances) SGM.useConformance(conformance); return SILBuilder::createAllocExistentialBox(Loc, ExistentialType, ConcreteType, - ConcreteLoweredType, Conformances); } diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index c58643ba6fae7..ed4f9f7999041 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,7 @@ #include "swift/SIL/SILBuilder.h" namespace swift { + class ParameterList; namespace Lowering { class ArgumentSource; @@ -37,7 +38,7 @@ class TemporaryInitialization; /// In general, emission methods which take an SGFContext indicate /// that they've initialized the emit-into buffer (if they have) by /// returning a "isInContext()" ManagedValue of whatever type. Callers who -/// propagate down an SGFContext that might have a emit-into buffer must be +/// propagate down an SGFContext that might have an emit-into buffer must be /// aware of this. /// /// Clients of emission routines that take an SGFContext can also specify that @@ -201,7 +202,7 @@ class SILGenBuilder : public SILBuilder { MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype); - // Generic pply instructions use the conformances necessary to form the call. + // Generic apply instructions use the conformances necessary to form the call. using SILBuilder::createApply; @@ -237,24 +238,33 @@ class SILGenBuilder : public SILBuilder { SILValue Existential, CanType FormalConcreteType, SILType LoweredConcreteType, - ArrayRef Conformances); + ArrayRef Conformances); InitExistentialMetatypeInst * createInitExistentialMetatype(SILLocation loc, SILValue metatype, SILType existentialType, - ArrayRef conformances); + ArrayRef conformances); InitExistentialRefInst * createInitExistentialRef(SILLocation Loc, SILType ExistentialType, CanType FormalConcreteType, SILValue Concrete, - ArrayRef Conformances); + ArrayRef Conformances); AllocExistentialBoxInst *createAllocExistentialBox(SILLocation Loc, SILType ExistentialType, CanType ConcreteType, - SILType ConcreteLoweredType, - ArrayRef Conformances); + ArrayRef Conformances); +}; + +/// Parameter to \c SILGenFunction::emitCaptures that indicates what the +/// capture parameters are being emitted for. +enum class CaptureEmission { + /// Captures are being emitted for immediate application to a local function. + ImmediateApplication, + /// Captures are being emitted for partial application to form a closure + /// value. + PartialApplication, }; /// SILGenFunction - an ASTVisitor for producing SIL from function bodies. @@ -558,7 +568,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SILDeclRef fromLevel, SILDeclRef toLevel); /// Generates a thunk from a foreign function to the native Swift convention. void emitForeignToNativeThunk(SILDeclRef thunk); - /// Generates a thunk from a native function to the conventions. + /// Generates a thunk from a native function to the conventions. void emitNativeToForeignThunk(SILDeclRef thunk); // Generate a nullary function that returns the given value. @@ -669,15 +679,15 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// emitProlog - Generates prolog code to allocate and clean up mutable /// storage for closure captures and local arguments. - void emitProlog(AnyFunctionRef TheClosure, ArrayRef paramPatterns, - Type resultType); + void emitProlog(AnyFunctionRef TheClosure, + ArrayRef paramPatterns, Type resultType); /// returns the number of variables in paramPatterns. - unsigned emitProlog(ArrayRef paramPatterns, + unsigned emitProlog(ArrayRef paramPatterns, Type resultType, DeclContext *DeclCtx); /// Create SILArguments in the entry block that bind all the values /// of the given pattern suitably for being forwarded. - void bindParametersForForwarding(Pattern *paramPattern, + void bindParametersForForwarding(const ParameterList *params, SmallVectorImpl ¶meters); /// \brief Create (but do not emit) the epilog branch, and save the @@ -895,7 +905,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction CanType concreteFormalType, const TypeLowering &concreteTL, const TypeLowering &existentialTL, - const ArrayRef &conformances, + ArrayRef conformances, SGFContext C, llvm::function_ref F); @@ -1031,6 +1041,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction void emitCaptures(SILLocation loc, AnyFunctionRef TheClosure, + CaptureEmission purpose, SmallVectorImpl &captures); ManagedValue emitClosureValue(SILLocation loc, @@ -1071,6 +1082,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction FuncDecl *witness, ArrayRef witnessSubs, ArrayRef params); + void emitMaterializeForSet(FuncDecl *decl); SILDeclRef getAddressorDeclRef(AbstractStorageDecl *decl, AccessKind accessKind, @@ -1335,8 +1347,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// convention. ManagedValue emitNativeToBridgedValue(SILLocation loc, ManagedValue v, SILFunctionTypeRepresentation destRep, - AbstractionPattern origNativeTy, - CanType substNativeTy, CanType bridgedTy); /// Convert a value received as the result or argument of a function with @@ -1364,8 +1374,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction emitBridgeReturnValueForForeignError(SILLocation loc, SILValue result, SILFunctionTypeRepresentation repr, - AbstractionPattern origNativeType, - CanType substNativeType, SILType bridgedResultType, SILValue foreignErrorSlot, const ForeignErrorConvention &foreignError); @@ -1413,6 +1421,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction CanType outputSubstType, SGFContext ctx = SGFContext()); + /// Used for emitting SILArguments of bare functions, such as thunks and + /// open-coded materializeForSet. + void collectThunkParams(SILLocation loc, + SmallVectorImpl ¶ms, + bool allowPlusZero); + /// Build the type of a function transformation thunk. CanSILFunctionType buildThunkType(ManagedValue fn, CanSILFunctionType expectedType, @@ -1530,8 +1544,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// Produce a substitution for invoking a pointer argument conversion /// intrinsic. - Substitution getPointerSubstitution(Type pointerType, - ArchetypeType *archetype); + Substitution getPointerSubstitution(Type pointerType); }; diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 6dd1d1a624d68..ed38636a8f1cb 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,10 +25,11 @@ using namespace Lowering; SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, ForDefinition_t forDef) { // First, get a mangled name for the declaration. - llvm::SmallString<32> mangledName; { - llvm::raw_svector_ostream buffer(mangledName); - Mangler mangler(buffer); + std::string mangledName; + { + Mangler mangler; mangler.mangleGlobalVariableFull(gDecl); + mangledName = mangler.finalize(); } // Check if it is already created, and update linkage if necessary. @@ -87,12 +88,12 @@ SILGenFunction::emitGlobalVariableRef(SILLocation loc, VarDecl *var) { SILDeclRef(var, SILDeclRef::Kind::GlobalAccessor), NotForDefinition); SILValue accessor = B.createFunctionRef(loc, accessorFn); - auto accessorTy = accessor.getType().castTo(); + auto accessorTy = accessor->getType().castTo(); (void)accessorTy; assert(!accessorTy->isPolymorphic() && "generic global variable accessors not yet implemented"); - SILValue addr = B.createApply(loc, accessor, accessor.getType(), - accessor.getType().castTo() + SILValue addr = B.createApply(loc, accessor, accessor->getType(), + accessor->getType().castTo() ->getResult().getSILType(), {}, {}); // FIXME: It'd be nice if the result of the accessor was natively an @@ -210,10 +211,11 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, }); assert(varDecl); - llvm::SmallString<20> onceTokenBuffer; { - llvm::raw_svector_ostream onceTokenStream(onceTokenBuffer); - Mangler tokenMangler(onceTokenStream); + std::string onceTokenBuffer; + { + Mangler tokenMangler; tokenMangler.mangleGlobalInit(varDecl, counter, false); + onceTokenBuffer = tokenMangler.finalize(); } auto onceTy = BuiltinIntegerType::getWordType(M.getASTContext()); @@ -228,12 +230,14 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, onceToken->setDeclaration(false); // Emit the initialization code into a function. - llvm::SmallString<20> onceFuncBuffer; - llvm::raw_svector_ostream onceFuncStream(onceFuncBuffer); - Mangler funcMangler(onceFuncStream); - funcMangler.mangleGlobalInit(varDecl, counter, true); + std::string onceFuncBuffer; + { + Mangler funcMangler; + funcMangler.mangleGlobalInit(varDecl, counter, true); + onceFuncBuffer = funcMangler.finalize(); + } - SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncStream.str(), pd, + SILFunction *onceFunc = emitLazyGlobalInitializer(onceFuncBuffer, pd, pbdEntry); // Generate accessor functions for all of the declared variables, which diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 7766e9a834061..85cc0cd055639 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -201,7 +201,7 @@ static ManagedValue emitGetIntoTemporary(SILGenFunction &gen, if (!value.isInContext()) { if (value.getType().getSwiftRValueType() - != temporaryInit->getAddress().getType().getSwiftRValueType()) { + != temporaryInit->getAddress()->getType().getSwiftRValueType()) { value = gen.emitSubstToOrigValue(loc, value, component.getOrigFormalType(), component.getSubstFormalType()); @@ -364,7 +364,7 @@ static LValueTypeData getValueTypeData(CanType formalType, return { AbstractionPattern(formalType), formalType, - value.getType().getObjectType() + value->getType().getObjectType() }; } static LValueTypeData getValueTypeData(SILGenFunction &gen, Expr *e) { @@ -562,7 +562,7 @@ namespace { static bool isReadNoneFunction(const Expr *e) { // If this is a curried call to an integer literal conversion operations, then // we can "safely" assume it is readnone (btw, yes this is totally gross). - // This is better to be attribute driven, ala rdar://15587352. + // This is better to be attribute driven, a la rdar://15587352. if (auto *dre = dyn_cast(e)) { DeclName name = dre->getDecl()->getFullName(); return (name.getArgumentNames().size() == 1 && @@ -804,6 +804,7 @@ namespace { if (accessKind == AccessKind::Read || decl->getAttrs().hasAttribute() || !decl->getMaterializeForSetFunc() || + isa(decl->getDeclContext()) || decl->getDeclContext()->isProtocolExtensionContext()) { return std::move(*this).LogicalPathComponent::getMaterialized(gen, loc, base, accessKind); @@ -921,7 +922,7 @@ namespace { SILType::getPrimitiveObjectType(TupleType::getEmpty(ctx)); SILType callbackSILType = gen.getLoweredType( - optionalCallback.getType().getSwiftRValueType() + optionalCallback->getType().getSwiftRValueType() .getAnyOptionalObjectType()); // The callback is a BB argument from the switch_enum. @@ -1360,6 +1361,17 @@ namespace { }; } // end anonymous namespace. +LValue LValue::forValue(ManagedValue value, + CanType substFormalType) { + assert(value.getType().isObject()); + LValueTypeData typeData = getValueTypeData(substFormalType, + value.getValue()); + + LValue lv; + lv.add(value, typeData); + return lv; +} + LValue LValue::forAddress(ManagedValue address, AbstractionPattern origFormalType, CanType substFormalType) { @@ -1415,7 +1427,7 @@ void LValue::addOrigToSubstComponent(SILType loweredSubstType) { assert(getTypeOfRValue() != loweredSubstType && "reabstraction component is unnecessary!"); - // Peephole away complementary reabstractons. + // Peephole away complementary reabstractions. assert(!Path.empty() && "adding translation component to empty l-value"); if (Path.back()->getKind() == PathComponent::SubstToOrigKind) { // But only if the lowered type matches exactly. @@ -1437,7 +1449,7 @@ void LValue::addSubstToOrigComponent(AbstractionPattern origType, assert(getTypeOfRValue() != loweredSubstType && "reabstraction component is unnecessary!"); - // Peephole away complementary reabstractons. + // Peephole away complementary reabstractions. assert(!Path.empty() && "adding translation component to empty l-value"); if (Path.back()->getKind() == PathComponent::OrigToSubstKind) { // But only if the lowered type matches exactly. @@ -1529,8 +1541,7 @@ static ArrayRef getNonMemberVarDeclSubstitutions(SILGenFunction &gen, VarDecl *var) { ArrayRef substitutions; if (auto genericParams - = gen.SGM.Types.getEffectiveGenericParamsForContext( - var->getDeclContext())) + = var->getDeclContext()->getGenericParamsOfContext()) substitutions = genericParams->getForwardingSubstitutions(gen.getASTContext()); return substitutions; @@ -1894,7 +1905,7 @@ getOptionalObjectTypeData(SILGenFunction &gen, EnumElementDecl *someDecl = gen.getASTContext().getOptionalSomeDecl(otk); return { - AbstractionPattern(someDecl->getArgumentType()), + gen.SGM.M.Types.getAbstractionPattern(someDecl), objectTy, baseTypeData.TypeOfRValue.getEnumElementType(someDecl, gen.SGM.M), }; @@ -2020,8 +2031,8 @@ ManagedValue SILGenFunction::emitLoad(SILLocation loc, SILValue addr, // in the very common case of this being equivalent to the r-value // type. auto &addrTL = - (addr.getType() == rvalueTL.getLoweredType().getAddressType() - ? rvalueTL : getTypeLowering(addr.getType())); + (addr->getType() == rvalueTL.getLoweredType().getAddressType() + ? rvalueTL : getTypeLowering(addr->getType())); // Never do a +0 load together with a take. bool isPlusZeroOk = (isTake == IsNotTake && @@ -2067,12 +2078,12 @@ SILValue SILGenFunction::emitConversionToSemanticRValue(SILLocation loc, SILValue src, const TypeLowering &valueTL) { // Weak storage types are handled with their underlying type. - assert(!src.getType().is() && + assert(!src->getType().is() && "weak pointers are always the right optional types"); // For @unowned(safe) types, we need to generate a strong retain and // strip the unowned box. - if (auto unownedType = src.getType().getAs()) { + if (auto unownedType = src->getType().getAs()) { assert(unownedType->isLoadable(ResilienceExpansion::Maximal)); (void) unownedType; @@ -2083,7 +2094,7 @@ SILValue SILGenFunction::emitConversionToSemanticRValue(SILLocation loc, // For @unowned(unsafe) types, we need to strip the unmanaged box // and then do an (unsafe) retain. - if (auto unmanagedType = src.getType().getAs()) { + if (auto unmanagedType = src->getType().getAs()) { auto result = B.createUnmanagedToRef(loc, src, SILType::getPrimitiveObjectType(unmanagedType.getReferentType())); B.createStrongRetain(loc, result); @@ -2101,7 +2112,7 @@ static SILValue emitLoadOfSemanticRValue(SILGenFunction &gen, SILValue src, const TypeLowering &valueTL, IsTake_t isTake) { - SILType storageType = src.getType(); + SILType storageType = src->getType(); // For @weak types, we need to create an Optional. // Optional is currently loadable, but it probably won't be forever. @@ -2122,7 +2133,7 @@ static SILValue emitLoadOfSemanticRValue(SILGenFunction &gen, } // For @unowned(unsafe) types, we need to strip the unmanaged box. - if (auto unmanagedType = src.getType().getAs()) { + if (auto unmanagedType = src->getType().getAs()) { auto value = gen.B.createLoad(loc, src); auto result = gen.B.createUnmanagedToRef(loc, value, SILType::getPrimitiveObjectType(unmanagedType.getReferentType())); @@ -2152,7 +2163,7 @@ static void emitStoreOfSemanticRValue(SILGenFunction &gen, SILValue dest, const TypeLowering &valueTL, IsInitialization_t isInit) { - auto storageType = dest.getType(); + auto storageType = dest->getType(); // For @weak types, we need to break down an Optional and then // emit the storeWeak ourselves. @@ -2204,7 +2215,7 @@ SILValue SILGenFunction::emitSemanticLoad(SILLocation loc, const TypeLowering &srcTL, const TypeLowering &rvalueTL, IsTake_t isTake) { - assert(srcTL.getLoweredType().getAddressType() == src.getType()); + assert(srcTL.getLoweredType().getAddressType() == src->getType()); assert(rvalueTL.isLoadable()); // Easy case: the types match. @@ -2224,8 +2235,8 @@ void SILGenFunction::emitSemanticLoadInto(SILLocation loc, const TypeLowering &destTL, IsTake_t isTake, IsInitialization_t isInit) { - assert(srcTL.getLoweredType().getAddressType() == src.getType()); - assert(destTL.getLoweredType().getAddressType() == dest.getType()); + assert(srcTL.getLoweredType().getAddressType() == src->getType()); + assert(destTL.getLoweredType().getAddressType() == dest->getType()); // Easy case: the types match. if (srcTL.getLoweredType() == destTL.getLoweredType()) { @@ -2243,12 +2254,12 @@ void SILGenFunction::emitSemanticStore(SILLocation loc, SILValue dest, const TypeLowering &destTL, IsInitialization_t isInit) { - assert(destTL.getLoweredType().getAddressType() == dest.getType()); + assert(destTL.getLoweredType().getAddressType() == dest->getType()); // Easy case: the types match. - if (rvalue.getType() == destTL.getLoweredType()) { - assert(destTL.isAddressOnly() == rvalue.getType().isAddress()); - if (rvalue.getType().isAddress()) { + if (rvalue->getType() == destTL.getLoweredType()) { + assert(destTL.isAddressOnly() == rvalue->getType().isAddress()); + if (rvalue->getType().isAddress()) { B.createCopyAddr(loc, rvalue, dest, IsTake, isInit); } else { emitUnloweredStoreOfCopy(B, loc, rvalue, dest, isInit); @@ -2256,7 +2267,7 @@ void SILGenFunction::emitSemanticStore(SILLocation loc, return; } - auto &rvalueTL = getTypeLowering(rvalue.getType()); + auto &rvalueTL = getTypeLowering(rvalue->getType()); emitStoreOfSemanticRValue(*this, loc, rvalue, dest, rvalueTL, isInit); } @@ -2267,7 +2278,7 @@ SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, auto &destTL = getTypeLowering(storageType); (void)destTL; // Easy case: the types match. - if (semanticValue.getType() == storageType) { + if (semanticValue->getType() == storageType) { return semanticValue; } @@ -2436,7 +2447,7 @@ void SILGenFunction::emitCopyLValueInto(SILLocation loc, LValue &&src, if (!destAddr) return skipPeephole(); if (src.getTypeOfRValue().getSwiftRValueType() - != destAddr.getType().getSwiftRValueType()) + != destAddr->getType().getSwiftRValueType()) return skipPeephole(); auto srcAddr = emitAddressOfLValue(loc, std::move(src), AccessKind::Read) @@ -2466,7 +2477,7 @@ void SILGenFunction::emitAssignLValueToLValue(SILLocation loc, auto destAddr = emitAddressOfLValue(loc, std::move(dest), AccessKind::Write) .getUnmanagedValue(); - if (srcAddr.getType() == destAddr.getType()) { + if (srcAddr->getType() == destAddr->getType()) { B.createCopyAddr(loc, srcAddr, destAddr, IsNotTake, IsNotInitialization); } else { // If there's a semantic conversion necessary, do a load then assign. @@ -2476,737 +2487,3 @@ void SILGenFunction::emitAssignLValueToLValue(SILLocation loc, loaded.assignInto(*this, loc, destAddr); } } - -//===----------------------------------------------------------------------===// -// materializeForSet emission -//===----------------------------------------------------------------------===// - -namespace { - -/// A helper class for emitting materializeForSet. -struct MaterializeForSetEmitter { - SILGenModule &SGM; - ProtocolConformance *Conformance; - FuncDecl *Requirement; - FuncDecl *Witness; - AbstractStorageDecl *RequirementStorage; - AbstractStorageDecl *WitnessStorage; - ArrayRef WitnessSubs; - CanType SubstSelfType; - CanType SubstStorageType; - AccessSemantics TheAccessSemantics; - bool IsSuper; - GenericParamList *OuterGenericParams = nullptr; // initialized in emit() - - AbstractionPattern RequirementStoragePattern; - SILType RequirementStorageType; - SILType WitnessStorageType; - - MaterializeForSetEmitter(SILGenModule &SGM, - ProtocolConformance *conformance, - FuncDecl *requirement, - FuncDecl *witness, - ArrayRef witnessSubs, - SILType selfType) - : SGM(SGM), - Conformance(conformance), Requirement(requirement), Witness(witness), - RequirementStorage(requirement->getAccessorStorageDecl()), - WitnessStorage(witness->getAccessorStorageDecl()), - WitnessSubs(witnessSubs), - RequirementStoragePattern(AbstractionPattern::getInvalid()) - { - // Assume that we don't need to reabstract 'self'. Right now, - // that's always true; if we ever reabstract Optional (or other - // nominal types) and allow "partial specialization" extensions, - // this will break, and we'll have to do inout-translation in - // the callback buffer. - SubstSelfType = selfType.getSwiftRValueType(); - - // Determine the formal type of the storage. - CanType witnessIfaceType = - WitnessStorage->getInterfaceType()->getCanonicalType(); - if (isa(WitnessStorage)) - witnessIfaceType = cast(witnessIfaceType).getResult(); - SubstStorageType = getSubstWitnessInterfaceType(witnessIfaceType); - - // Determine the desired abstraction pattern of the storage type - // in the requirement and the witness. - RequirementStoragePattern = - SGM.Types.getAbstractionPattern(RequirementStorage); - RequirementStorageType = - SGM.Types.getLoweredType(RequirementStoragePattern, SubstStorageType) - .getObjectType(); - - auto witnessStoragePattern = - SGM.Types.getAbstractionPattern(WitnessStorage); - WitnessStorageType = - SGM.Types.getLoweredType(witnessStoragePattern, SubstStorageType) - .getObjectType(); - - // In a protocol witness thunk, we always want to use ordinary - // access semantics. But when we're changing for standard - // implementations, we'll need to modify this to use direct - // semantics. - TheAccessSemantics = AccessSemantics::Ordinary; - IsSuper = false; - } - - bool shouldOpenCode() const { - // We need to open-code if there's an abstraction difference in the - // result address. - if (RequirementStorageType != WitnessStorageType) - return true; - - // We also need to open-code if the witness is defined in a - // protocol context because IRGen won't know how to reconstruct - // the type parameters. (In principle, this can be done in the - // callback storage if we need to.) - if (Witness->getDeclContext()->isProtocolOrProtocolExtensionContext()) - return true; - - return false; - } - - void emit(SILGenFunction &gen, ManagedValue self, SILValue resultBuffer, - SILValue callbackBuffer, ArrayRef indices); - - SILValue emitUsingStorage(SILGenFunction &gen, SILLocation loc, - ManagedValue self, RValue &&indices); - - SILValue emitUsingAddressor(SILGenFunction &gen, SILLocation loc, - ManagedValue self, RValue &&indices, - SILValue callbackBuffer, SILFunction *&callback); - SILFunction *createAddressorCallback(SILType ownerType, - AddressorKind addressorKind); - - SILValue emitUsingGetterSetter(SILGenFunction &gen, SILLocation loc, - ManagedValue self, RValue &&indices, - SILValue resultBuffer, - SILValue callbackBuffer, - SILFunction *&callback); - SILFunction *createSetterCallback(const TypeLowering *indicesTL, - CanType indicesFormalType); - - using GeneratorFn = llvm::function_ref; - - SILFunction *createCallback(GeneratorFn generator); - - RValue collectIndicesFromParameters(SILGenFunction &gen, SILLocation loc, - ArrayRef sourceIndices); - - LValue buildSelfLValue(SILGenFunction &gen, SILLocation loc, - ManagedValue self) { - // All of the complexity here is tied up with class types. If the - // substituted type isn't a reference type, then we can't have a - // class-bounded protocol or inheritance, and the simple case just - // works. - AbstractionPattern selfPattern(SubstSelfType); - if (!SubstSelfType->mayHaveSuperclass()) { - return LValue::forAddress(self, selfPattern, SubstSelfType); - } - - CanType witnessSelfType = - Witness->computeInterfaceSelfType(false)->getCanonicalType(); - witnessSelfType = getSubstWitnessInterfaceType(witnessSelfType); - if (auto selfTuple = dyn_cast(witnessSelfType)) { - assert(selfTuple->getNumElements() == 1); - witnessSelfType = selfTuple.getElementType(0); - } - witnessSelfType = witnessSelfType.getLValueOrInOutObjectType(); - - // Eagerly loading here could cause an unnecessary - // load+materialize in some cases, but it's not really important. - SILValue selfValue = self.getValue(); - if (selfValue.getType().isAddress()) { - selfValue = gen.B.createLoad(loc, selfValue); - } - - // Do a derived-to-base conversion if necessary. - if (witnessSelfType != SubstSelfType) { - auto selfSILType = SILType::getPrimitiveObjectType(witnessSelfType); - selfValue = gen.B.createUpcast(loc, selfValue, selfSILType); - } - - // Recreate as a borrowed value. - self = ManagedValue::forUnmanaged(selfValue); - return LValue::forClassReference(self); - } - - LValue buildLValue(SILGenFunction &gen, SILLocation loc, - ManagedValue self, RValue &&indices, - AccessKind accessKind) { - // Begin with the 'self' value. - LValue lv = buildSelfLValue(gen, loc, self); - - auto strategy = - WitnessStorage->getAccessStrategy(TheAccessSemantics, accessKind); - - // Drill down to the member storage. - lv.addMemberComponent(gen, loc, WitnessStorage, WitnessSubs, IsSuper, - accessKind, TheAccessSemantics, strategy, - SubstStorageType, std::move(indices)); - assert(lv.getTypeOfRValue().getObjectType() == WitnessStorageType); - - // Reabstract back to the requirement pattern. - if (RequirementStorageType != WitnessStorageType) { - SILType substTy = SGM.getLoweredType(SubstStorageType).getObjectType(); - - // Translate to the formal type... - if (WitnessStorageType != substTy) - lv.addOrigToSubstComponent(substTy); - - // ...then back to the requirement type. - if (substTy != RequirementStorageType) - lv.addSubstToOrigComponent(RequirementStoragePattern, - RequirementStorageType); - } - - return lv; - } - - /// Given part of the witness's interface type, produce its - /// substitution according to the witness substitutions. - CanType getSubstWitnessInterfaceType(CanType type) { - return SubstSelfType->getTypeOfMember(SGM.SwiftModule, type, - WitnessStorage->getDeclContext()) - ->getCanonicalType(); - } - -}; - -} // end anonymous namespace - -void MaterializeForSetEmitter::emit(SILGenFunction &gen, ManagedValue self, - SILValue resultBuffer, - SILValue callbackBuffer, - ArrayRef indices) { - SILLocation loc = Witness; - loc.markAutoGenerated(); - - OuterGenericParams = gen.F.getContextGenericParams(); - - // If there's an abstraction difference, we always need to use the - // get/set pattern. - AccessStrategy strategy; - if (RequirementStorageType != WitnessStorageType) { - strategy = AccessStrategy::DispatchToAccessor; - } else { - strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics, - AccessKind::ReadWrite); - } - - // Handle the indices. - RValue indicesRV; - if (isa(WitnessStorage)) { - indicesRV = collectIndicesFromParameters(gen, loc, indices); - } else { - assert(indices.empty() && "indices for a non-subscript?"); - } - - // As above, assume that we don't need to reabstract 'self'. - - // Choose the right implementation. - SILValue address; - SILFunction *callbackFn = nullptr; - switch (strategy) { - case AccessStrategy::Storage: - address = emitUsingStorage(gen, loc, self, std::move(indicesRV)); - break; - - case AccessStrategy::Addressor: - address = emitUsingAddressor(gen, loc, self, std::move(indicesRV), - callbackBuffer, callbackFn); - break; - - case AccessStrategy::DirectToAccessor: - case AccessStrategy::DispatchToAccessor: - address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV), - resultBuffer, callbackBuffer, callbackFn); - break; - } - - // Return the address as a Builtin.RawPointer. - SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext()); - address = gen.B.createAddressToPointer(loc, address, rawPointerTy); - - SILType resultTupleTy = gen.F.mapTypeIntoContext( - gen.F.getLoweredFunctionType()->getResult().getSILType()); - SILType optCallbackTy = resultTupleTy.getTupleElementType(1); - - // Form the callback. - SILValue callback; - if (callbackFn) { - // Make a reference to the function. - callback = gen.B.createFunctionRef(loc, callbackFn); - - // If it's polymorphic, cast to RawPointer and then back to the - // right monomorphic type. The safety of this cast relies on some - // assumptions about what exactly IRGen can reconstruct from the - // callback's thick type argument. - if (callbackFn->getLoweredFunctionType()->isPolymorphic()) { - callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy); - - OptionalTypeKind optKind; - auto callbackTy = optCallbackTy.getAnyOptionalObjectType(SGM.M, optKind); - callback = gen.B.createPointerToThinFunction(loc, callback, callbackTy); - } - - callback = gen.B.createOptionalSome(loc, callback, optCallbackTy); - } else { - callback = gen.B.createOptionalNone(loc, optCallbackTy); - } - - // Form the result and return. - auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback }); - gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc)); - gen.B.createReturn(loc, result); -} - -/// Recursively walk into the given formal index type, expanding tuples, -/// in order to -static void translateIndices(SILGenFunction &gen, SILLocation loc, - AbstractionPattern pattern, CanType formalType, - ArrayRef &sourceIndices, - RValue &result) { - // Expand if the pattern was a tuple. - if (pattern.isTuple()) { - auto formalTupleType = cast(formalType); - for (auto i : indices(formalTupleType.getElementTypes())) { - translateIndices(gen, loc, pattern.getTupleElementType(i), - formalTupleType.getElementType(i), - sourceIndices, result); - } - return; - } - - assert(!sourceIndices.empty() && "ran out of elements in index!"); - ManagedValue value = sourceIndices.front(); - sourceIndices = sourceIndices.slice(1); - - // We're going to build an RValue here, so make sure we translate - // indirect arguments to be scalar if we have a loadable type. - if (value.getType().isAddress()) { - auto &valueTL = gen.getTypeLowering(value.getType()); - if (!valueTL.isAddressOnly()) { - value = gen.emitLoad(loc, value.forward(gen), valueTL, - SGFContext(), IsTake); - } - } - - // Reabstract the subscripts from the requirement pattern to the - // formal type. - value = gen.emitOrigToSubstValue(loc, value, pattern, formalType); - - // Invoking the accessor will expect a value of the formal type, so - // don't reabstract to that here. - - // Add that to the result, further expanding if necessary. - result.addElement(gen, value, formalType, loc); -} - -RValue MaterializeForSetEmitter:: -collectIndicesFromParameters(SILGenFunction &gen, SILLocation loc, - ArrayRef sourceIndices) { - auto witnessSubscript = cast(WitnessStorage); - CanType witnessIndicesType = - witnessSubscript->getIndicesInterfaceType()->getCanonicalType(); - CanType substIndicesType = - getSubstWitnessInterfaceType(witnessIndicesType); - - auto reqSubscript = cast(RequirementStorage); - auto pattern = SGM.Types.getIndicesAbstractionPattern(reqSubscript); - - RValue result(substIndicesType); - - // Translate and reabstract the index values by recursively walking - // the abstracted index type. - SmallVector translatedIndices; - translateIndices(gen, loc, pattern, substIndicesType, - sourceIndices, result); - assert(sourceIndices.empty() && "index value not claimed!"); - - return result; -} - -static AnyFunctionType *getMaterializeForSetCallbackType(ASTContext &ctx, - Type selfType, - GenericParamList *genericParams) { - // inout storage: Builtin.ValueBuffer, - // inout self: Self, - // @thick selfType: Self.Type) -> () - TupleTypeElt params[] = { - ctx.TheRawPointerType, - InOutType::get(ctx.TheUnsafeValueBufferType), - InOutType::get(selfType), - MetatypeType::get(selfType, MetatypeRepresentation::Thick) - }; - Type input = TupleType::get(params, ctx); - Type result = TupleType::getEmpty(ctx); - FunctionType::ExtInfo extInfo = FunctionType::ExtInfo() - .withRepresentation(FunctionType::Representation::Thin); - - if (genericParams) { - return PolymorphicFunctionType::get(input, result, genericParams, extInfo); - } else { - return FunctionType::get(input, result, extInfo); - } -} - -static Type getSelfTypeForCallbackDeclaration(FuncDecl *witness) { - // We're intentionally using non-interface types here: we want - // something specified in terms of the witness's archetypes, because - // we're going to build the closure as if it were contextually - // within the witness. - auto type = witness->getType()->castTo()->getInput(); - if (auto tuple = type->getAs()) { - assert(tuple->getNumElements() == 1); - type = tuple->getElementType(0); - } - return type->getLValueOrInOutObjectType(); -} - -SILFunction *MaterializeForSetEmitter::createCallback(GeneratorFn generator) { - auto &ctx = SGM.getASTContext(); - - // Mangle this as if it were a conformance thunk for a closure - // within the witness. - llvm::SmallString<128> name; - { - ClosureExpr closure(/*patterns*/ nullptr, - /*throws*/ SourceLoc(), - /*arrow*/ SourceLoc(), - /*in*/ SourceLoc(), - /*result*/ TypeLoc(), - /*discriminator*/ 0, - /*context*/ Witness); - closure.setType(getMaterializeForSetCallbackType(ctx, - getSelfTypeForCallbackDeclaration(Witness), - nullptr)); - closure.getCaptureInfo().setGenericParamCaptures(true); - - llvm::raw_svector_ostream nameStream(name); - nameStream << "_TTW"; - Mangle::Mangler mangler(nameStream); - mangler.mangleProtocolConformance(Conformance); - mangler.mangleClosureEntity(&closure, ResilienceExpansion::Minimal, 1); - } - - // Create the SILFunctionType for the callback. - CanType selfIfaceType = Conformance->getInterfaceType()->getCanonicalType(); - SILParameterInfo params[] = { - { ctx.TheRawPointerType, ParameterConvention::Direct_Unowned }, - { ctx.TheUnsafeValueBufferType, ParameterConvention::Indirect_Inout }, - { selfIfaceType, ParameterConvention::Indirect_Inout }, - { CanMetatypeType::get(selfIfaceType, MetatypeRepresentation::Thick), - ParameterConvention::Direct_Unowned }, - }; - SILResultInfo result = { - TupleType::getEmpty(ctx), ResultConvention::Unowned - }; - auto extInfo = - SILFunctionType::ExtInfo() - .withRepresentation(SILFunctionTypeRepresentation::Thin); - - GenericSignature *signature = Conformance->getGenericSignature(); - if (signature) signature = signature->getCanonicalSignature(); - - auto callbackType = SILFunctionType::get(signature, extInfo, - /*callee*/ ParameterConvention::Direct_Unowned, - params, result, None, ctx); - - auto linkage = SGM.Types.getLinkageForProtocolConformance( - Conformance->getRootNormalConformance(), ForDefinition); - auto callback = - SGM.M.getOrCreateFunction(Witness, name, linkage, callbackType, - IsBare, IsTransparent, IsNotFragile); - - callback->setContextGenericParams(Conformance->getGenericParams()); - callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, *callback)); - - PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback); - { - SILGenFunction gen(SGM, *callback); - - auto makeParam = [&](unsigned index) -> SILArgument* { - SILType type = gen.F.mapTypeIntoContext(params[index].getSILType()); - return new (SGM.M) SILArgument(gen.F.begin(), type); - }; - - // Add arguments for all the parameters. - auto valueBuffer = makeParam(0); - auto storageBuffer = makeParam(1); - auto self = makeParam(2); - (void) makeParam(3); - - SILLocation loc = Witness; - loc.markAutoGenerated(); - - // Call the generator function we were provided. - { - LexicalScope scope(gen.Cleanups, gen, CleanupLocation::get(loc)); - generator(gen, loc, valueBuffer, storageBuffer, self); - } - - // Return void. - auto result = gen.emitEmptyTuple(loc); - gen.B.createReturn(loc, result); - } - - callback->verify(); - return callback; -} - -/// Emit a materializeForSet operation that projects storage, assuming -/// that no cleanups or callbacks are required. -SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen, - SILLocation loc, - ManagedValue self, - RValue &&indices) { - LValue lvalue = buildLValue(gen, loc, self, std::move(indices), - AccessKind::ReadWrite); - ManagedValue address = - gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite); - return address.getUnmanagedValue(); -} - -/// Emit a materializeForSet operation that calls a mutable addressor. -/// -/// If it's not an unsafe addressor, this uses a callback function to -/// write the l-value back. -SILValue MaterializeForSetEmitter::emitUsingAddressor(SILGenFunction &gen, - SILLocation loc, - ManagedValue self, - RValue &&indices, - SILValue callbackBuffer, - SILFunction *&callback) { - bool isDirect = (TheAccessSemantics != AccessSemantics::Ordinary); - - // Call the mutable addressor. - auto addressor = gen.getAddressorDeclRef(WitnessStorage, - AccessKind::ReadWrite, - isDirect); - RValue selfRV(gen, loc, SubstSelfType, self); - auto result = gen.emitAddressorAccessor(loc, addressor, WitnessSubs, - { loc, std::move(selfRV) }, - IsSuper, isDirect, - std::move(indices), - WitnessStorageType); - SILValue address = result.first.getUnmanagedValue(); - - AddressorKind addressorKind = - WitnessStorage->getMutableAddressor()->getAddressorKind(); - ManagedValue owner = result.second; - if (!owner) { - assert(addressorKind == AddressorKind::Unsafe); - } else { - SILValue allocatedCallbackBuffer = - gen.B.createAllocValueBuffer(loc, owner.getType(), callbackBuffer); - gen.B.createStore(loc, owner.forward(gen), allocatedCallbackBuffer); - - callback = createAddressorCallback(owner.getType(), addressorKind); - } - - return address; -} - -/// Emit a materializeForSet callback to clean up after an addressor -/// with an owner result. -SILFunction * -MaterializeForSetEmitter::createAddressorCallback(SILType ownerType, - AddressorKind addressorKind) { - return createCallback([&](SILGenFunction &gen, SILLocation loc, - SILValue resultBuffer, SILValue callbackStorage, - SILValue self) { - auto ownerAddress = - gen.B.createProjectValueBuffer(loc, ownerType, callbackStorage); - auto owner = gen.B.createLoad(loc, ownerAddress); - - switch (addressorKind) { - case AddressorKind::NotAddressor: - case AddressorKind::Unsafe: - llvm_unreachable("owner with unexpected addressor kind"); - - case AddressorKind::Owning: - case AddressorKind::NativeOwning: - gen.B.createStrongRelease(loc, owner); - return; - - case AddressorKind::NativePinning: - gen.B.createStrongUnpin(loc, owner); - return; - } - llvm_unreachable("bad addressor kind"); - }); -} - -/// Emit a materializeForSet operation that simply loads the l-value -/// into the result buffer. This operation creates a callback to write -/// the l-value back. -SILValue -MaterializeForSetEmitter::emitUsingGetterSetter(SILGenFunction &gen, - SILLocation loc, - ManagedValue self, - RValue &&indices, - SILValue resultBuffer, - SILValue callbackBuffer, - SILFunction *&callback) { - // Copy the indices into the callback storage. - const TypeLowering *indicesTL = nullptr; - CleanupHandle indicesCleanup = CleanupHandle::invalid(); - CanType indicesFormalType; - if (isa(WitnessStorage)) { - indicesFormalType = indices.getType(); - indicesTL = &gen.getTypeLowering(indicesFormalType); - SILValue allocatedCallbackBuffer = - gen.B.createAllocValueBuffer(loc, indicesTL->getLoweredType(), - callbackBuffer); - - // Emit into the buffer. - auto init = gen.useBufferAsTemporary(loc, allocatedCallbackBuffer, - *indicesTL); - indicesCleanup = init->getInitializedCleanup(); - - indices.copyInto(gen, init.get(), loc); - } - - // Set up the result buffer. - resultBuffer = - gen.B.createPointerToAddress(loc, resultBuffer, - RequirementStorageType.getAddressType()); - TemporaryInitialization init(resultBuffer, CleanupHandle::invalid()); - - // Evaluate the getter into the result buffer. - LValue lv = buildLValue(gen, loc, self, std::move(indices), AccessKind::Read); - ManagedValue result = gen.emitLoadOfLValue(loc, std::move(lv), - SGFContext(&init)); - if (!result.isInContext()) { - result.forwardInto(gen, loc, resultBuffer); - } - - // Forward the cleanup on the saved indices. - if (indicesCleanup.isValid()) { - gen.Cleanups.setCleanupState(indicesCleanup, CleanupState::Dead); - } - - callback = createSetterCallback(indicesTL, indicesFormalType); - return resultBuffer; -} - -namespace { - class DeallocateValueBuffer : public Cleanup { - SILValue Buffer; - SILType ValueType; - public: - DeallocateValueBuffer(SILType valueType, SILValue buffer) - : Buffer(buffer), ValueType(valueType) {} - void emit(SILGenFunction &gen, CleanupLocation loc) override { - gen.B.createDeallocValueBuffer(loc, ValueType, Buffer); - } - }; -} - -/// Emit a materializeForSet callback that stores the value from the -/// result buffer back into the l-value. -SILFunction * -MaterializeForSetEmitter::createSetterCallback(const TypeLowering *indicesTL, - CanType indicesFormalType) { - return createCallback([&](SILGenFunction &gen, SILLocation loc, - SILValue value, SILValue callbackBuffer, - SILValue self) { - // If this is a subscript, we need to handle the indices in the - // callback storage. - RValue indices; - if (indicesTL) { - assert(isa(WitnessStorage)); - SILType indicesTy = indicesTL->getLoweredType(); - - // Enter a cleanup to deallocate the callback storage. - gen.Cleanups.pushCleanup(indicesTy, - callbackBuffer); - - // Project the value out, loading if necessary, and take - // ownership of it. - SILValue indicesV = - gen.B.createProjectValueBuffer(loc, indicesTy, callbackBuffer); - if (indicesTL->isLoadable()) - indicesV = gen.B.createLoad(loc, indicesV); - ManagedValue mIndices = - gen.emitManagedRValueWithCleanup(indicesV, *indicesTL); - - // Explode as an r-value. - indices = RValue(gen, loc, indicesFormalType, mIndices); - } - - // The callback gets the address of 'self' at +0. - ManagedValue mSelf = ManagedValue::forLValue(self); - - // That's enough to build the l-value. - LValue lvalue = buildLValue(gen, loc, mSelf, std::move(indices), - AccessKind::Write); - - // The callback gets the value at +1. - auto &valueTL = gen.getTypeLowering(lvalue.getTypeOfRValue()); - value = gen.B.createPointerToAddress(loc, value, - valueTL.getLoweredType().getAddressType()); - if (valueTL.isLoadable()) - value = gen.B.createLoad(loc, value); - ManagedValue mValue = gen.emitManagedRValueWithCleanup(value, valueTL); - RValue rvalue(gen, loc, lvalue.getSubstFormalType(), mValue); - - // Finally, call the setter. - gen.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue)); - }); -} - -/// Emit an open-coded protocol-witness thunk for materializeForSet if -/// delegating to the standard implementation isn't good enough. -/// -/// materializeForSet sometimes needs to be open-coded because of the -/// thin callback function, which is dependent but cannot be reabstracted. -/// -/// - In a protocol extension, the callback doesn't know how to capture -/// or reconstruct the generic conformance information. -/// -/// - The abstraction pattern of the variable from the witness may -/// differ from the abstraction pattern of the protocol, likely forcing -/// a completely different access pattern (e.g. to write back a -/// reabstracted value instead of modifying it in-place). -/// -/// \return true if special code was emitted -bool SILGenFunction:: -maybeEmitMaterializeForSetThunk(ProtocolConformance *conformance, - FuncDecl *requirement, FuncDecl *witness, - ArrayRef witnessSubs, - ArrayRef origParams) { - // The formal type of materializeForSet is: - // - // (self: Self) -> (temporary: Builtin.RawPointer, - // inout storage: Builtin.ValueBuffer, - // indices...) - // -> (address: Builtin.RawPointer, - // callback: (@thin (address: Builtin.RawPointer, - // inout storage: Builtin.ValueBuffer, - // inout self: Self, - // @thick selfType: Self.Type) -> ())?) - - // Break apart the parameters. self comes last, the result buffer - // comes first, the callback storage buffer comes second, and the - // rest are indices. - ManagedValue self = origParams.back(); - SILValue resultBuffer = origParams[0].getUnmanagedValue(); - SILValue callbackBuffer = origParams[1].getUnmanagedValue(); - ArrayRef indices = origParams.slice(2).drop_back(); - - MaterializeForSetEmitter emitter(SGM, conformance, requirement, witness, - witnessSubs, self.getType()); - - if (!emitter.shouldOpenCode()) - return false; - - emitter.emit(*this, self, resultBuffer, callbackBuffer, indices); - return true; -} diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp new file mode 100644 index 0000000000000..6fe024be31e77 --- /dev/null +++ b/lib/SILGen/SILGenMaterializeForSet.cpp @@ -0,0 +1,867 @@ +//===--- SILGenMaterializeForSet.cpp - Open-coded materializeForSet -------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Emission of materializeForSet. +// +//===----------------------------------------------------------------------===// + +#include "SILGen.h" +#include "ArgumentSource.h" +#include "LValue.h" +#include "RValue.h" +#include "Scope.h" +#include "Initialization.h" +#include "swift/AST/AST.h" +#include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Types.h" +#include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/Mangle.h" +#include "swift/SIL/PrettyStackTrace.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILUndef.h" +#include "swift/SIL/TypeLowering.h" +#include "llvm/Support/raw_ostream.h" +#include "ASTVisitor.h" +using namespace swift; +using namespace Lowering; + +namespace { + +/// A helper class for emitting materializeForSet. +/// +/// The formal type of materializeForSet is: +/// +/// (self: Self) -> (temporary: Builtin.RawPointer, +/// inout storage: Builtin.ValueBuffer, +/// indices...) +/// -> (address: Builtin.RawPointer, +/// callback: (@thin (address: Builtin.RawPointer, +/// inout storage: Builtin.ValueBuffer, +/// inout self: Self, +/// @thick selfType: Self.Type) -> ())?) +/// +struct MaterializeForSetEmitter { + SILGenModule &SGM; + + // Only used if we're emitting a witness thunk, not a static entry point. + ProtocolConformance *Conformance; + FuncDecl *Requirement; + AbstractStorageDecl *RequirementStorage; + AbstractionPattern RequirementStoragePattern; + SILType RequirementStorageType; + + FuncDecl *Witness; + AbstractStorageDecl *WitnessStorage; + ArrayRef WitnessSubs; + CanGenericSignature GenericSig; + GenericParamList *GenericParams; + SILLinkage Linkage; + Type SelfInterfaceType; + CanType SubstSelfType; + CanType SubstStorageType; + AccessSemantics TheAccessSemantics; + bool IsSuper; + + SILType WitnessStorageType; + + MaterializeForSetEmitter(SILGenModule &SGM, + ProtocolConformance *conformance, + FuncDecl *requirement, + FuncDecl *witness, + ArrayRef witnessSubs, + SILType selfType) + : SGM(SGM), + Conformance(conformance), + Requirement(requirement), + RequirementStorage(nullptr), + RequirementStoragePattern(AbstractionPattern::getInvalid()), + Witness(witness), + WitnessStorage(witness->getAccessorStorageDecl()), + WitnessSubs(witnessSubs) + { + + // Assume that we don't need to reabstract 'self'. Right now, + // that's always true; if we ever reabstract Optional (or other + // nominal types) and allow "partial specialization" extensions, + // this will break, and we'll have to do inout-translation in + // the callback buffer. + SubstSelfType = selfType.getSwiftRValueType(); + + // Determine the formal type of the storage. + CanType witnessIfaceType = + WitnessStorage->getInterfaceType()->getCanonicalType(); + if (isa(WitnessStorage)) + witnessIfaceType = cast(witnessIfaceType).getResult(); + SubstStorageType = getSubstWitnessInterfaceType(witnessIfaceType); + + auto witnessStoragePattern = + SGM.Types.getAbstractionPattern(WitnessStorage); + WitnessStorageType = + SGM.Types.getLoweredType(witnessStoragePattern, SubstStorageType) + .getObjectType(); + + if (Conformance) { + if (auto signature = Conformance->getGenericSignature()) + GenericSig = signature->getCanonicalSignature(); + GenericParams = Conformance->getGenericParams(); + Linkage = SGM.Types.getLinkageForProtocolConformance( + Conformance->getRootNormalConformance(), + ForDefinition); + SelfInterfaceType = conformance->getInterfaceType(); + + RequirementStorage = requirement->getAccessorStorageDecl(); + + // Determine the desired abstraction pattern of the storage type + // in the requirement and the witness. + RequirementStoragePattern = + SGM.Types.getAbstractionPattern(RequirementStorage); + RequirementStorageType = + SGM.Types.getLoweredType(RequirementStoragePattern, SubstStorageType) + .getObjectType(); + + // In a protocol witness thunk, we always want to use ordinary + // access semantics. + TheAccessSemantics = AccessSemantics::Ordinary; + } else { + SILDeclRef constant(witness); + auto constantInfo = SGM.Types.getConstantInfo(constant); + + if (auto signature = witness->getGenericSignatureOfContext()) + GenericSig = signature->getCanonicalSignature(); + GenericParams = constantInfo.ContextGenericParams; + Linkage = constant.getLinkage(ForDefinition); + + SelfInterfaceType = + witness->computeInterfaceSelfType(false) + ->getLValueOrInOutObjectType(); + + // When we're emitting a standard implementation, use direct semantics. + // If we used TheAccessSemantics::Ordinary here, the only downside would + // be unnecessary vtable dispatching for class materializeForSets. + if (!WitnessStorage->hasObservers() && + (WitnessStorage->hasStorage() || + WitnessStorage->hasAddressors())) + TheAccessSemantics = AccessSemantics::DirectToStorage; + else if (WitnessStorage->hasClangNode() || + WitnessStorage->getAttrs().hasAttribute()) + TheAccessSemantics = AccessSemantics::Ordinary; + else + TheAccessSemantics = AccessSemantics::DirectToAccessor; + } + + IsSuper = false; + } + + bool shouldOpenCode() const { + // We need to open-code if there's an abstraction difference in the + // result address. + if (Conformance && RequirementStorageType != WitnessStorageType) + return true; + + // We also need to open-code if the witness is defined in a + // protocol context because IRGen won't know how to reconstruct + // the type parameters. (In principle, this can be done in the + // callback storage if we need to.) + if (Witness->getDeclContext()->isProtocolOrProtocolExtensionContext()) + return true; + + return false; + } + + void emit(SILGenFunction &gen, ManagedValue self, SILValue resultBuffer, + SILValue callbackBuffer, ArrayRef indices); + + SILValue emitUsingStorage(SILGenFunction &gen, SILLocation loc, + ManagedValue self, RValue &&indices); + + SILValue emitUsingAddressor(SILGenFunction &gen, SILLocation loc, + ManagedValue self, RValue &&indices, + SILValue callbackBuffer, SILFunction *&callback); + SILFunction *createAddressorCallback(SILFunction &F, + SILType ownerType, + AddressorKind addressorKind); + + SILValue emitUsingGetterSetter(SILGenFunction &gen, SILLocation loc, + ManagedValue self, RValue &&indices, + SILValue resultBuffer, + SILValue callbackBuffer, + SILFunction *&callback); + SILFunction *createSetterCallback(SILFunction &F, + const TypeLowering *indicesTL, + CanType indicesFormalType); + + using GeneratorFn = llvm::function_ref; + + SILFunction *createCallback(SILFunction &F, GeneratorFn generator); + + RValue collectIndicesFromParameters(SILGenFunction &gen, SILLocation loc, + ArrayRef sourceIndices); + + LValue buildSelfLValue(SILGenFunction &gen, SILLocation loc, + ManagedValue self) { + // All of the complexity here is tied up with class types. If the + // substituted type isn't a reference type, then we can't have a + // class-bounded protocol or inheritance, and the simple case just + // works. + AbstractionPattern selfPattern(SubstSelfType); + + // Metatypes and bases of non-mutating setters on value types + // are always rvalues. + if (!SubstSelfType->mayHaveSuperclass()) { + if (self.getType().isObject()) + return LValue::forValue(self, SubstSelfType); + else { + if (!self.isLValue()) + self = ManagedValue::forLValue(self.getValue()); + return LValue::forAddress(self, selfPattern, SubstSelfType); + } + } + + CanType witnessSelfType = + Witness->computeInterfaceSelfType(false)->getCanonicalType(); + witnessSelfType = getSubstWitnessInterfaceType(witnessSelfType); + if (auto selfTuple = dyn_cast(witnessSelfType)) { + assert(selfTuple->getNumElements() == 1); + witnessSelfType = selfTuple.getElementType(0); + } + witnessSelfType = witnessSelfType.getLValueOrInOutObjectType(); + + // Eagerly loading here could cause an unnecessary + // load+materialize in some cases, but it's not really important. + SILValue selfValue = self.getValue(); + if (selfValue->getType().isAddress()) { + selfValue = gen.B.createLoad(loc, selfValue); + } + + // Do a derived-to-base conversion if necessary. + if (witnessSelfType != SubstSelfType) { + auto selfSILType = SILType::getPrimitiveObjectType(witnessSelfType); + selfValue = gen.B.createUpcast(loc, selfValue, selfSILType); + } + + // Recreate as a borrowed value. + self = ManagedValue::forUnmanaged(selfValue); + return LValue::forClassReference(self); + } + + LValue buildLValue(SILGenFunction &gen, SILLocation loc, + ManagedValue self, RValue &&indices, + AccessKind accessKind) { + // Begin with the 'self' value. + LValue lv = buildSelfLValue(gen, loc, self); + + auto strategy = + WitnessStorage->getAccessStrategy(TheAccessSemantics, accessKind); + + // Drill down to the member storage. + lv.addMemberComponent(gen, loc, WitnessStorage, WitnessSubs, IsSuper, + accessKind, TheAccessSemantics, strategy, + SubstStorageType, std::move(indices)); + assert(lv.getTypeOfRValue().getObjectType() == WitnessStorageType); + + // Reabstract back to the requirement pattern. + if (Conformance && RequirementStorageType != WitnessStorageType) { + SILType substTy = SGM.getLoweredType(SubstStorageType).getObjectType(); + + // FIXME: we can do transforms between two abstraction patterns now + + // Translate to the formal type... + if (WitnessStorageType != substTy) + lv.addOrigToSubstComponent(substTy); + + // ...then back to the requirement type. + if (substTy != RequirementStorageType) + lv.addSubstToOrigComponent(RequirementStoragePattern, + RequirementStorageType); + } + + return lv; + } + + /// Given part of the witness's interface type, produce its + /// substitution according to the witness substitutions. + CanType getSubstWitnessInterfaceType(CanType type) { + return SubstSelfType->getTypeOfMember(SGM.SwiftModule, type, + WitnessStorage->getDeclContext()) + ->getReferenceStorageReferent() + ->getCanonicalType(); + } + +}; + +} // end anonymous namespace + +void MaterializeForSetEmitter::emit(SILGenFunction &gen, ManagedValue self, + SILValue resultBuffer, + SILValue callbackBuffer, + ArrayRef indices) { + SILLocation loc = Witness; + loc.markAutoGenerated(); + + // If there's an abstraction difference, we always need to use the + // get/set pattern. + AccessStrategy strategy; + if (WitnessStorage->getType()->is() || + (Conformance && RequirementStorageType != WitnessStorageType)) { + strategy = AccessStrategy::DispatchToAccessor; + } else { + strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics, + AccessKind::ReadWrite); + } + + // Handle the indices. + RValue indicesRV; + if (isa(WitnessStorage)) { + indicesRV = collectIndicesFromParameters(gen, loc, indices); + } else { + assert(indices.empty() && "indices for a non-subscript?"); + } + + // As above, assume that we don't need to reabstract 'self'. + + // Choose the right implementation. + SILValue address; + SILFunction *callbackFn = nullptr; + switch (strategy) { + case AccessStrategy::Storage: + address = emitUsingStorage(gen, loc, self, std::move(indicesRV)); + break; + + case AccessStrategy::Addressor: + address = emitUsingAddressor(gen, loc, self, std::move(indicesRV), + callbackBuffer, callbackFn); + break; + + case AccessStrategy::DirectToAccessor: + case AccessStrategy::DispatchToAccessor: + address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV), + resultBuffer, callbackBuffer, callbackFn); + break; + } + + // Return the address as a Builtin.RawPointer. + SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext()); + address = gen.B.createAddressToPointer(loc, address, rawPointerTy); + + SILType resultTupleTy = gen.F.mapTypeIntoContext( + gen.F.getLoweredFunctionType()->getResult().getSILType()); + SILType optCallbackTy = resultTupleTy.getTupleElementType(1); + + // Form the callback. + SILValue callback; + if (callbackFn) { + // Make a reference to the function. + callback = gen.B.createFunctionRef(loc, callbackFn); + + // If it's polymorphic, cast to RawPointer and then back to the + // right monomorphic type. The safety of this cast relies on some + // assumptions about what exactly IRGen can reconstruct from the + // callback's thick type argument. + if (callbackFn->getLoweredFunctionType()->isPolymorphic()) { + callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy); + + OptionalTypeKind optKind; + auto callbackTy = optCallbackTy.getAnyOptionalObjectType(SGM.M, optKind); + callback = gen.B.createPointerToThinFunction(loc, callback, callbackTy); + } + + callback = gen.B.createOptionalSome(loc, callback, optCallbackTy); + } else { + callback = gen.B.createOptionalNone(loc, optCallbackTy); + } + + // Form the result and return. + auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback }); + gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc)); + gen.B.createReturn(loc, result); +} + +/// Recursively walk into the given formal index type, expanding tuples, +/// in order to form the arguments to a subscript accessor. +static void translateIndices(SILGenFunction &gen, SILLocation loc, + AbstractionPattern pattern, CanType formalType, + ArrayRef &sourceIndices, + RValue &result) { + // Expand if the pattern was a tuple. + if (pattern.isTuple()) { + auto formalTupleType = cast(formalType); + for (auto i : indices(formalTupleType.getElementTypes())) { + translateIndices(gen, loc, pattern.getTupleElementType(i), + formalTupleType.getElementType(i), + sourceIndices, result); + } + return; + } + + assert(!sourceIndices.empty() && "ran out of elements in index!"); + ManagedValue value = sourceIndices.front(); + sourceIndices = sourceIndices.slice(1); + + // We're going to build an RValue here, so make sure we translate + // indirect arguments to be scalar if we have a loadable type. + if (value.getType().isAddress()) { + auto &valueTL = gen.getTypeLowering(value.getType()); + if (!valueTL.isAddressOnly()) { + value = gen.emitLoad(loc, value.forward(gen), valueTL, + SGFContext(), IsTake); + } + } + + // Reabstract the subscripts from the requirement pattern to the + // formal type. + value = gen.emitOrigToSubstValue(loc, value, pattern, formalType); + + // Invoking the accessor will expect a value of the formal type, so + // don't reabstract to that here. + + // Add that to the result, further expanding if necessary. + result.addElement(gen, value, formalType, loc); +} + +RValue MaterializeForSetEmitter:: +collectIndicesFromParameters(SILGenFunction &gen, SILLocation loc, + ArrayRef sourceIndices) { + auto witnessSubscript = cast(WitnessStorage); + CanType witnessIndicesType = + witnessSubscript->getIndicesInterfaceType()->getCanonicalType(); + CanType substIndicesType = + getSubstWitnessInterfaceType(witnessIndicesType); + + auto reqSubscript = cast(Conformance + ? RequirementStorage + : WitnessStorage); + auto pattern = SGM.Types.getIndicesAbstractionPattern(reqSubscript); + + RValue result(pattern, substIndicesType); + + // Translate and reabstract the index values by recursively walking + // the abstracted index type. + translateIndices(gen, loc, pattern, substIndicesType, + sourceIndices, result); + assert(sourceIndices.empty() && "index value not claimed!"); + + return result; +} + +static FunctionType *getMaterializeForSetCallbackType(ASTContext &ctx, + Type selfType) { + // (inout storage: Builtin.ValueBuffer, + // inout self: Self, + // @thick selfType: Self.Type) -> () + TupleTypeElt params[] = { + ctx.TheRawPointerType, + InOutType::get(ctx.TheUnsafeValueBufferType), + InOutType::get(selfType), + MetatypeType::get(selfType, MetatypeRepresentation::Thick) + }; + Type input = TupleType::get(params, ctx); + Type result = TupleType::getEmpty(ctx); + FunctionType::ExtInfo extInfo = FunctionType::ExtInfo() + .withRepresentation(FunctionType::Representation::Thin); + + return FunctionType::get(input, result, extInfo); +} + +static Type getSelfTypeForCallbackDeclaration(FuncDecl *witness) { + // We're intentionally using non-interface types here: we want + // something specified in terms of the witness's archetypes, because + // we're going to build the closure as if it were contextually + // within the witness. + auto type = witness->getType()->castTo()->getInput(); + if (auto tuple = type->getAs()) { + assert(tuple->getNumElements() == 1); + type = tuple->getElementType(0); + } + return type->getLValueOrInOutObjectType(); +} + +SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F, GeneratorFn generator) { + auto &ctx = SGM.getASTContext(); + + // Mangle this as if it were a conformance thunk for a closure + // within the witness. + std::string name; + { + ClosureExpr closure(/*patterns*/ nullptr, + /*throws*/ SourceLoc(), + /*arrow*/ SourceLoc(), + /*in*/ SourceLoc(), + /*result*/ TypeLoc(), + /*discriminator*/ 0, + /*context*/ Witness); + closure.setType(getMaterializeForSetCallbackType(ctx, + getSelfTypeForCallbackDeclaration(Witness))); + closure.getCaptureInfo().setGenericParamCaptures(true); + + Mangle::Mangler mangler; + if (Conformance) { + mangler.append("_TTW"); + mangler.mangleProtocolConformance(Conformance); + } else { + mangler.append("_T"); + } + mangler.mangleClosureEntity(&closure, /*uncurryLevel=*/1); + name = mangler.finalize(); + } + + // Get lowered formal types for callback parameters. + Type selfType = SelfInterfaceType; + Type selfMetatypeType = MetatypeType::get(SelfInterfaceType, + MetatypeRepresentation::Thick); + + { + GenericContextScope scope(SGM.Types, GenericSig); + + // If 'self' is a metatype, make it @thin or @thick as needed, but not inside + // selfMetatypeType. + if (auto metatype = selfType->getAs()) { + if (!metatype->hasRepresentation()) + selfType = SGM.getLoweredType(metatype).getSwiftRValueType(); + } + } + + // Create the SILFunctionType for the callback. + SILParameterInfo params[] = { + { ctx.TheRawPointerType, ParameterConvention::Direct_Unowned }, + { ctx.TheUnsafeValueBufferType, ParameterConvention::Indirect_Inout }, + { selfType->getCanonicalType(), ParameterConvention::Indirect_Inout }, + { selfMetatypeType->getCanonicalType(), ParameterConvention::Direct_Unowned }, + }; + SILResultInfo result = { + TupleType::getEmpty(ctx), ResultConvention::Unowned + }; + auto extInfo = + SILFunctionType::ExtInfo() + .withRepresentation(SILFunctionTypeRepresentation::Thin); + + auto callbackType = SILFunctionType::get(GenericSig, extInfo, + /*callee*/ ParameterConvention::Direct_Unowned, + params, result, None, ctx); + auto callback = + SGM.M.getOrCreateFunction(Witness, name, Linkage, callbackType, + IsBare, + F.isTransparent(), + F.isFragile()); + + callback->setContextGenericParams(GenericParams); + callback->setDebugScope(new (SGM.M) SILDebugScope(Witness, *callback)); + + PrettyStackTraceSILFunction X("silgen materializeForSet callback", callback); + { + SILGenFunction gen(SGM, *callback); + + auto makeParam = [&](unsigned index) -> SILArgument* { + SILType type = gen.F.mapTypeIntoContext(params[index].getSILType()); + return new (SGM.M) SILArgument(gen.F.begin(), type); + }; + + // Add arguments for all the parameters. + auto valueBuffer = makeParam(0); + auto storageBuffer = makeParam(1); + auto self = makeParam(2); + (void) makeParam(3); + + SILLocation loc = Witness; + loc.markAutoGenerated(); + + // Call the generator function we were provided. + { + LexicalScope scope(gen.Cleanups, gen, CleanupLocation::get(loc)); + generator(gen, loc, valueBuffer, storageBuffer, self); + } + + // Return void. + auto result = gen.emitEmptyTuple(loc); + gen.B.createReturn(loc, result); + } + + callback->verify(); + return callback; +} + +/// Emit a materializeForSet operation that projects storage, assuming +/// that no cleanups or callbacks are required. +SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen, + SILLocation loc, + ManagedValue self, + RValue &&indices) { + LValue lvalue = buildLValue(gen, loc, self, std::move(indices), + AccessKind::ReadWrite); + ManagedValue address = + gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite); + return address.getUnmanagedValue(); +} + +/// Emit a materializeForSet operation that calls a mutable addressor. +/// +/// If it's not an unsafe addressor, this uses a callback function to +/// write the l-value back. +SILValue MaterializeForSetEmitter::emitUsingAddressor(SILGenFunction &gen, + SILLocation loc, + ManagedValue self, + RValue &&indices, + SILValue callbackBuffer, + SILFunction *&callback) { + bool isDirect = (TheAccessSemantics != AccessSemantics::Ordinary); + + // Call the mutable addressor. + auto addressor = gen.getAddressorDeclRef(WitnessStorage, + AccessKind::ReadWrite, + isDirect); + ArgumentSource baseRV = gen.prepareAccessorBaseArg(loc, self, + SubstSelfType, addressor); + SILType addressType = WitnessStorageType.getAddressType(); + auto result = gen.emitAddressorAccessor(loc, addressor, WitnessSubs, + std::move(baseRV), + IsSuper, isDirect, + std::move(indices), + addressType); + SILValue address = result.first.getUnmanagedValue(); + + AddressorKind addressorKind = + WitnessStorage->getMutableAddressor()->getAddressorKind(); + ManagedValue owner = result.second; + if (!owner) { + assert(addressorKind == AddressorKind::Unsafe); + } else { + SILValue allocatedCallbackBuffer = + gen.B.createAllocValueBuffer(loc, owner.getType(), callbackBuffer); + gen.B.createStore(loc, owner.forward(gen), allocatedCallbackBuffer); + + callback = createAddressorCallback(gen.F, owner.getType(), addressorKind); + } + + return address; +} + +/// Emit a materializeForSet callback to clean up after an addressor +/// with an owner result. +SILFunction * +MaterializeForSetEmitter::createAddressorCallback(SILFunction &F, + SILType ownerType, + AddressorKind addressorKind) { + return createCallback(F, [&](SILGenFunction &gen, SILLocation loc, + SILValue resultBuffer, SILValue callbackStorage, + SILValue self) { + auto ownerAddress = + gen.B.createProjectValueBuffer(loc, ownerType, callbackStorage); + auto owner = gen.B.createLoad(loc, ownerAddress); + + switch (addressorKind) { + case AddressorKind::NotAddressor: + case AddressorKind::Unsafe: + llvm_unreachable("owner with unexpected addressor kind"); + + case AddressorKind::Owning: + case AddressorKind::NativeOwning: + gen.B.createStrongRelease(loc, owner); + break; + + case AddressorKind::NativePinning: + gen.B.createStrongUnpin(loc, owner); + break; + } + + gen.B.createDeallocValueBuffer(loc, ownerType, callbackStorage); + }); +} + +/// Emit a materializeForSet operation that simply loads the l-value +/// into the result buffer. This operation creates a callback to write +/// the l-value back. +SILValue +MaterializeForSetEmitter::emitUsingGetterSetter(SILGenFunction &gen, + SILLocation loc, + ManagedValue self, + RValue &&indices, + SILValue resultBuffer, + SILValue callbackBuffer, + SILFunction *&callback) { + // Copy the indices into the callback storage. + const TypeLowering *indicesTL = nullptr; + CleanupHandle indicesCleanup = CleanupHandle::invalid(); + CanType indicesFormalType; + if (isa(WitnessStorage)) { + indicesFormalType = indices.getType(); + indicesTL = &gen.getTypeLowering(indicesFormalType); + SILValue allocatedCallbackBuffer = + gen.B.createAllocValueBuffer(loc, indicesTL->getLoweredType(), + callbackBuffer); + + // Emit into the buffer. + auto init = gen.useBufferAsTemporary(loc, allocatedCallbackBuffer, + *indicesTL); + indicesCleanup = init->getInitializedCleanup(); + + indices.copyInto(gen, init.get(), loc); + } + + // Set up the result buffer. + resultBuffer = + gen.B.createPointerToAddress(loc, resultBuffer, + Conformance + ? RequirementStorageType.getAddressType() + : WitnessStorageType.getAddressType()); + TemporaryInitialization init(resultBuffer, CleanupHandle::invalid()); + + // Evaluate the getter into the result buffer. + LValue lv = buildLValue(gen, loc, self, std::move(indices), AccessKind::Read); + ManagedValue result = gen.emitLoadOfLValue(loc, std::move(lv), + SGFContext(&init)); + if (!result.isInContext()) { + result.forwardInto(gen, loc, resultBuffer); + } + + // Forward the cleanup on the saved indices. + if (indicesCleanup.isValid()) { + gen.Cleanups.setCleanupState(indicesCleanup, CleanupState::Dead); + } + + callback = createSetterCallback(gen.F, indicesTL, indicesFormalType); + return resultBuffer; +} + +namespace { + class DeallocateValueBuffer : public Cleanup { + SILValue Buffer; + SILType ValueType; + public: + DeallocateValueBuffer(SILType valueType, SILValue buffer) + : Buffer(buffer), ValueType(valueType) {} + void emit(SILGenFunction &gen, CleanupLocation loc) override { + gen.B.createDeallocValueBuffer(loc, ValueType, Buffer); + } + }; +} + +/// Emit a materializeForSet callback that stores the value from the +/// result buffer back into the l-value. +SILFunction * +MaterializeForSetEmitter::createSetterCallback(SILFunction &F, + const TypeLowering *indicesTL, + CanType indicesFormalType) { + return createCallback(F, [&](SILGenFunction &gen, SILLocation loc, + SILValue value, SILValue callbackBuffer, + SILValue self) { + // If this is a subscript, we need to handle the indices in the + // callback storage. + RValue indices; + if (indicesTL) { + assert(isa(WitnessStorage)); + SILType indicesTy = indicesTL->getLoweredType(); + + // Enter a cleanup to deallocate the callback storage. + gen.Cleanups.pushCleanup(indicesTy, + callbackBuffer); + + // Project the value out, loading if necessary, and take + // ownership of it. + SILValue indicesV = + gen.B.createProjectValueBuffer(loc, indicesTy, callbackBuffer); + if (indicesTL->isLoadable()) + indicesV = gen.B.createLoad(loc, indicesV); + ManagedValue mIndices = + gen.emitManagedRValueWithCleanup(indicesV, *indicesTL); + + // Explode as an r-value. + indices = RValue(gen, loc, indicesFormalType, mIndices); + } + + // The callback gets the address of 'self' at +0. + ManagedValue mSelf = ManagedValue::forLValue(self); + + // That's enough to build the l-value. + LValue lvalue = buildLValue(gen, loc, mSelf, std::move(indices), + AccessKind::Write); + + // The callback gets the value at +1. + auto &valueTL = gen.getTypeLowering(lvalue.getTypeOfRValue()); + value = gen.B.createPointerToAddress(loc, value, + valueTL.getLoweredType().getAddressType()); + if (valueTL.isLoadable()) + value = gen.B.createLoad(loc, value); + ManagedValue mValue = gen.emitManagedRValueWithCleanup(value, valueTL); + RValue rvalue(gen, loc, lvalue.getSubstFormalType(), mValue); + + // Finally, call the setter. + gen.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue)); + }); +} + +/// Emit an open-coded protocol-witness thunk for materializeForSet if +/// delegating to the standard implementation isn't good enough. +/// +/// materializeForSet sometimes needs to be open-coded because of the +/// thin callback function, which is dependent but cannot be reabstracted. +/// +/// - In a protocol extension, the callback doesn't know how to capture +/// or reconstruct the generic conformance information. +/// +/// - The abstraction pattern of the variable from the witness may +/// differ from the abstraction pattern of the protocol, likely forcing +/// a completely different access pattern (e.g. to write back a +/// reabstracted value instead of modifying it in-place). +/// +/// \return true if special code was emitted +bool SILGenFunction:: +maybeEmitMaterializeForSetThunk(ProtocolConformance *conformance, + FuncDecl *requirement, FuncDecl *witness, + ArrayRef witnessSubs, + ArrayRef origParams) { + // Break apart the parameters. self comes last, the result buffer + // comes first, the callback storage buffer comes second, and the + // rest are indices. + ManagedValue self = origParams.back(); + SILValue resultBuffer = origParams[0].getUnmanagedValue(); + SILValue callbackBuffer = origParams[1].getUnmanagedValue(); + ArrayRef indices = origParams.slice(2).drop_back(); + + MaterializeForSetEmitter emitter(SGM, conformance, requirement, witness, + witnessSubs, self.getType()); + + if (!emitter.shouldOpenCode()) + return false; + + emitter.emit(*this, self, resultBuffer, callbackBuffer, indices); + return true; +} + +/// Emit an open-coded static implementation for materializeForSet. +void SILGenFunction::emitMaterializeForSet(FuncDecl *decl) { + assert(decl->getAccessorKind() == AccessorKind::IsMaterializeForSet); + + MagicFunctionName = SILGenModule::getMagicFunctionName(decl); + F.setBare(IsBare); + + SmallVector params; + collectThunkParams(RegularLocation(decl), params, + /*allowPlusZero*/ true); + + ManagedValue self = params.back(); + SILValue resultBuffer = params[0].getUnmanagedValue(); + SILValue callbackBuffer = params[1].getUnmanagedValue(); + auto indices = ArrayRef(params).slice(2).drop_back(); + + MaterializeForSetEmitter emitter(SGM, + /*conformance=*/ nullptr, + /*requirement=*/ nullptr, + decl, + getForwardingSubstitutions(), + self.getType()); + + emitter.emit(*this, self, resultBuffer, callbackBuffer, indices); +} diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index 57bf622525cda..644e3cbfec834 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Pattern.h" #include "swift/AST/SILOptions.h" @@ -50,7 +51,7 @@ static void dumpPattern(const Pattern *p, llvm::raw_ostream &os) { os << ""; return; case PatternKind::Named: - os << "var " << cast(p)->getBodyName(); + os << "var " << cast(p)->getBoundName(); return; case PatternKind::Tuple: { unsigned numFields = cast(p)->getNumElements(); @@ -449,7 +450,7 @@ class PatternMatchEmission { void bindVariable(SILLocation loc, VarDecl *var, ConsumableManagedValue value, CanType formalValueType, - bool isForSuccess); + bool isIrrefutable); void emitSpecializedDispatch(ClauseMatrix &matrix, ArgArray args, unsigned &lastRow, unsigned column, @@ -526,11 +527,6 @@ class ClauseRow { return Columns; } - /// Remove a column. - void removeColumn(unsigned index) { - Columns.erase(Columns.begin() + index); - } - /// Add new columns to the end of the row. void addColumns(ArrayRef columns) { Columns.append(columns.begin(), columns.end()); @@ -1296,7 +1292,7 @@ void PatternMatchEmission::emitSpecializedDispatch(ClauseMatrix &clauses, ArrayRef rows, const FailureHandler &innerFailure) { // These two operations must follow the same rules for column - // placement because 'arguments' are parallel to the matrix colums. + // placement because 'arguments' are parallel to the matrix columns. // We use the column-specialization algorithm described in // specializeInPlace. ClauseMatrix innerClauses = clauses.specializeRowsInPlace(column, rows); @@ -1382,7 +1378,7 @@ emitTupleDispatch(ArrayRef rows, ConsumableManagedValue src, SmallVector destructured; // Break down the values. - auto tupleSILTy = v.getType(); + auto tupleSILTy = v->getType(); for (unsigned i = 0, e = sourceType->getNumElements(); i < e; ++i) { SILType fieldTy = tupleSILTy.getTupleElementType(i); auto &fieldTL = SGF.getTypeLowering(fieldTy); @@ -1466,7 +1462,7 @@ emitNominalTypeDispatch(ArrayRef rows, CanType baseFormalType = aggMV.getType().getSwiftRValueType(); auto val = SGF.emitRValueForPropertyLoad(loc, aggMV, baseFormalType, false, property, - // FIXME: No generic substitions. + // FIXME: No generic substitutions. {}, AccessSemantics::Ordinary, firstMatcher->getType(), // TODO: Avoid copies on @@ -1698,7 +1694,10 @@ emitEnumElementDispatch(ArrayRef rows, // switch is not exhaustive. bool exhaustive = false; auto enumDecl = sourceType.getEnumOrBoundGenericEnum(); - if (enumDecl->hasFixedLayout(SGF.SGM.M.getSwiftModule())) { + + // FIXME: Get expansion from SILFunction + if (enumDecl->hasFixedLayout(SGF.SGM.M.getSwiftModule(), + ResilienceExpansion::Maximal)) { exhaustive = true; for (auto elt : enumDecl->getAllElements()) { @@ -1827,7 +1826,7 @@ emitEnumElementDispatch(ArrayRef rows, break; case CastConsumptionKind::CopyOnSuccess: { - auto copy = SGF.emitTemporaryAllocation(loc, srcValue.getType()); + auto copy = SGF.emitTemporaryAllocation(loc, srcValue->getType()); SGF.B.createCopyAddr(loc, srcValue, copy, IsNotTake, IsInitialization); // We can always take from the copy. @@ -1857,7 +1856,7 @@ emitEnumElementDispatch(ArrayRef rows, if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) { SILValue boxedValue = SGF.B.createProjectBox(loc, origCMV.getValue()); - eltTL = &SGF.getTypeLowering(boxedValue.getType()); + eltTL = &SGF.getTypeLowering(boxedValue->getType()); if (eltTL->isLoadable()) boxedValue = SGF.B.createLoad(loc, boxedValue); @@ -1875,8 +1874,8 @@ emitEnumElementDispatch(ArrayRef rows, ->getCanonicalType(); eltCMV = emitReabstractedSubobject(SGF, loc, eltCMV, *eltTL, - AbstractionPattern(elt->getArgumentType()), - substEltTy); + SGF.SGM.M.Types.getAbstractionPattern(elt), + substEltTy); } const FailureHandler *innerFailure = &outerFailure; @@ -1942,7 +1941,7 @@ emitBoolDispatch(ArrayRef rows, ConsumableManagedValue src, auto *IL = SGF.B.createIntegerLiteral(PatternMatchStmt, SILType::getBuiltinIntegerType(1, Context), isTrue ? 1 : 0); - caseBBs.push_back({SILValue(IL, 0), curBB}); + caseBBs.push_back({SILValue(IL), curBB}); caseInfos.resize(caseInfos.size() + 1); caseInfos.back().FirstMatcher = row.Pattern; } @@ -1976,7 +1975,7 @@ emitBoolDispatch(ArrayRef rows, ConsumableManagedValue src, assert(Member &&"Bool should have a property with name '_value' of type Int1"); auto *ETI = SGF.B.createStructExtract(loc, srcValue, Member); - SGF.B.createSwitchValue(loc, SILValue(ETI, 0), defaultBB, caseBBs); + SGF.B.createSwitchValue(loc, SILValue(ETI), defaultBB, caseBBs); // Okay, now emit all the cases. for (unsigned i = 0, e = caseInfos.size(); i != e; ++i) { @@ -2049,7 +2048,7 @@ void PatternMatchEmission::emitSharedCaseBlocks() { // blocks might fallthrough into this one. if (!hasFallthroughTo && caseBlock->getCaseLabelItems().size() == 1) { SILBasicBlock *predBB = caseBB->getSinglePredecessor(); - assert(predBB && "Should only have 1 predecesor because it isn't shared"); + assert(predBB && "Should only have 1 predecessor because it isn't shared"); assert(isa(predBB->getTerminator()) && "Should have uncond branch to shared block"); predBB->getTerminator()->eraseFromParent(); diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index a62f8f663ef5f..49eb115887966 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -49,7 +49,7 @@ // parameter of the base with a concrete type, the derived class can override // methods in the base that involved generic types. In the derived class, a // method override that involves substituted types will have a different -// SIL lowering than the base method. In this case, the overriden vtable entry +// SIL lowering than the base method. In this case, the overridden vtable entry // will point to a thunk which transforms parameters and results and invokes // the derived method. // @@ -141,18 +141,18 @@ namespace { }; }; -static ArrayRef +static ArrayRef collectExistentialConformances(Module *M, Type fromType, Type toType) { assert(!fromType->isAnyExistentialType()); SmallVector protocols; toType->getAnyExistentialTypeProtocols(protocols); - SmallVector conformances; + SmallVector conformances; for (auto proto : protocols) { ProtocolConformance *conformance = - M->lookupConformance(fromType, proto, nullptr).getPointer(); - conformances.push_back(conformance); + M->lookupConformance(fromType, proto, nullptr).getPointer(); + conformances.push_back(ProtocolConformanceRef(proto, conformance)); } return M->getASTContext().AllocateCopy(conformances); @@ -200,7 +200,7 @@ static ManagedValue emitTransformExistential(SILGenFunction &SGF, ->getInstanceType(); } - ArrayRef conformances = + ArrayRef conformances = collectExistentialConformances(SGF.SGM.M.getSwiftModule(), fromInstanceType, toInstanceType); @@ -472,7 +472,7 @@ static void explodeTuple(SILGenFunction &gen, // elements. SILValue tuple = managedTuple.forward(gen); - auto tupleSILType = tuple.getType(); + auto tupleSILType = tuple->getType(); auto tupleType = tupleSILType.castTo(); out.reserve(tupleType->getNumElements()); @@ -553,7 +553,7 @@ ManagedValue Transform::transformTuple(ManagedValue inputTuple, if (outputAddr) { SILValue outputEltAddr = SGF.B.createTupleElementAddr(Loc, outputAddr, index); - auto &outputEltTL = SGF.getTypeLowering(outputEltAddr.getType()); + auto &outputEltTL = SGF.getTypeLowering(outputEltAddr->getType()); assert(outputEltTL.isAddressOnly() == inputEltTL.isAddressOnly()); auto cleanup = SGF.enterDormantTemporaryCleanup(outputEltAddr, outputEltTL); @@ -623,7 +623,7 @@ static ManagedValue manageParam(SILGenFunction &gen, // Unowned parameters are only guaranteed at the instant of the call, so we // must retain them even if we're in a context that can accept a +0 value. case ParameterConvention::Direct_Unowned: - gen.getTypeLowering(paramValue.getType()) + gen.getTypeLowering(paramValue->getType()) .emitRetainValue(gen.B, loc, paramValue); SWIFT_FALLTHROUGH; case ParameterConvention::Direct_Owned: @@ -635,7 +635,7 @@ static ManagedValue manageParam(SILGenFunction &gen, if (allowPlusZero) { return ManagedValue::forUnmanaged(paramValue); } else { - auto copy = gen.emitTemporaryAllocation(loc, paramValue.getType()); + auto copy = gen.emitTemporaryAllocation(loc, paramValue->getType()); gen.B.createCopyAddr(loc, paramValue, copy, IsNotTake, IsInitialization); return gen.emitManagedBufferWithCleanup(copy); } @@ -650,18 +650,16 @@ static ManagedValue manageParam(SILGenFunction &gen, llvm_unreachable("bad parameter convention"); } -static void collectParams(SILGenFunction &gen, - SILLocation loc, - SmallVectorImpl ¶ms, - bool allowPlusZero) { +void SILGenFunction::collectThunkParams(SILLocation loc, + SmallVectorImpl ¶ms, + bool allowPlusZero) { auto paramTypes = - gen.F.getLoweredFunctionType()->getParametersWithoutIndirectResult(); + F.getLoweredFunctionType()->getParametersWithoutIndirectResult(); for (auto param : paramTypes) { - auto paramTy = gen.F.mapTypeIntoContext(param.getSILType()); - auto paramValue = new (gen.SGM.M) SILArgument(gen.F.begin(), - paramTy); - - params.push_back(manageParam(gen, loc, paramValue, param, allowPlusZero)); + auto paramTy = F.mapTypeIntoContext(param.getSILType()); + auto paramValue = new (SGM.M) SILArgument(F.begin(), paramTy); + auto paramMV = manageParam(*this, loc, paramValue, param, allowPlusZero); + params.push_back(paramMV); } } @@ -762,7 +760,7 @@ namespace { if (outputTupleType) { // The input is exploded and the output is not. Translate values // and store them to a result tuple in memory. - assert(outputOrigType.isOpaque() && + assert(outputOrigType.isTypeParameter() && "Output is not a tuple and is not opaque?"); auto output = claimNextOutputType(); @@ -787,7 +785,7 @@ namespace { if (inputTupleType) { // The input is exploded and the output is not. Translate values // and store them to a result tuple in memory. - assert(inputOrigType.isOpaque() && + assert(inputOrigType.isTypeParameter() && "Input is not a tuple and is not opaque?"); return translateAndExplodeOutOf(inputOrigType, @@ -986,7 +984,7 @@ namespace { AbstractionPattern outputOrigType, CanTupleType outputSubstType, ManagedValue inputTupleAddr) { - assert(inputOrigType.isOpaque()); + assert(inputOrigType.isTypeParameter()); assert(outputOrigType.matchesTuple(outputSubstType)); assert(!inputSubstType->hasInOut() && !outputSubstType->hasInOut()); @@ -1033,7 +1031,7 @@ namespace { CanTupleType outputSubstType, TemporaryInitialization &tupleInit) { assert(inputOrigType.matchesTuple(inputSubstType)); - assert(outputOrigType.isOpaque()); + assert(outputOrigType.isTypeParameter()); assert(!inputSubstType->hasInOut() && !outputSubstType->hasInOut()); assert(inputSubstType->getNumElements() == @@ -1110,7 +1108,7 @@ namespace { llvm::errs() << "inout writeback in abstraction difference thunk " "not yet implemented\n"; llvm::errs() << "input value "; - input.getValue().dump(); + input.getValue()->dump(); llvm::errs() << "output type " << result.getSILType() << "\n"; abort(); } @@ -1207,7 +1205,7 @@ static SILValue getThunkInnerResultAddr(SILGenFunction &gen, resultType = gen.F.mapTypeIntoContext(resultType); // Re-use the original result if possible. - if (outerResultAddr && outerResultAddr.getType() == resultType) + if (outerResultAddr && outerResultAddr->getType() == resultType) return outerResultAddr; else return gen.emitTemporaryAllocation(loc, resultType); @@ -1310,7 +1308,7 @@ static SILValue getThunkResult(SILGenFunction &gen, /// \param inputOrigType Abstraction pattern of function value being thunked /// \param inputSubstType Formal AST type of function value being thunked /// \param outputOrigType Abstraction pattern of the thunk -/// \param outputSubstType Formal AST type of the thuk +/// \param outputSubstType Formal AST type of the thunk static void buildThunkBody(SILGenFunction &gen, SILLocation loc, AbstractionPattern inputOrigType, CanAnyFunctionType inputSubstType, @@ -1332,7 +1330,7 @@ static void buildThunkBody(SILGenFunction &gen, SILLocation loc, SmallVector params; // TODO: Could accept +0 arguments here when forwardFunctionArguments/ // emitApply can. - collectParams(gen, loc, params, /*allowPlusZero*/ false); + gen.collectThunkParams(loc, params, /*allowPlusZero*/ false); ManagedValue fnValue = params.pop_back_val(); auto fnType = fnValue.getType().castTo(); @@ -1412,7 +1410,10 @@ CanSILFunctionType SILGenFunction::buildThunkType( auto genericSig = F.getLoweredFunctionType()->getGenericSignature(); if (generics) { for (auto archetype : generics->getAllNestedArchetypes()) { - subs.push_back({ archetype, archetype, { } }); + SmallVector conformances; + for (auto proto : archetype->getConformsTo()) + conformances.push_back(ProtocolConformanceRef(proto)); + subs.push_back({ archetype, getASTContext().AllocateCopy(conformances) }); } } @@ -1668,6 +1669,13 @@ SILGenFunction::emitVTableThunk(SILDeclRef derived, F.setContextGenericParams(context); subs = getForwardingSubstitutions(); fTy = fTy->substGenericArgs(SGM.M, SGM.SwiftModule, subs); + + inputSubstType = cast( + cast(inputSubstType) + ->substGenericArgs(SGM.SwiftModule, subs)->getCanonicalType()); + outputSubstType = cast( + cast(outputSubstType) + ->substGenericArgs(SGM.SwiftModule, subs)->getCanonicalType()); } // Emit the indirect return and arguments. @@ -1680,7 +1688,7 @@ SILGenFunction::emitVTableThunk(SILDeclRef derived, } SmallVector thunkArgs; - collectParams(*this, loc, thunkArgs, /*allowPlusZero*/ true); + collectThunkParams(loc, thunkArgs, /*allowPlusZero*/ true); SmallVector substArgs; // If the thunk and implementation share an indirect result type, use it @@ -1823,7 +1831,7 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, SmallVector origParams; // TODO: Should be able to accept +0 values here, once // forwardFunctionArguments/emitApply are able to. - collectParams(*this, loc, origParams, /*allowPlusZero*/ false); + collectThunkParams(loc, origParams, /*allowPlusZero*/ false); // Handle special abstraction differences in "self". // If the witness is a free function, drop it completely. @@ -1831,13 +1839,17 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, if (isFree) origParams.pop_back(); + // Open-code certain protocol witness "thunks". + if (maybeOpenCodeProtocolWitness(*this, conformance, requirement, + witness, witnessSubs, origParams)) + return; + // Get the type of the witness. auto witnessInfo = getConstantInfo(witness); - CanAnyFunctionType witnessFormalTy = witnessInfo.LoweredType; - CanAnyFunctionType witnessSubstTy = witnessFormalTy; + CanAnyFunctionType witnessSubstTy = witnessInfo.LoweredInterfaceType; if (!witnessSubs.empty()) { witnessSubstTy = cast( - cast(witnessSubstTy) + cast(witnessSubstTy) ->substGenericArgs(SGM.M.getSwiftModule(), witnessSubs) ->getCanonicalType()); } @@ -1847,19 +1859,21 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, // abstraction pattern. auto reqtInfo = getConstantInfo(requirement); - // Ugh... - CanAnyFunctionType reqtSubstTy = reqtInfo.FormalType; + // FIXME: reqtSubstTy is already computed in SGM::emitProtocolWitness(), + // but its called witnessSubstIfaceTy there; the mapTypeIntoContext() + // calls should be pushed down into thunk emission. + CanAnyFunctionType reqtSubstTy = reqtInfo.LoweredInterfaceType; reqtSubstTy = cast( - cast(reqtSubstTy) - ->substGenericArgs(conformance->getDeclContext()->getParentModule(), - conformance->getType()) + cast(reqtSubstTy) + ->partialSubstGenericArgs(conformance->getDeclContext()->getParentModule(), + conformance->getInterfaceType()) ->getCanonicalType()); - reqtSubstTy = SGM.Types.getLoweredASTFunctionType(reqtSubstTy, - requirement.uncurryLevel, - requirement); - CanType reqtSubstInputTy = reqtSubstTy.getInput(); + CanType reqtSubstInputTy = F.mapTypeIntoContext(reqtSubstTy.getInput()) + ->getCanonicalType(); + CanType reqtSubstResultTy = F.mapTypeIntoContext(reqtSubstTy.getResult()) + ->getCanonicalType(); - AbstractionPattern reqtOrigTy(reqtInfo.LoweredType); + AbstractionPattern reqtOrigTy(reqtInfo.LoweredInterfaceType); AbstractionPattern reqtOrigInputTy = reqtOrigTy.getFunctionInputType(); // For a free function witness, discard the 'self' parameter of the // requirement. @@ -1868,11 +1882,6 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, reqtSubstInputTy = dropLastElement(reqtSubstInputTy); } - // Open-code certain protocol witness "thunks". - if (maybeOpenCodeProtocolWitness(*this, conformance, requirement, - witness, witnessSubs, origParams)) - return; - // Translate the argument values from the requirement abstraction level to // the substituted signature of the witness. SmallVector witnessParams; @@ -1920,7 +1929,7 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, witness, isFree, witnessParams, loc); - auto witnessFTy = witnessFnRef.getType().getAs(); + auto witnessFTy = witnessFnRef->getType().getAs(); if (!witnessSubs.empty()) witnessFTy = witnessFTy->substGenericArgs(SGM.M, SGM.M.getSwiftModule(), @@ -1936,7 +1945,7 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, // TODO: Collect forwarding substitutions from outer context of method. auto witnessResultAddr = witnessSubstResultAddr; - AbstractionPattern witnessOrigTy(witnessFormalTy); + AbstractionPattern witnessOrigTy(witnessInfo.LoweredInterfaceType); if (witnessFTy != witnessSubstFTy) { SmallVector genParams; TranslateArguments(*this, loc, @@ -1981,7 +1990,7 @@ void SILGenFunction::emitProtocolWitness(ProtocolConformance *conformance, AbstractionPattern(witnessSubstTy.getResult()), // XXX ugly witnessSubstTy.getResult(), reqtOrigTy.getFunctionResultType(), - reqtSubstTy.getResult(), + reqtSubstResultTy, witnessResultValue, witnessSubstResultAddr, reqtResultAddr); diff --git a/lib/SILGen/SILGenProfiling.cpp b/lib/SILGen/SILGenProfiling.cpp index 5e84602be92d5..af966d51e1992 100644 --- a/lib/SILGen/SILGenProfiling.cpp +++ b/lib/SILGen/SILGenProfiling.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -564,8 +564,11 @@ struct CoverageMapping : public ASTWalker { assignCounter(E); } else if (auto *IE = dyn_cast(E)) { CounterExpr &ThenCounter = assignCounter(IE->getThenExpr()); - assignCounter(IE->getElseExpr(), - CounterExpr::Sub(getCurrentCounter(), ThenCounter)); + if (Parent.isNull()) + assignCounter(IE->getElseExpr()); + else + assignCounter(IE->getElseExpr(), + CounterExpr::Sub(getCurrentCounter(), ThenCounter)); } if (hasCounter(E)) @@ -604,9 +607,7 @@ static void walkForProfiling(AbstractFunctionDecl *Root, ASTWalker &Walker) { } void SILGenProfiling::assignRegionCounters(AbstractFunctionDecl *Root) { - SmallString<128> NameBuffer; - SILDeclRef(Root).mangle(NameBuffer); - CurrentFuncName = NameBuffer.str(); + CurrentFuncName = SILDeclRef(Root).mangle(); MapRegionCounters Mapper(RegionCounterMap); walkForProfiling(Root, Mapper); diff --git a/lib/SILGen/SILGenProfiling.h b/lib/SILGen/SILGenProfiling.h index 779f0d7538b84..417a6200934d4 100644 --- a/lib/SILGen/SILGenProfiling.h +++ b/lib/SILGen/SILGenProfiling.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index 7063a25508a45..c13e728464eeb 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,6 +15,7 @@ #include "ManagedValue.h" #include "Scope.h" #include "swift/SIL/SILArgument.h" +#include "swift/AST/ParameterList.h" #include "swift/Basic/Fallthrough.h" using namespace swift; @@ -34,7 +35,7 @@ SILValue SILGenFunction::emitSelfDecl(VarDecl *selfDecl) { namespace { -/// Cleanup that writes back to a inout argument on function exit. +/// Cleanup that writes back to an inout argument on function exit. class CleanupWriteBackToInOut : public Cleanup { VarDecl *var; SILValue inoutAddr; @@ -51,7 +52,10 @@ class CleanupWriteBackToInOut : public Cleanup { IsNotTake, IsNotInitialization); } }; +} // end anonymous namespace + +namespace { class StrongReleaseCleanup : public Cleanup { SILValue box; public: @@ -60,7 +64,10 @@ class StrongReleaseCleanup : public Cleanup { gen.B.emitStrongReleaseAndFold(l, box); } }; +} // end anonymous namespace + +namespace { class EmitBBArguments : public CanTypeVisitor { @@ -199,12 +206,14 @@ class EmitBBArguments : public CanTypeVisitor -{ + +namespace { + +/// A helper for creating SILArguments and binding variables to the argument +/// names. +struct ArgumentInitHelper { SILGenFunction &gen; SILFunction &f; SILGenBuilder &initB; @@ -214,7 +223,7 @@ struct ArgumentInitVisitor : ArrayRef parameters; unsigned ArgNo = 0; - ArgumentInitVisitor(SILGenFunction &gen, SILFunction &f) + ArgumentInitHelper(SILGenFunction &gen, SILFunction &f) : gen(gen), f(f), initB(gen.B), parameters(f.getLoweredFunctionType()->getParameters()) { // If we have an out parameter, skip it. @@ -229,7 +238,6 @@ struct ArgumentInitVisitor : // Create an RValue by emitting destructured arguments into a basic block. CanType canTy = ty->getCanonicalType(); - return EmitBBArguments(gen, parent, l, /*functionArgs*/ true, parameters).visit(canTy); } @@ -295,142 +303,54 @@ struct ArgumentInitVisitor : argrv.copyInto(gen, initVar->getAddress(), loc); initVar->finishInitialization(gen); - } } - // Paren, Typed, and Var patterns are no-ops. Just look through them. - void visitParenPattern(ParenPattern *P) { - visit(P->getSubPattern()); - } - void visitTypedPattern(TypedPattern *P) { - visit(P->getSubPattern()); - } - void visitVarPattern(VarPattern *P) { - visit(P->getSubPattern()); - } - - void visitTuplePattern(TuplePattern *P) { - // Destructure tuples into their elements. - for (size_t i = 0, size = P->getNumElements(); i < size; ++i) - visit(P->getElement(i).getPattern()); - } - - void visitAnyPattern(AnyPattern *P) { - llvm_unreachable("unnamed parameters should have a ParamDecl"); - } - - void visitNamedPattern(NamedPattern *P) { + void emitParam(ParamDecl *PD) { ++ArgNo; - auto PD = P->getDecl(); - if (!PD->hasName()) { - // A value bound to _ is unused and can be immediately released. - Scope discardScope(gen.Cleanups, CleanupLocation(P)); - makeArgument(P->getType(), &*f.begin(), PD); - // Popping the scope destroys the value. - } else { - makeArgumentIntoBinding(P->getType(), &*f.begin(), PD); + if (PD->hasName()) { + makeArgumentIntoBinding(PD->getType(), &*f.begin(), PD); + return; } - } - -#define PATTERN(Id, Parent) -#define REFUTABLE_PATTERN(Id, Parent) \ - void visit##Id##Pattern(Id##Pattern *) { \ - llvm_unreachable("pattern not valid in argument binding"); \ - } -#include "swift/AST/PatternNodes.def" -}; - -// Unlike the ArgumentInitVisitor, this visitor generates arguments but leaves -// them destructured instead of storing them to lvalues so that the -// argument set can be easily forwarded to another function. -class ArgumentForwardVisitor - : public PatternVisitor -{ - SILGenFunction &gen; - SmallVectorImpl &args; -public: - ArgumentForwardVisitor(SILGenFunction &gen, - SmallVectorImpl &args) - : gen(gen), args(args) {} - - void makeArgument(Type ty, VarDecl *varDecl) { - assert(ty && "no type?!"); - // Destructure tuple arguments. - if (TupleType *tupleTy = ty->getAs()) { - for (auto fieldType : tupleTy->getElementTypes()) - makeArgument(fieldType, varDecl); - } else { - SILValue arg = - new (gen.F.getModule()) SILArgument(gen.F.begin(), - gen.getLoweredType(ty), - varDecl); - args.push_back(arg); - } - } - - void visitParenPattern(ParenPattern *P) { - visit(P->getSubPattern()); - } - void visitVarPattern(VarPattern *P) { - visit(P->getSubPattern()); - } - - void visitTypedPattern(TypedPattern *P) { - // FIXME: work around a bug in visiting the "self" argument of methods - if (auto NP = dyn_cast(P->getSubPattern())) - makeArgument(P->getType(), NP->getDecl()); + + ManagedValue argrv = makeArgument(PD->getType(), &*f.begin(), PD); + // Emit debug information for the argument. + SILLocation loc(PD); + loc.markAsPrologue(); + if (argrv.getType().isAddress()) + gen.B.createDebugValueAddr(loc, argrv.getValue(), {PD->isLet(), ArgNo}); else - visit(P->getSubPattern()); - } - - void visitTuplePattern(TuplePattern *P) { - for (auto &elt : P->getElements()) - visit(elt.getPattern()); - } - - void visitAnyPattern(AnyPattern *P) { - llvm_unreachable("unnamed parameters should have a ParamDecl"); - } + gen.B.createDebugValue(loc, argrv.getValue(), {PD->isLet(), ArgNo}); - void visitNamedPattern(NamedPattern *P) { - makeArgument(P->getType(), P->getDecl()); + // A value bound to _ is unused and can be immediately released. + Scope discardScope(gen.Cleanups, CleanupLocation(PD)); + // Popping the scope destroys the value. } - -#define PATTERN(Id, Parent) -#define REFUTABLE_PATTERN(Id, Parent) \ - void visit##Id##Pattern(Id##Pattern *) { \ - llvm_unreachable("pattern not valid in argument binding"); \ - } -#include "swift/AST/PatternNodes.def" }; - } // end anonymous namespace -void SILGenFunction::bindParametersForForwarding(Pattern *pattern, - SmallVectorImpl ¶meters) { - ArgumentForwardVisitor(*this, parameters).visit(pattern); + +static void makeArgument(Type ty, ParamDecl *decl, + SmallVectorImpl &args, SILGenFunction &gen) { + assert(ty && "no type?!"); + + // Destructure tuple arguments. + if (TupleType *tupleTy = ty->getAs()) { + for (auto fieldType : tupleTy->getElementTypes()) + makeArgument(fieldType, decl, args, gen); + } else { + auto arg = new (gen.F.getModule()) SILArgument(gen.F.begin(), + gen.getLoweredType(ty),decl); + args.push_back(arg); + } } -/// Tuple values captured by a closure are passed as individual arguments to the -/// SILFunction since SILFunctionType canonicalizes away tuple types. -static SILValue -emitReconstitutedConstantCaptureArguments(SILType ty, - ValueDecl *capture, - SILGenFunction &gen) { - auto TT = ty.getAs(); - if (!TT) - return new (gen.SGM.M) SILArgument(gen.F.begin(), ty, capture); - - SmallVector Elts; - for (unsigned i = 0, e = TT->getNumElements(); i != e; ++i) { - auto EltTy = ty.getTupleElementType(i); - auto EV = - emitReconstitutedConstantCaptureArguments(EltTy, capture, gen); - Elts.push_back(EV); - } - return gen.B.createTuple(capture, ty, Elts); +void SILGenFunction::bindParametersForForwarding(const ParameterList *params, + SmallVectorImpl ¶meters) { + for (auto param : *params) { + makeArgument(param->getType(), param, parameters, *this); + } } static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture, @@ -445,10 +365,9 @@ static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture, case CaptureKind::Constant: { auto &lowering = gen.getTypeLowering(VD->getType()); - // Constant decls are captured by value. If the captured value is a tuple - // value, we need to reconstitute it before sticking it in VarLocs. + // Constant decls are captured by value. SILType ty = lowering.getLoweredType(); - SILValue val = emitReconstitutedConstantCaptureArguments(ty, VD, gen); + SILValue val = new (gen.SGM.M) SILArgument(gen.F.begin(), ty, VD); // If the original variable was settable, then Sema will have treated the // VarDecl as an lvalue, even in the closure's use. As such, we need to @@ -465,7 +384,10 @@ static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture, AllocStack->setArgNo(ArgNo); else gen.B.createDebugValue(Loc, val, {/*Constant*/true, ArgNo}); - if (!lowering.isTrivial()) + + // TODO: Closure contexts should always be guaranteed. + if (!gen.SGM.M.getOptions().EnableGuaranteedClosureContexts + && !lowering.isTrivial()) gen.enterDestroyCleanup(val); break; } @@ -480,7 +402,8 @@ static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture, SILValue addr = gen.B.createProjectBox(VD, box); gen.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box); gen.B.createDebugValueAddr(Loc, addr, {/*Constant*/false, ArgNo}); - gen.Cleanups.pushCleanup(box); + if (!gen.SGM.M.getOptions().EnableGuaranteedClosureContexts) + gen.Cleanups.pushCleanup(box); break; } case CaptureKind::StorageAddress: { @@ -495,7 +418,7 @@ static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture, } void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, - ArrayRef paramPatterns, + ArrayRef paramPatterns, Type resultType) { unsigned ArgNo = emitProlog(paramPatterns, resultType, TheClosure.getAsDeclContext()); @@ -507,13 +430,13 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, emitCaptureArguments(*this, capture, ++ArgNo); } -unsigned SILGenFunction::emitProlog(ArrayRef paramPatterns, +unsigned SILGenFunction::emitProlog(ArrayRef paramLists, Type resultType, DeclContext *DeclCtx) { // If the return type is address-only, emit the indirect return argument. const TypeLowering &returnTI = getTypeLowering(resultType); if (returnTI.isReturnedIndirectly()) { auto &AC = getASTContext(); - auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), + auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), resultType, DeclCtx); @@ -522,12 +445,14 @@ unsigned SILGenFunction::emitProlog(ArrayRef paramPatterns, } // Emit the argument variables in calling convention order. - ArgumentInitVisitor argVisitor(*this, F); - for (Pattern *p : reversed(paramPatterns)) { + ArgumentInitHelper emitter(*this, F); + + for (ParameterList *paramList : reversed(paramLists)) { // Add the SILArguments and use them to initialize the local argument // values. - argVisitor.visit(p); + for (auto ¶m : *paramList) + emitter.emitParam(param); } - return argVisitor.getNumArgs(); + return emitter.getNumArgs(); } diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index bfbb04575a3a3..2a5dd96347ae4 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -53,7 +53,8 @@ SILBasicBlock *SILGenFunction::createBasicBlock(FunctionSection section) { // The end of the ordinary section is just the end of the function // unless postmatter blocks exist. SILBasicBlock *afterBB = - (StartOfPostmatter ? StartOfPostmatter->getPrevNode() : nullptr); + (StartOfPostmatter ? &*std::prev(StartOfPostmatter->getIterator()) + : nullptr); return new (F.getModule()) SILBasicBlock(&F, afterBB); } @@ -73,7 +74,7 @@ void SILGenFunction::eraseBasicBlock(SILBasicBlock *block) { assert(block->pred_empty() && "erasing block with predecessors"); assert(block->empty() && "erasing block with content"); if (block == StartOfPostmatter) { - StartOfPostmatter = block->getNextNode(); + StartOfPostmatter = &*std::next(block->getIterator()); } block->eraseFromParent(); } @@ -147,7 +148,7 @@ Condition SILGenFunction::emitCondition(Expr *E, FullExpr Scope(Cleanups, CleanupLocation(E)); V = emitRValue(E).forwardAsSingleValue(*this, E); } - assert(V.getType().castTo()->isFixedWidth(1)); + assert(V->getType().castTo()->isFixedWidth(1)); return emitCondition(V, E, hasFalseCode, invertValue, contArgs); } @@ -511,7 +512,7 @@ void StmtEmitter::visitDoCatchStmt(DoCatchStmt *S) { SILArgument *exnArg = throwDest.getBlock()->createBBArg(exnTL.getLoweredType()); - // We always need an continuation block because we might fall out of + // We always need a continuation block because we might fall out of // a catch block. But we don't need a loop block unless the 'do' // statement is labeled. JumpDest endDest = createJumpDest(S->getBody()); diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 9a4044bd97715..1548dff417f46 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,8 +33,7 @@ using namespace Lowering; SILFunction *SILGenModule::getDynamicThunk(SILDeclRef constant, SILConstantInfo constantInfo) { // Mangle the constant with a _TTD header. - llvm::SmallString<32> name; - constant.mangle(name, "_TTD"); + auto name = constant.mangle("_TTD"); auto F = M.getOrCreateFunction(constant.getDecl(), name, SILLinkage::Shared, constantInfo.getSILType().castTo(), @@ -63,8 +62,7 @@ SILGenModule::emitVTableMethod(SILDeclRef derived, SILDeclRef base) { // TODO: If we allocated a new vtable slot for the derived method, then // further derived methods would potentially need multiple thunks, and we // would need to mangle the base method into the symbol as well. - llvm::SmallString<32> name; - derived.mangle(name, "_TTV"); + auto name = derived.mangle("_TTV"); // If we already emitted this thunk, reuse it. // TODO: Allocating new vtable slots for derived methods with different ABIs @@ -76,7 +74,7 @@ SILGenModule::emitVTableMethod(SILDeclRef derived, SILDeclRef base) { // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); auto derivedInfo = Types.getConstantInfo(derived); - auto basePattern = AbstractionPattern(baseInfo.LoweredType); + auto basePattern = AbstractionPattern(baseInfo.LoweredInterfaceType); auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); @@ -96,7 +94,8 @@ SILGenModule::emitVTableMethod(SILDeclRef derived, SILDeclRef base) { SILGenFunction(*this, *thunk) .emitVTableThunk(derived, basePattern, - overrideInfo.LoweredType, derivedInfo.LoweredType); + overrideInfo.LoweredInterfaceType, + derivedInfo.LoweredInterfaceType); return thunk; } diff --git a/lib/SILGen/Scope.h b/lib/SILGen/Scope.h index 26fd6d5b46053..b8c74ad9d91be 100644 --- a/lib/SILGen/Scope.h +++ b/lib/SILGen/Scope.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -93,6 +93,17 @@ class LLVM_LIBRARY_VISIBILITY LexicalScope : private Scope { } }; +/// A scope that only exists in the debug info. +class LLVM_LIBRARY_VISIBILITY DebugScope { + SILGenFunction &SGF; + +public: + explicit DebugScope(SILGenFunction &SGF, CleanupLocation Loc) : SGF(SGF) { + SGF.enterDebugScope(Loc); + } + + ~DebugScope() { SGF.leaveDebugScope(); } +}; } // end namespace Lowering } // end namespace swift diff --git a/lib/SILGen/SpecializedEmitter.h b/lib/SILGen/SpecializedEmitter.h index 88ac5c9cce699..4c1d59439148d 100644 --- a/lib/SILGen/SpecializedEmitter.h +++ b/lib/SILGen/SpecializedEmitter.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILGen/Varargs.h b/lib/SILGen/Varargs.h index 5ee6b4e37fffd..c498f59745df6 100644 --- a/lib/SILGen/Varargs.h +++ b/lib/SILGen/Varargs.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/ARC/ARCBBState.cpp b/lib/SILOptimizer/ARC/ARCBBState.cpp index 80e9709c2f772..ffe3814ca3d18 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.cpp +++ b/lib/SILOptimizer/ARC/ARCBBState.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "ARCBBState.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/ARC/ARCBBState.h b/lib/SILOptimizer/ARC/ARCBBState.h index dc9b5b523ef98..1daecceb653f8 100644 --- a/lib/SILOptimizer/ARC/ARCBBState.h +++ b/lib/SILOptimizer/ARC/ARCBBState.h @@ -1,8 +1,8 @@ -//===--- ARCBBState.h --------------------------------------*- C++ -*------===// +//===--- ARCBBState.h -------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -55,7 +55,7 @@ class ARCSequenceDataflowEvaluator::ARCBBState { /// builtin "int_trap"() : $() /// unreachable /// - /// This can not have any uses of reference counted values since the frontend + /// This cannot have any uses of reference counted values since the frontend /// just leaks at that point. bool isTrapBB() const { return IsTrapBB; } diff --git a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp index 68882766f12f8..ef437ae3354d2 100644 --- a/lib/SILOptimizer/ARC/ARCLoopOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCLoopOpts.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,11 +21,11 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "swift/SILOptimizer/PassManager/Passes.h" #include "GlobalARCPairingAnalysis.h" -#include "ProgramTerminationAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" diff --git a/lib/SILOptimizer/ARC/ARCRegionState.cpp b/lib/SILOptimizer/ARC/ARCRegionState.cpp index 72727763e1f03..1adeae1412dbd 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.cpp +++ b/lib/SILOptimizer/ARC/ARCRegionState.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "ARCRegionState.h" #include "RCStateTransitionVisitors.h" #include "swift/Basic/Range.h" @@ -158,13 +158,80 @@ void ARCRegionState::mergePredTopDown(ARCRegionState &PredRegionState) { // Bottom Up Dataflow // +static bool isARCSignificantTerminator(TermInst *TI) { + switch (TI->getTermKind()) { + case TermKind::UnreachableInst: + // br is a forwarding use for its arguments. It cannot in of itself extend + // the lifetime of an object (just like a phi-node) cannot. + case TermKind::BranchInst: + // A cond_br is a forwarding use for its non-operand arguments in a similar + // way to br. Its operand must be an i1 that has a different lifetime from any + // ref counted object. + case TermKind::CondBranchInst: + return false; + // Be conservative for now. These actually perform some sort of operation + // against the operand or can use the value in some way. + case TermKind::ThrowInst: + case TermKind::ReturnInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + } +} + +// Visit each one of our predecessor regions and see if any are blocks that can +// use reference counted values. If any of them do, we advance the sequence for +// the pointer and create an insertion point here. This state will be propagated +// into all of our predecessors, allowing us to be conservatively correct in all +// cases. +// +// The key thing to notice is that in general this cannot happen due to +// critical edge splitting. To trigger this, one would need a terminator that +// uses a reference counted value and only has one successor due to critical +// edge splitting. This is just to be conservative when faced with the unknown +// of future changes. +// +// We do not need to worry about loops here, since a loop exit block can only +// have predecessors in the loop itself implying that loop exit blocks at the +// loop region level always have only one predecessor, the loop itself. +void ARCRegionState::processBlockBottomUpPredTerminators( + const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI) { + auto &BB = *R->getBlock(); + llvm::TinyPtrVector PredTerminators; + for (unsigned PredID : R->getPreds()) { + auto *PredRegion = LRFI->getRegion(PredID); + if (!PredRegion->isBlock()) + continue; + + auto *TermInst = PredRegion->getBlock()->getTerminator(); + if (!isARCSignificantTerminator(TermInst)) + continue; + PredTerminators.push_back(TermInst); + } + + auto *InsertPt = &*BB.begin(); + for (auto &OtherState : getBottomupStates()) { + // If the other state's value is blotted, skip it. + if (!OtherState.hasValue()) + continue; + + OtherState->second.updateForPredTerminators(PredTerminators, InsertPt, AA); + } +} + bool ARCRegionState::processBlockBottomUp( - SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, - bool FreezeOwnedArgEpilogueReleases, + const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, + LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, ConsumedArgToEpilogueReleaseMatcher &ConsumedArgToReleaseMap, BlotMapVector &IncToDecStateMap) { DEBUG(llvm::dbgs() << ">>>> Bottom Up!\n"); + SILBasicBlock &BB = *R->getBlock(); bool NestingDetected = false; BottomUpDataflowRCStateVisitor DataflowVisitor( @@ -211,6 +278,13 @@ bool ARCRegionState::processBlockBottomUp( } } + // Now visit each one of our predecessor regions and see if any are blocks + // that can use reference counted values. If any of them do, we advance the + // sequence for the pointer and create an insertion point here. This state + // will be propagated into all of our predecessors, allowing us to be + // conservatively correct in all cases. + processBlockBottomUpPredTerminators(R, AA, LRFI); + return NestingDetected; } @@ -224,7 +298,7 @@ static bool getInsertionPtsForLoopRegionExits( llvm::SmallVectorImpl &InsertPts) { assert(R->isLoop() && "Expected a loop region that is representing a loop"); - // Go through all of our non local successors. If any of them can not be + // Go through all of our non local successors. If any of them cannot be // ignored, we bail for simplicity. This means that for now we do not handle // early exits. if (any_of(R->getNonLocalSuccs(), [&](unsigned SuccID) -> bool { @@ -285,10 +359,8 @@ bool ARCRegionState::processBottomUp( if (!R->isBlock()) return processLoopBottomUp(R, AA, LRFI, RegionStateInfo); - return processBlockBottomUp(*R->getBlock(), AA, RCIA, - FreezeOwnedArgEpilogueReleases, - ConsumedArgToReleaseMap, - IncToDecStateMap); + return processBlockBottomUp(R, AA, RCIA, LRFI, FreezeOwnedArgEpilogueReleases, + ConsumedArgToReleaseMap, IncToDecStateMap); } //===--- diff --git a/lib/SILOptimizer/ARC/ARCRegionState.h b/lib/SILOptimizer/ARC/ARCRegionState.h index dfc381f5dbd41..2b4a2b50462f6 100644 --- a/lib/SILOptimizer/ARC/ARCRegionState.h +++ b/lib/SILOptimizer/ARC/ARCRegionState.h @@ -1,8 +1,8 @@ -//===--- ARCRegionState.h -------------------------------------------------===// +//===--- ARCRegionState.h ---------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,7 @@ class ARCRegionState { /// The region that this ARCRegionState summarizes information for. /// /// The only time that the pointer is null is during initialization. Using - /// NullablePtr is just a convient way to make sure that we assert if we + /// NullablePtr is just a convenient way to make sure that we assert if we /// attempt to use Region during initialization before the pointer is set. NullablePtr Region; @@ -192,11 +192,14 @@ class ARCRegionState { llvm::DenseMap &RegionStateInfo); private: + void processBlockBottomUpPredTerminators(const LoopRegion *R, + AliasAnalysis *AA, + LoopRegionFunctionInfo *LRFI); bool processBlockBottomUp( - SILBasicBlock &BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, - bool FreezeOwnedArgEpilogueReleases, - ConsumedArgToEpilogueReleaseMatcher &ConsumedArgToReleaseMap, - BlotMapVector &IncToDecStateMap); + const LoopRegion *R, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA, + LoopRegionFunctionInfo *LRFI, bool FreezeOwnedArgEpilogueReleases, + ConsumedArgToEpilogueReleaseMatcher &ConsumedArgToReleaseMap, + BlotMapVector &IncToDecStateMap); bool processLoopBottomUp( const LoopRegion *R, AliasAnalysis *AA, LoopRegionFunctionInfo *LRFI, llvm::DenseMap &RegionStateInfo); diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index f91bbec55251e..c9f0d1b9f25b3 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,7 +13,6 @@ #define DEBUG_TYPE "arc-sequence-opts" #include "swift/SILOptimizer/PassManager/Passes.h" #include "GlobalARCPairingAnalysis.h" -#include "ProgramTerminationAnalysis.h" #include "swift/Basic/Fallthrough.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" @@ -22,6 +21,7 @@ #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" @@ -55,7 +55,7 @@ static SILInstruction *createIncrement(SILValue Ptr, SILInstruction *InsertPt) { // If Ptr is refcounted itself, create the strong_retain and // return. - if (Ptr.getType().isReferenceCounted(B.getModule())) + if (Ptr->getType().isReferenceCounted(B.getModule())) return B.createStrongRetain(Loc, Ptr); // Otherwise, create the retain_value. @@ -71,7 +71,7 @@ static SILInstruction *createDecrement(SILValue Ptr, SILInstruction *InsertPt) { auto Loc = SILFileLocation(SourceLoc()); // If Ptr has reference semantics itself, create a strong_release. - if (Ptr.getType().isReferenceCounted(B.getModule())) + if (Ptr->getType().isReferenceCounted(B.getModule())) return B.createStrongRelease(Loc, Ptr); // Otherwise create a release value. diff --git a/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.cpp b/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.cpp index fa6183c5c5b17..3e0fe426b0ca2 100644 --- a/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.cpp @@ -1,8 +1,8 @@ -//===-- GlobalARCPairingAnalysis.cpp - Global ARC Retain Release Pairing --===// +//===--- GlobalARCPairingAnalysis.cpp - Global ARC Retain Release Pairing -===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "GlobalARCPairingAnalysis.h" #include "RefCountState.h" #include "GlobalARCSequenceDataflow.h" @@ -140,40 +140,49 @@ ARCMatchingSetBuilder::matchIncrementsToDecrements() { // We need to be known safe over all increments/decrements we are matching up // to ignore insertion points. - Flags.KnownSafe &= (*BURefCountState)->second.isKnownSafe(); + bool BUIsKnownSafe = (*BURefCountState)->second.isKnownSafe(); + DEBUG(llvm::dbgs() << " KNOWNSAFE: " + << (BUIsKnownSafe ? "true" : "false") << "\n"); + Flags.KnownSafe &= BUIsKnownSafe; // We can only move instructions if we know that we are not partial. We can // still delete instructions in such cases though. - Flags.Partial |= (*BURefCountState)->second.isPartial(); + bool BUIsPartial = (*BURefCountState)->second.isPartial(); + DEBUG(llvm::dbgs() << " PARTIAL: " + << (BUIsPartial ? "true" : "false") << "\n"); + Flags.Partial |= BUIsPartial; // Now that we know we have an inst, grab the decrement. for (auto DecIter : (*BURefCountState)->second.getInstructions()) { SILInstruction *Decrement = DecIter; - DEBUG(llvm::dbgs() << " Decrement: " << *Decrement); + DEBUG(llvm::dbgs() << " Decrement: " << *Decrement); // Now grab the increment matched up with the decrement from the bottom up map. // If we can't find it, bail we can't match this increment up with anything. auto TDRefCountState = TDMap.find(Decrement); if (TDRefCountState == TDMap.end()) { - DEBUG(llvm::dbgs() << " FAILURE! Could not find state for " - "decrement.\n"); + DEBUG(llvm::dbgs() << " FAILURE! Could not find state for " + "decrement.\n"); return None; } - DEBUG(llvm::dbgs() << " SUCCESS! Found state for decrement.\n"); + DEBUG(llvm::dbgs() << " SUCCESS! Found state for " + "decrement.\n"); // Make sure the increment we are looking at is also matched to our decrement. // Otherwise bail. if (!(*TDRefCountState)->second.isTrackingRefCountInst() || !(*TDRefCountState)->second.containsInstruction(Increment)) { - DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or " - "found increment that did not match.\n"); + DEBUG( + llvm::dbgs() << " FAILURE! Not tracking instruction or " + "found increment that did not match.\n"); return None; } // Add the decrement to the decrement to move set. If we don't insert // anything, just continue. if (!MatchSet.Decrements.insert(Decrement)) { - DEBUG(llvm::dbgs() << " SKIPPING! Already processed this decrement\n"); + DEBUG(llvm::dbgs() + << " SKIPPING! Already processed this decrement\n"); continue; } @@ -218,34 +227,42 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() { // We need to be known safe over all increments/decrements we are matching up // to ignore insertion points. - Flags.KnownSafe &= (*TDRefCountState)->second.isKnownSafe(); + bool TDIsKnownSafe = (*TDRefCountState)->second.isKnownSafe(); + DEBUG(llvm::dbgs() << " KNOWNSAFE: " + << (TDIsKnownSafe ? "true" : "false") << "\n"); + Flags.KnownSafe &= TDIsKnownSafe; // We can only move instructions if we know that we are not partial. We can // still delete instructions in such cases though. - Flags.Partial |= (*TDRefCountState)->second.isPartial(); + bool TDIsPartial = (*TDRefCountState)->second.isPartial(); + DEBUG(llvm::dbgs() << " PARTIAL: " + << (TDIsPartial ? "true" : "false") << "\n"); + Flags.Partial |= TDIsPartial; // Now that we know we have an inst, grab the decrement. for (auto IncIter : (*TDRefCountState)->second.getInstructions()) { SILInstruction *Increment = IncIter; - DEBUG(llvm::dbgs() << " Increment: " << *Increment); + DEBUG(llvm::dbgs() << " Increment: " << *Increment); // Now grab the increment matched up with the decrement from the bottom up map. // If we can't find it, bail we can't match this increment up with anything. auto BURefCountState = BUMap.find(Increment); if (BURefCountState == BUMap.end()) { - DEBUG(llvm::dbgs() << " FAILURE! Could not find state for " - "increment.\n"); + DEBUG(llvm::dbgs() << " FAILURE! Could not find state for " + "increment.\n"); return None; } - DEBUG(llvm::dbgs() << " SUCCESS! Found state for increment.\n"); + DEBUG( + llvm::dbgs() << " SUCCESS! Found state for increment.\n"); // Make sure the increment we are looking at is also matched to our decrement. // Otherwise bail. if (!(*BURefCountState)->second.isTrackingRefCountInst() || !(*BURefCountState)->second.containsInstruction(Decrement)) { - DEBUG(llvm::dbgs() << " FAILURE! Not tracking instruction or " - "found increment that did not match.\n"); + DEBUG( + llvm::dbgs() << " FAILURE! Not tracking instruction or " + "found increment that did not match.\n"); return None; } @@ -269,7 +286,7 @@ ARCMatchingSetBuilder::matchDecrementsToIncrements() { /// Visit each retain/release that is matched up to our operand over and over /// again until we converge by not adding any more to the set which we can move. -/// If we find a situation that we can not handle, we bail and return false. If +/// If we find a situation that we cannot handle, we bail and return false. If /// we succeed and it is safe to move increment/releases, we return true. bool ARCMatchingSetBuilder::matchUpIncDecSetsForPtr() { bool KnownSafeTD = true; diff --git a/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.h b/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.h index bd10f7cddedb2..aa8b2e05b6a03 100644 --- a/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.h +++ b/lib/SILOptimizer/ARC/GlobalARCPairingAnalysis.h @@ -1,8 +1,8 @@ -//===--- GlobalARCPairingAnalysis.h ---------------------------------------===// +//===--- GlobalARCPairingAnalysis.h -----------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -56,7 +56,7 @@ struct ARCMatchingSet { /// reference counted value could be used. llvm::SetVector DecrementInsertPts; - // This is a data structure that can not be moved or copied. + // This is a data structure that cannot be moved or copied. ARCMatchingSet() = default; ARCMatchingSet(const ARCMatchingSet &) = delete; ARCMatchingSet(ARCMatchingSet &&) = delete; @@ -95,7 +95,7 @@ class CodeMotionOrDeleteCallback { bool madeChange() const { return Changed; } }; -/// A wrapper around the results of the bottomup/topdown dataflow that knows how +/// A wrapper around the results of the bottom-up/top-down dataflow that knows how /// to pair the retains/releases in those results. struct ARCPairingContext { SILFunction &F; diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp index 8e5bc3d39eb7a..4fe198f91befb 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "GlobalARCSequenceDataflow.h" #include "ARCBBState.h" #include "RCStateTransitionVisitors.h" @@ -149,7 +149,7 @@ void ARCSequenceDataflowEvaluator::mergePredecessors( ARCBBState &PredBBState = PredDataHandle->getState(); // If we found the state but the state is for a trap BB, skip it. Trap BBs - // leak all reference counts and do not reference reference semantic objects + // leak all reference counts and do not reference semantic objects // in any manner. // // TODO: I think this is a copy paste error, since we a trap BB should have @@ -198,6 +198,34 @@ bool ARCSequenceDataflowEvaluator::processTopDown() { // Bottom Up Dataflow //===----------------------------------------------------------------------===// +// This is temporary code duplication. This will be removed when Loop ARC is +// finished and Block ARC is removed. +static bool isARCSignificantTerminator(TermInst *TI) { + switch (TI->getTermKind()) { + case TermKind::UnreachableInst: + // br is a forwarding use for its arguments. It cannot in of itself extend + // the lifetime of an object (just like a phi-node) cannot. + case TermKind::BranchInst: + // A cond_br is a forwarding use for its non-operand arguments in a similar + // way to br. Its operand must be an i1 that has a different lifetime from any + // ref counted object. + case TermKind::CondBranchInst: + return false; + // Be conservative for now. These actually perform some sort of operation + // against the operand or can use the value in some way. + case TermKind::ThrowInst: + case TermKind::ReturnInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + } +} + /// Analyze a single BB for refcount inc/dec instructions. /// /// If anything was found it will be added to DecToIncStateMap. @@ -209,9 +237,9 @@ bool ARCSequenceDataflowEvaluator::processTopDown() { /// pointer in a function that implies that the pointer is alive up to that /// point. We "freeze" (i.e. do not attempt to remove or move) such releases if /// FreezeOwnedArgEpilogueReleases is set. This is useful since in certain cases -/// due to dataflow issues, we can not properly propagate the last use +/// due to dataflow issues, we cannot properly propagate the last use /// information. Instead we run an extra iteration of the ARC optimizer with -/// this enabled in a side table so the information gets propgated everywhere in +/// this enabled in a side table so the information gets propagated everywhere in /// the CFG. bool ARCSequenceDataflowEvaluator::processBBBottomUp( ARCBBState &BBState, bool FreezeOwnedArgEpilogueReleases) { @@ -266,6 +294,31 @@ bool ARCSequenceDataflowEvaluator::processBBBottomUp( } } + // This is ignoring the possibility that we may have a loop with an + // interesting terminator but for which, we are going to clear all state + // (since it is a loop boundary). We may in such a case, be too conservative + // with our other predecessors. Luckily this cannot happen since cond_br is + // the only terminator that allows for critical edges and all other + // "interesting terminators" always having multiple successors. This means + // that this block could not have multiple predecessors since otherwise, the + // edge would be broken. + llvm::TinyPtrVector PredTerminators; + for (SILBasicBlock *PredBB : BB.getPreds()) { + auto *TermInst = PredBB->getTerminator(); + if (!isARCSignificantTerminator(TermInst)) + continue; + PredTerminators.push_back(TermInst); + } + + auto *InsertPt = &*BB.begin(); + for (auto &OtherState : BBState.getBottomupStates()) { + // If the other state's value is blotted, skip it. + if (!OtherState.hasValue()) + continue; + + OtherState->second.updateForPredTerminators(PredTerminators, InsertPt, AA); + } + return NestingDetected; } diff --git a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h index 00f12053bda96..4f5b784263ec1 100644 --- a/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalARCSequenceDataflow.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,7 +15,7 @@ #include "RefCountState.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "ProgramTerminationAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" #include "swift/Basic/BlotMapVector.h" #include "swift/Basic/NullablePtr.h" #include "llvm/ADT/MapVector.h" diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp index 11f458d672914..101e1eb93a9da 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "GlobalLoopARCSequenceDataflow.h" #include "ARCRegionState.h" #include "RCStateTransitionVisitors.h" @@ -171,7 +171,7 @@ void LoopARCSequenceDataflowEvaluator::mergeSuccessors(const LoopRegion *Region, } // Otherwise, we treat it as unknown control flow. - DEBUG(llvm::dbgs() << " Cleaing state b/c of early exit\n"); + DEBUG(llvm::dbgs() << " Clearing state b/c of early exit\n"); State.clear(); break; } @@ -188,9 +188,9 @@ void LoopARCSequenceDataflowEvaluator::mergeSuccessors(const LoopRegion *Region, /// pointer in a function that implies that the pointer is alive up to that /// point. We "freeze" (i.e. do not attempt to remove or move) such releases if /// FreezeOwnedArgEpilogueReleases is set. This is useful since in certain cases -/// due to dataflow issues, we can not properly propagate the last use +/// due to dataflow issues, we cannot properly propagate the last use /// information. Instead we run an extra iteration of the ARC optimizer with -/// this enabled in a side table so the information gets propgated everywhere in +/// this enabled in a side table so the information gets propagated everywhere in /// the CFG. bool LoopARCSequenceDataflowEvaluator::processLoopBottomUp( const LoopRegion *R, bool FreezeOwnedArgEpilogueReleases) { diff --git a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h index 9ddb2008fdc2e..bbe1925fdb857 100644 --- a/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h +++ b/lib/SILOptimizer/ARC/GlobalLoopARCSequenceDataflow.h @@ -1,8 +1,8 @@ -//===--- GlobalLoopARCSequenceDataflow.h ----------------------------------===// +//===--- GlobalLoopARCSequenceDataflow.h ------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,8 +14,8 @@ #define SWIFT_SILOPTIMIZER_PASSMANAGER_ARC_GLOBALLOOPARCSEQUENCEDATAFLOW_H #include "RefCountState.h" -#include "ProgramTerminationAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" #include "swift/Basic/BlotMapVector.h" #include "swift/Basic/NullablePtr.h" #include "llvm/ADT/MapVector.h" diff --git a/lib/SILOptimizer/ARC/RCStateTransition.cpp b/lib/SILOptimizer/ARC/RCStateTransition.cpp index 9a593cec1708f..96ab4ed67cde2 100644 --- a/lib/SILOptimizer/ARC/RCStateTransition.cpp +++ b/lib/SILOptimizer/ARC/RCStateTransition.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "RCStateTransition.h" #include "swift/Basic/Fallthrough.h" diff --git a/lib/SILOptimizer/ARC/RCStateTransition.def b/lib/SILOptimizer/ARC/RCStateTransition.def index 6124c2376dbb4..7e1d01faf10c6 100644 --- a/lib/SILOptimizer/ARC/RCStateTransition.def +++ b/lib/SILOptimizer/ARC/RCStateTransition.def @@ -1,8 +1,8 @@ -//===--- RCStateTransition.def -------------------------------*- C++ -*----===// +//===--- RCStateTransition.def ----------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/ARC/RCStateTransition.h b/lib/SILOptimizer/ARC/RCStateTransition.h index 8fe74d353264e..eb7f37ef20170 100644 --- a/lib/SILOptimizer/ARC/RCStateTransition.h +++ b/lib/SILOptimizer/ARC/RCStateTransition.h @@ -1,8 +1,8 @@ -//===--- RCStateTransition.h -------------------------------*- C++ -*------===// +//===--- RCStateTransition.h ------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp index 548cea57e12af..5a6b090e56dd8 100644 --- a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp +++ b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "RCStateTransitionVisitors.h" #include "ARCBBState.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" @@ -276,10 +276,9 @@ typename TopDownDataflowRCStateVisitor::DataflowResult TopDownDataflowRCStateVisitor:: visitStrongAllocBox(AllocBoxInst *ABI) { // Alloc box introduces a ref count of +1 on its container. - SILValue Container = ABI->getContainerResult(); - auto &State = DataflowState.getTopDownRefCountState(Container); - State.initWithEntranceInst(ABI, Container); - return DataflowResult(Container); + auto &State = DataflowState.getTopDownRefCountState(ABI); + State.initWithEntranceInst(ABI, ABI); + return DataflowResult(ABI); } template diff --git a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h index ac4cb390a0250..d979777ae4b2f 100644 --- a/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h +++ b/lib/SILOptimizer/ARC/RCStateTransitionVisitors.h @@ -1,8 +1,8 @@ -//===--- RCStateTransitionVisitors.h -------------------------*- C++ -*----===// +//===--- RCStateTransitionVisitors.h ----------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index 068c0d78eaee7..f385f64925dff 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-global-arc-opts" +#define DEBUG_TYPE "arc-sequence-opts" #include "RefCountState.h" #include "RCStateTransition.h" #include "llvm/Support/Debug.h" @@ -117,7 +117,7 @@ bool BottomUpRefCountState::mightRemoveMutators() { /// Uninitialize the current state. void BottomUpRefCountState::clear() { - // If we can not conservatively prove that the given RefCountState will not + // If we cannot conservatively prove that the given RefCountState will not // be removed, be conservative and clear the transition state, so we do not // propagate KnownSafety forward. if (mightRemoveMutators()) @@ -154,8 +154,7 @@ bool BottomUpRefCountState::valueCanBeDecrementedGivenLatticeState() const { /// If advance the state's sequence appropriately for a decrement. If we do /// advance return true. Otherwise return false. -bool BottomUpRefCountState:: -handleDecrement(SILInstruction *PotentialDecrement) { +bool BottomUpRefCountState::handleDecrement() { switch (LatState) { case LatticeState::MightBeUsed: LatState = LatticeState::MightBeDecremented; @@ -182,19 +181,11 @@ bool BottomUpRefCountState::valueCanBeUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. -bool BottomUpRefCountState::handleUser(SILInstruction *PotentialUser, - ArrayRef NewInsertPts, +bool BottomUpRefCountState::handleUser(ArrayRef NewInsertPts, SILValue RCIdentity, AliasAnalysis *AA) { assert(valueCanBeUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); - // Instructions that we do not recognize (and thus will not move) and that - // *must* use RCIdentity, implies we are always known safe as long as meet - // over all path constraints are satisfied. - if (isRCStateTransitionUnknown(PotentialUser)) - if (mustUseValue(PotentialUser, RCIdentity, AA)) - FoundNonARCUser = true; - // Advance the sequence... switch (LatState) { case LatticeState::Decremented: @@ -227,19 +218,11 @@ valueCanBeGuaranteedUsedGivenLatticeState() const { /// Given the current lattice state, if we have seen a use, advance the /// lattice state. Return true if we do so and false otherwise. bool BottomUpRefCountState::handleGuaranteedUser( - SILInstruction *PotentialGuaranteedUser, ArrayRef NewInsertPts, SILValue RCIdentity, AliasAnalysis *AA) { assert(valueCanBeGuaranteedUsedGivenLatticeState() && "Must be able to be used at this point of the lattice."); - // Instructions that we do not recognize (and thus will not move) and that - // *must* use RCIdentity, implies we are always known safe as long as meet - // over all path constraints are satisfied. - if (isRCStateTransitionUnknown(PotentialGuaranteedUser)) - if (mustUseValue(PotentialGuaranteedUser, RCIdentity, AA)) - FoundNonARCUser = true; - // Advance the sequence... switch (LatState) { // If were decremented, insert the insertion point. @@ -368,14 +351,20 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser( if (!valueCanBeGuaranteedUsedGivenLatticeState()) return false; - // If we can prove that Other can not use the pointer we are tracking, + // If we can prove that Other cannot use the pointer we are tracking, // return... if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; + // Instructions that we do not recognize (and thus will not move) and that + // *must* use RCIdentity, implies we are always known safe as long as meet + // over all path constraints are satisfied. + if (isRCStateTransitionUnknown(PotentialGuaranteedUser)) + if (mustUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) + FoundNonARCUser = true; + // Otherwise, update the ref count state given the guaranteed user. - return handleGuaranteedUser(PotentialGuaranteedUser, InsertPt, getRCRoot(), - AA); + return handleGuaranteedUser(InsertPt, getRCRoot(), AA); } /// Check if PotentialDecrement can decrement the reference count associated @@ -395,14 +384,14 @@ bool BottomUpRefCountState::handlePotentialDecrement( if (!valueCanBeDecrementedGivenLatticeState()) return false; - // If we can prove that Other can not use the pointer we are tracking, + // If we can prove that Other cannot use the pointer we are tracking, // return... if (!mayDecrementRefCount(PotentialDecrement, getRCRoot(), AA)) return false; // Otherwise, allow the CRTP substruct to update itself given we have a // potential decrement. - return handleDecrement(PotentialDecrement); + return handleDecrement(); } // Check if PotentialUser could be a use of the reference counted value that @@ -427,7 +416,14 @@ bool BottomUpRefCountState::handlePotentialUser( if (!mayUseValue(PotentialUser, getRCRoot(), AA)) return false; - return handleUser(PotentialUser, InsertPts, getRCRoot(), AA); + // Instructions that we do not recognize (and thus will not move) and that + // *must* use RCIdentity, implies we are always known safe as long as meet + // over all path constraints are satisfied. + if (isRCStateTransitionUnknown(PotentialUser)) + if (mustUseValue(PotentialUser, getRCRoot(), AA)) + FoundNonARCUser = true; + + return handleUser(InsertPts, getRCRoot(), AA); } void BottomUpRefCountState::updateForSameLoopInst(SILInstruction *I, @@ -475,7 +471,7 @@ void BottomUpRefCountState::updateForDifferentLoopInst( mayDecrementRefCount(I, getRCRoot(), AA)) { DEBUG(llvm::dbgs() << " Found potential guaranteed use:\n " << getRCRoot()); - handleGuaranteedUser(I, InsertPts, getRCRoot(), AA); + handleGuaranteedUser(InsertPts, getRCRoot(), AA); return; } } @@ -488,6 +484,40 @@ void BottomUpRefCountState::updateForDifferentLoopInst( DEBUG(llvm::dbgs() << " Found Potential Use:\n " << getRCRoot()); } +void BottomUpRefCountState::updateForPredTerminators( + ArrayRef Terms, SILInstruction *InsertPt, + AliasAnalysis *AA) { + // If this state is not tracking anything, there is nothing to update. + if (!isTrackingRefCount()) + return; + + if (valueCanBeGuaranteedUsedGivenLatticeState() && + std::any_of(Terms.begin(), Terms.end(), + [this, &AA](SILInstruction *I) -> bool { + return mayGuaranteedUseValue(I, getRCRoot(), AA); + })) { + handleGuaranteedUser(InsertPt, getRCRoot(), AA); + return; + } + + if (valueCanBeDecrementedGivenLatticeState() && + std::any_of(Terms.begin(), Terms.end(), + [this, &AA](SILInstruction *I) -> bool { + return mayDecrementRefCount(I, getRCRoot(), AA); + })) { + handleDecrement(); + return; + } + + if (!valueCanBeUsedGivenLatticeState() || + std::none_of(Terms.begin(), Terms.end(), + [this, &AA](SILInstruction *I) + -> bool { return mayUseValue(I, getRCRoot(), AA); })) + return; + + handleUser(InsertPt, getRCRoot(), AA); +} + //===----------------------------------------------------------------------===// // Top Down Ref Count State //===----------------------------------------------------------------------===// @@ -765,7 +795,7 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser( if (!valueCanBeGuaranteedUsedGivenLatticeState()) return false; - // If we can prove that Other can not use the pointer we are tracking, + // If we can prove that Other cannot use the pointer we are tracking, // return... if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; @@ -793,7 +823,7 @@ bool TopDownRefCountState::handlePotentialDecrement( if (!valueCanBeDecrementedGivenLatticeState()) return false; - // If we can prove that Other can not use the pointer we are tracking, + // If we can prove that Other cannot use the pointer we are tracking, // return... if (!mayDecrementRefCount(PotentialDecrement, getRCRoot(), AA)) return false; diff --git a/lib/SILOptimizer/ARC/RefCountState.h b/lib/SILOptimizer/ARC/RefCountState.h index 7a6839c92c427..abdea90a13ee8 100644 --- a/lib/SILOptimizer/ARC/RefCountState.h +++ b/lib/SILOptimizer/ARC/RefCountState.h @@ -1,8 +1,8 @@ -//===--- RefCountState.h - Represents a Reference Count -----*- C++ -*-----===// +//===--- RefCountState.h - Represents a Reference Count ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,6 +18,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include @@ -57,7 +58,7 @@ class RefCountState { /// semantics. InstructionSet InsertPts; - /// Have we performed any partial merges of insertion points? We can not + /// Have we performed any partial merges of insertion points? We cannot /// perform two partial merges in a row unless we are able to reason about /// control dependency (which avoid for now). bool Partial = false; @@ -83,7 +84,7 @@ class RefCountState { KnownSafe = false; // Initialize value. - RCRoot = I->getOperand(0).stripCasts(); + RCRoot = stripCasts(I->getOperand(0)); // Clear our insertion point list. InsertPts.clear(); @@ -135,7 +136,7 @@ class RefCountState { /// Returns true if we have a valid value that we are tracking. bool hasRCRoot() const { - return RCRoot.isValid(); + return (bool)RCRoot; } /// The latest point we can move the increment without bypassing instructions @@ -176,7 +177,7 @@ class BottomUpRefCountState : public RefCountState { MightBeUsed, ///< The pointer will be used and then at this point /// be decremented MightBeDecremented, ///< The pointer might be decremented again implying - /// that we can not, without being known safe remove + /// that we cannot, without being known safe remove /// this decrement. }; @@ -219,6 +220,11 @@ class BottomUpRefCountState : public RefCountState { ArrayRef InsertPts, AliasAnalysis *AA); + // Determine the conservative effect of the given list of predecessor + // terminators upon this reference count. + void updateForPredTerminators(ArrayRef PredTerms, + SILInstruction *InsertPt, AliasAnalysis *AA); + /// Attempt to merge \p Other into this ref count state. Return true if we /// succeed and false otherwise. bool merge(const BottomUpRefCountState &Other); @@ -246,7 +252,7 @@ class BottomUpRefCountState : public RefCountState { /// If advance the state's sequence appropriately for a decrement. If we do /// advance return true. Otherwise return false. - bool handleDecrement(SILInstruction *PotentialDecrement); + bool handleDecrement(); /// Check if PotentialDecrement can decrement the reference count associated /// with the value we are tracking. If so advance the state's sequence @@ -261,8 +267,7 @@ class BottomUpRefCountState : public RefCountState { /// lattice state. Return true if we do so and false otherwise. \p InsertPt is /// the location where if \p PotentialUser is a user of this ref count, we /// would insert a release. - bool handleUser(SILInstruction *PotentialUser, - ArrayRef InsertPt, SILValue RCIdentity, + bool handleUser(ArrayRef InsertPt, SILValue RCIdentity, AliasAnalysis *AA); /// Check if PotentialUser could be a use of the reference counted value that @@ -280,8 +285,7 @@ class BottomUpRefCountState : public RefCountState { /// lattice state. Return true if we do so and false otherwise. \p InsertPt is /// the location where if \p PotentialUser is a user of this ref count, we /// would insert a release. - bool handleGuaranteedUser(SILInstruction *PotentialGuaranteedUser, - ArrayRef InsertPts, + bool handleGuaranteedUser(ArrayRef InsertPts, SILValue RCIdentity, AliasAnalysis *AA); /// Check if PotentialGuaranteedUser can use the reference count associated diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp index ca9d621ffa613..42db112b03fb2 100644 --- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp @@ -1,8 +1,8 @@ -//===-------------- ARCAnalysis.cpp - SIL ARC Analysis --------------------===// +//===--- ARCAnalysis.cpp - SIL ARC Analysis -------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,65 +28,6 @@ using namespace swift; // Decrement Analysis //===----------------------------------------------------------------------===// -static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) { - return llvm::StringSwitch(FRI->getReferencedFunction()->getName()) - .Case("swift_keepAlive", true) - .Default(false); -} - -static bool canApplyDecrementRefCount(OperandValueArrayRef Ops, SILValue Ptr, - AliasAnalysis *AA) { - // Ok, this apply *MAY* decrement ref counts. Now our strategy is to attempt - // to use properties of the pointer, the function's arguments, and the - // function itself to prove that the pointer cannot have its ref count - // affected by the applied function. - - // TODO: Put in function property check section here when we get access to - // such information. - - // First make sure that the underlying object of ptr is a local object which - // does not escape. This prevents the apply from indirectly via the global - // affecting the reference count of the pointer. - if (!isNonEscapingLocalObject(getUnderlyingObject(Ptr))) - return true; - - // Now that we know that the function can not affect the pointer indirectly, - // make sure that the apply can not affect the pointer directly via the - // applies arguments by proving that the pointer can not alias any of the - // functions arguments. - for (auto Op : Ops) { - for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) { - if (!AA->isNoAlias(Op, SILValue(Ptr.getDef(), i))) - return true; - } - } - - // Success! The apply inst can not affect the reference count of ptr! - return false; -} - -static bool canApplyDecrementRefCount(ApplyInst *AI, SILValue Ptr, - AliasAnalysis *AA) { - // Ignore any thick functions for now due to us not handling the ref-counted - // nature of its context. - if (auto FTy = AI->getCallee().getType().getAs()) - if (FTy->getExtInfo().hasContext()) - return true; - - // Treat applications of @noreturn functions as decrementing ref counts. This - // causes the apply to become a sink barrier for ref count increments. - if (AI->getCallee().getType().getAs()->isNoReturn()) - return true; - - // swift_keepAlive can not retain values. Remove this when we get rid of that. - if (auto *FRI = dyn_cast(AI->getCallee())) - if (isKnownToNotDecrementRefCount(FRI)) - return false; - - return canApplyDecrementRefCount(AI->getArgumentsWithoutIndirectResult(), - Ptr, AA); -} - bool swift::mayDecrementRefCount(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) { // First do a basic check, mainly based on the type of instruction. @@ -97,11 +38,13 @@ bool swift::mayDecrementRefCount(SILInstruction *User, // Ok, this instruction may have ref counts. If it is an apply, attempt to // prove that the callee is unable to affect Ptr. if (auto *AI = dyn_cast(User)) - return canApplyDecrementRefCount(AI, Ptr, AA); + return AA->canApplyDecrementRefCount(AI, Ptr); + if (auto *TAI = dyn_cast(User)) + return AA->canApplyDecrementRefCount(TAI, Ptr); if (auto *BI = dyn_cast(User)) - return canApplyDecrementRefCount(BI->getArguments(), Ptr, AA); + return AA->canBuiltinDecrementRefCount(BI, Ptr); - // We can not conservatively prove that this instruction can not decrement the + // We cannot conservatively prove that this instruction cannot decrement the // ref count of Ptr. So assume that it does. return true; } @@ -114,10 +57,10 @@ bool swift::mayCheckRefCount(SILInstruction *User) { // Use Analysis //===----------------------------------------------------------------------===// -/// Returns true if a builtin apply can not use reference counted values. +/// Returns true if a builtin apply cannot use reference counted values. /// /// The main case that this handles here are builtins that via read none imply -/// that they can not read globals and at the same time do not take any +/// that they cannot read globals and at the same time do not take any /// non-trivial types via the arguments. The reason why we care about taking /// non-trivial types as arguments is that we want to be careful in the face of /// intrinsics that may be equivalent to bitcast and inttoptr operations. @@ -128,7 +71,7 @@ static bool canApplyOfBuiltinUseNonTrivialValues(BuiltinInst *BInst) { if (II.ID != llvm::Intrinsic::not_intrinsic) { if (II.hasAttribute(llvm::Attribute::ReadNone)) { for (auto &Op : BInst->getAllOperands()) { - if (!Op.get().getType().isTrivial(Mod)) { + if (!Op.get()->getType().isTrivial(Mod)) { return false; } } @@ -140,7 +83,7 @@ static bool canApplyOfBuiltinUseNonTrivialValues(BuiltinInst *BInst) { auto &BI = BInst->getBuiltinInfo(); if (BI.isReadNone()) { for (auto &Op : BInst->getAllOperands()) { - if (!Op.get().getType().isTrivial(Mod)) { + if (!Op.get()->getType().isTrivial(Mod)) { return false; } } @@ -165,8 +108,7 @@ bool swift::canNeverUseValues(SILInstruction *Inst) { case ValueKind::WitnessMethodInst: return true; - // DeallocStackInst do not use reference counted values, only local storage - // handles. + // DeallocStackInst do not use reference counted values. case ValueKind::DeallocStackInst: return true; @@ -205,7 +147,7 @@ bool swift::canNeverUseValues(SILInstruction *Inst) { // safe. case ValueKind::UncheckedTrivialBitCastInst: { SILValue Op = cast(Inst)->getOperand(); - return Op.getType().isTrivial(Inst->getModule()); + return Op->getType().isTrivial(Inst->getModule()); } // Typed GEPs do not use pointers. The user of the typed GEP may but we will @@ -238,7 +180,11 @@ bool swift::canNeverUseValues(SILInstruction *Inst) { // Certain builtin function refs we know can never use non-trivial values. return canApplyOfBuiltinUseNonTrivialValues(BI); } - + // We do not care about branch inst, since if the branch inst's argument is + // dead, LLVM will clean it up. + case ValueKind::BranchInst: + case ValueKind::CondBranchInst: + return true; default: return false; } @@ -294,23 +240,19 @@ bool swift::mayUseValue(SILInstruction *User, SILValue Ptr, // the object then return true. // Notice that we need to check all of the values of the object. if (isa(User)) { - for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) { - if (AA->mayWriteToMemory(User, SILValue(Ptr.getDef(), i))) - return true; - } + if (AA->mayWriteToMemory(User, Ptr)) + return true; return false; } if (isa(User) ) { - for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) { - if (AA->mayReadFromMemory(User, SILValue(Ptr.getDef(), i))) - return true; - } + if (AA->mayReadFromMemory(User, Ptr)) + return true; return false; } // If we have a terminator instruction, see if it can use ptr. This currently - // means that we first show that TI can not indirectly use Ptr and then use + // means that we first show that TI cannot indirectly use Ptr and then use // alias analysis on the arguments. if (auto *TI = dyn_cast(User)) return canTerminatorUseValue(TI, Ptr, AA); @@ -397,7 +339,7 @@ valueHasARCUsesInInstructionRange(SILValue Op, ++Start; } - // If all such instructions can not use Op, return false. + // If all such instructions cannot use Op, return false. return None; } @@ -428,7 +370,7 @@ swift::valueHasARCUsesInReverseInstructionRange(SILValue Op, --End; } - // If all such instructions can not use Op, return false. + // If all such instructions cannot use Op, return false. return None; } @@ -460,7 +402,7 @@ valueHasARCDecrementOrCheckInInstructionRange(SILValue Op, ++Start; } - // If all such instructions can not decrement Op, return nothing. + // If all such instructions cannot decrement Op, return nothing. return None; } @@ -481,7 +423,7 @@ mayGuaranteedUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) { // Ok, we have an apply site with arguments. Look at the function type and // iterate through the function parameters. If any of the parameters are - // guaranteed, attempt to prove that the passed in parameter can not alias + // guaranteed, attempt to prove that the passed in parameter cannot alias // Ptr. If we fail, return true. CanSILFunctionType FType = FAS.getSubstCalleeType(); auto Params = FType->getParameters(); @@ -489,9 +431,8 @@ mayGuaranteedUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) { if (!Params[i].isGuaranteed()) continue; SILValue Op = FAS.getArgument(i); - for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) - if (!AA->isNoAlias(Op, SILValue(Ptr.getDef(), i))) - return true; + if (!AA->isNoAlias(Op, Ptr)) + return true; } // Ok, we were able to prove that all arguments to the apply that were @@ -542,7 +483,7 @@ void ConsumedArgToEpilogueReleaseMatcher::findMatchingReleases( II != IE; ++II) { // If we do not have a release_value or strong_release... if (!isa(*II) && !isa(*II)) { - // And the object can not use values in a manner that will keep the object + // And the object cannot use values in a manner that will keep the object // alive, continue. We may be able to find additional releases. if (canNeverUseValues(&*II)) continue; @@ -620,7 +561,7 @@ static bool addLastUse(SILValue V, SILBasicBlock *BB, ReleaseTracker &Tracker) { for (auto I = BB->rbegin(); I != BB->rend(); ++I) { for (auto &Op : I->getAllOperands()) - if (Op.get().getDef() == V.getDef()) { + if (Op.get() == V) { Tracker.trackLastRelease(&*I); return true; } @@ -647,7 +588,7 @@ bool swift::getFinalReleasesForValue(SILValue V, ReleaseTracker &Tracker) { // We'll treat this like a liveness problem where the value is the def. Each // block that has a use of the value has the value live-in unless it is the // block with the value. - for (auto *UI : V.getUses()) { + for (auto *UI : V->getUses()) { auto *User = UI->getUser(); auto *BB = User->getParent(); @@ -695,19 +636,15 @@ bool swift::getFinalReleasesForValue(SILValue V, ReleaseTracker &Tracker) { // Leaking BB Analysis //===----------------------------------------------------------------------===// -static bool ignoreableApplyInstInUnreachableBlock(const ApplyInst *AI) { - const char *fatalName = "_TFs18_fatalErrorMessageFTVs12StaticStringS_S_Su_T_"; +static bool ignorableApplyInstInUnreachableBlock(const ApplyInst *AI) { const auto *Fn = AI->getCalleeFunction(); - - // We use endswith here since if we specialize fatal error we will always - // prepend the specialization records to fatalName. - if (!Fn || !Fn->getName().endswith(fatalName)) + if (!Fn) return false; - return true; + return Fn->hasSemanticsAttr("arc.programtermination_point"); } -static bool ignoreableBuiltinInstInUnreachableBlock(const BuiltinInst *BI) { +static bool ignorableBuiltinInstInUnreachableBlock(const BuiltinInst *BI) { const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID == BuiltinValueKind::CondUnreachable) return true; @@ -744,7 +681,7 @@ bool swift::isARCInertTrapBB(const SILBasicBlock *BB) { // Check for apply insts that we can ignore. if (auto *AI = dyn_cast(&*II)) { - if (ignoreableApplyInstInUnreachableBlock(AI)) { + if (ignorableApplyInstInUnreachableBlock(AI)) { ++II; continue; } @@ -752,7 +689,7 @@ bool swift::isARCInertTrapBB(const SILBasicBlock *BB) { // Check for builtins that we can ignore. if (auto *BI = dyn_cast(&*II)) { - if (ignoreableBuiltinInstInUnreachableBlock(BI)) { + if (ignorableBuiltinInstInUnreachableBlock(BI)) { ++II; continue; } diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index 243306f96d7f7..f75bb8e2eb126 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -1,8 +1,8 @@ -//===-------------- AliasAnalysis.cpp - SIL Alias Analysis ----------------===// +//===--- AliasAnalysis.cpp - SIL Alias Analysis ---------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,6 +14,7 @@ #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/PassManager/PassManager.h" #include "swift/SIL/Projection.h" @@ -22,6 +23,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/InstructionUtils.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -111,25 +113,19 @@ static bool isFunctionArgument(SILValue V) { return Arg->isFunctionArg(); } -/// A no alias argument is an argument that is an address type of the entry -/// basic block of a function. -static bool isNoAliasArgument(SILValue V) { - return isFunctionArgument(V) && V.getType().isAddress(); -} - /// Return true if V is an object that at compile time can be uniquely /// identified. static bool isIdentifiableObject(SILValue V) { if (isa(V) || isa(V)) return true; - if (isNoAliasArgument(V)) + if (isNotAliasingArgument(V)) return true; return false; } /// Return true if V1 and V2 are distinct objects that can be uniquely /// identified at compile time. -static bool areDistinctIdentifyableObjects(SILValue V1, SILValue V2) { +static bool areDistinctIdentifiableObjects(SILValue V1, SILValue V2) { // Do both values refer to the same global variable? if (auto *GA1 = dyn_cast(V1)) { if (auto *GA2 = dyn_cast(V2)) { @@ -155,7 +151,7 @@ static bool isSameValueOrGlobal(SILValue V1, SILValue V2) { return false; } -/// Is this a literal which we know can not refer to a global object? +/// Is this a literal which we know cannot refer to a global object? /// /// FIXME: function_ref? static bool isLocalLiteral(SILValue V) { @@ -172,65 +168,25 @@ static bool isLocalLiteral(SILValue V) { /// Is this a value that can be unambiguously identified as being defined at the /// function level. static bool isIdentifiedFunctionLocal(SILValue V) { - return isa(*V) || isNoAliasArgument(V) || isLocalLiteral(V); -} - -/// Returns true if V is a function argument that is not an address implying -/// that we do not have the guarantee that it will not alias anything inside the -/// function. -static bool isAliasingFunctionArgument(SILValue V) { - return isFunctionArgument(V) && !V.getType().isAddress(); -} - -/// Returns true if V is an apply inst that may read or write to memory. -static bool isReadWriteApplyInst(SILValue V) { - // See if this is a normal function application. - if (auto *AI = dyn_cast(V)) { - return AI->mayReadOrWriteMemory(); - } - - // Next, see if this is a builtin. - if (auto *BI = dyn_cast(V)) { - return BI->mayReadOrWriteMemory(); - } - - // If we fail, bail... - return false; -} - -/// Return true if the pointer is one which would have been considered an escape -/// by isNonEscapingLocalObject. -static bool isEscapeSource(SILValue V) { - if (isReadWriteApplyInst(V)) - return true; - - if (isAliasingFunctionArgument(V)) - return true; - - // The LoadInst case works since valueMayBeCaptured always assumes stores are - // escapes. - if (isa(*V)) - return true; - - // We could not prove anything, be conservative and return false. - return false; + return isa(*V) || isNotAliasingArgument(V) || + isLocalLiteral(V); } /// Returns true if we can prove that the two input SILValues which do not equal -/// can not alias. +/// cannot alias. static bool aliasUnequalObjects(SILValue O1, SILValue O2) { assert(O1 != O2 && "This function should only be called on unequal values."); // If O1 and O2 do not equal and they are both values that can be statically - // and uniquely identified, they can not alias. - if (areDistinctIdentifyableObjects(O1, O2)) { + // and uniquely identified, they cannot alias. + if (areDistinctIdentifiableObjects(O1, O2)) { DEBUG(llvm::dbgs() << " Found two unequal identified " "objects.\n"); return true; } // Function arguments can't alias with things that are known to be - // unambigously identified at the function level. + // unambiguously identified at the function level. // // Note that both function arguments must be identified. For example, an @in // argument may be an interior pointer into a box that is passed separately as @@ -243,16 +199,6 @@ static bool aliasUnequalObjects(SILValue O1, SILValue O2) { return true; } - // If one pointer is the result of an apply or load and the other is a - // non-escaping local object within the same function, then we know the object - // couldn't escape to a point where the call could return it. - if ((isEscapeSource(O1) && isNonEscapingLocalObject(O2)) || - (isEscapeSource(O2) && isNonEscapingLocalObject(O1))) { - DEBUG(llvm::dbgs() << " Found unequal escape source and non " - "escaping local object!\n"); - return true; - } - // We failed to prove that the two objects are different. return false; } @@ -270,20 +216,20 @@ AliasResult AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2, // If V2 is also a gep instruction with a must-alias or not-aliasing base // pointer, figure out if the indices of the GEPs tell us anything about the // derived pointers. - if (!Projection::isAddrProjection(V2)) { + if (!NewProjection::isAddressProjection(V2)) { // Ok, V2 is not an address projection. See if V2 after stripping casts // aliases O1. If so, then we know that V2 must partially alias V1 via a // must alias relation on O1. This ensures that given an alloc_stack and a // gep from that alloc_stack, we say that they partially alias. - if (isSameValueOrGlobal(O1, V2.stripCasts())) + if (isSameValueOrGlobal(O1, stripCasts(V2))) return AliasResult::PartialAlias; return AliasResult::MayAlias; } - assert(!Projection::isAddrProjection(O1) && + assert(!NewProjection::isAddressProjection(O1) && "underlying object may not be a projection"); - assert(!Projection::isAddrProjection(O2) && + assert(!NewProjection::isAddressProjection(O2) && "underlying object may not be a projection"); // Do the base pointers alias? @@ -295,8 +241,8 @@ AliasResult AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2, return AliasResult::NoAlias; // Let's do alias checking based on projections. - auto V1Path = ProjectionPath::getAddrProjectionPath(O1, V1, true); - auto V2Path = ProjectionPath::getAddrProjectionPath(O2, V2, true); + auto V1Path = NewProjectionPath::getProjectionPath(O1, V1); + auto V2Path = NewProjectionPath::getProjectionPath(O2, V2); // getUnderlyingPath and findAddressProjectionPathBetweenValues disagree on // what the base pointer of the two values are. Be conservative and return @@ -328,7 +274,7 @@ AliasResult AliasAnalysis::aliasAddressProjection(SILValue V1, SILValue V2, return AliasResult::NoAlias; // If one of the GEPs is a super path of the other then they partially - // alias. W + // alias. if (BaseAlias == AliasResult::MustAlias && isStrictSubSeqRelation(R)) return AliasResult::PartialAlias; @@ -354,6 +300,7 @@ static bool isTypedAccessOracle(SILInstruction *I) { case ValueKind::StoreInst: case ValueKind::AllocStackInst: case ValueKind::AllocBoxInst: + case ValueKind::ProjectBoxInst: case ValueKind::DeallocStackInst: case ValueKind::DeallocBoxInst: return true; @@ -397,13 +344,13 @@ static SILType findTypedAccessType(SILValue V) { // typed oracle. if (auto *I = dyn_cast(V)) if (isTypedAccessOracle(I)) - return V.getType(); + return V->getType(); // Then look at any uses of V that potentially could act as a typed access // oracle. - for (auto Use : V.getUses()) + for (auto Use : V->getUses()) if (isTypedAccessOracle(Use->getUser())) - return V.getType(); + return V->getType(); // Otherwise return an empty SILType return SILType(); @@ -435,17 +382,17 @@ static bool typedAccessTBAABuiltinTypesMayAlias(SILType LTy, SILType RTy, // 2. (Pointer, Pointer): If we have two pointers to pointers, since we know // that the two values do not equal due to previous AA calculations, one must // be a native object and the other is an unknown object type (i.e. an objc - // object) which can not alias. + // object) which cannot alias. // // 3. (Scalar, Scalar): If we have two scalar pointers, since we know that the - // types are already not equal, we know that they can not alias. For those + // types are already not equal, we know that they cannot alias. For those // unfamiliar even though BuiltinIntegerType/BuiltinFloatType are single // classes, the AST represents each integer/float of different bit widths as // different types, so equality of SILTypes allows us to know that they have // different bit widths. // // Thus we can just return false since in none of the aforementioned cases we - // can not alias, so return false. + // cannot alias, so return false. return false; } @@ -465,7 +412,7 @@ static bool typedAccessTBAAMayAlias(SILType LTy, SILType RTy, SILModule &Mod) { // Typed access based TBAA only occurs on pointers. If we reach this point and // do not have a pointer, be conservative and return that the two types may - // alias. *NOTE* This ensures we return may alias for local_storage. + // alias. if(!LTy.isAddress() || !RTy.isAddress()) return true; @@ -520,7 +467,7 @@ static bool typedAccessTBAAMayAlias(SILType LTy, SILType RTy, SILModule &Mod) { // FIXME: All the code following could be made significantly more aggressive // by saying that aggregates of the same type that do not contain each other - // can not alias. + // cannot alias. // Tuples do not alias non-tuples. bool LTyTT = LTy.is(); @@ -589,7 +536,10 @@ AliasResult AliasAnalysis::alias(SILValue V1, SILValue V2, // Flush the cache if the size of the cache is too large. if (AliasCache.size() > AliasAnalysisMaxCacheSize) { AliasCache.clear(); - ValueBaseToIndex.clear(); + AliasValueBaseToIndex.clear(); + + // Key is no longer valid as we cleared the AliasValueBaseToIndex. + Key = toAliasKey(V1, V2, TBAAType1, TBAAType2); } // Calculate the aliasing result and store it in the cache. @@ -613,8 +563,8 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2, if (isSameValueOrGlobal(V1, V2)) return AliasResult::MustAlias; - DEBUG(llvm::dbgs() << "ALIAS ANALYSIS:\n V1: " << *V1.getDef() - << " V2: " << *V2.getDef()); + DEBUG(llvm::dbgs() << "ALIAS ANALYSIS:\n V1: " << *V1 + << " V2: " << *V2); // Pass in both the TBAA types so we can perform typed access TBAA and the // actual types of V1, V2 so we can perform class based TBAA. @@ -627,37 +577,50 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2, #endif // Strip off any casts on V1, V2. - V1 = V1.stripCasts(); - V2 = V2.stripCasts(); - DEBUG(llvm::dbgs() << " After Cast Stripping V1:" << *V1.getDef()); - DEBUG(llvm::dbgs() << " After Cast Stripping V2:" << *V2.getDef()); + V1 = stripCasts(V1); + V2 = stripCasts(V2); + DEBUG(llvm::dbgs() << " After Cast Stripping V1:" << *V1); + DEBUG(llvm::dbgs() << " After Cast Stripping V2:" << *V2); // Ok, we need to actually compute an Alias Analysis result for V1, V2. Begin // by finding the "base" of V1, V2 by stripping off all casts and GEPs. SILValue O1 = getUnderlyingObject(V1); SILValue O2 = getUnderlyingObject(V2); - DEBUG(llvm::dbgs() << " Underlying V1:" << *O1.getDef()); - DEBUG(llvm::dbgs() << " Underlying V2:" << *O2.getDef()); + DEBUG(llvm::dbgs() << " Underlying V1:" << *O1); + DEBUG(llvm::dbgs() << " Underlying V2:" << *O2); - // If O1 and O2 do not equal, see if we can prove that they can not be the + // If O1 and O2 do not equal, see if we can prove that they cannot be the // same object. If we can, return No Alias. if (O1 != O2 && aliasUnequalObjects(O1, O2)) return AliasResult::NoAlias; // Ok, either O1, O2 are the same or we could not prove anything based off of - // their inequality. Now we climb up use-def chains and attempt to do tricks - // based off of GEPs. + // their inequality. + // Next: ask escape analysis. This catches cases where we compare e.g. a + // non-escaping pointer with another (maybe escaping) pointer. Escape analysis + // uses the connection graph to check if the pointers may point to the same + // content. + // Note that escape analysis must work with the original pointers and not the + // underlying objects because it treats projections differently. + if (!EA->canPointToSameMemory(V1, V2)) { + DEBUG(llvm::dbgs() << " Found not-aliased objects based on" + "escape analysis\n"); + return AliasResult::NoAlias; + } + + // Now we climb up use-def chains and attempt to do tricks based off of GEPs. // First if one instruction is a gep and the other is not, canonicalize our // inputs so that V1 always is the instruction containing the GEP. - if (!Projection::isAddrProjection(V1) && Projection::isAddrProjection(V2)) { + if (!NewProjection::isAddressProjection(V1) && + NewProjection::isAddressProjection(V2)) { std::swap(V1, V2); std::swap(O1, O2); } // If V1 is an address projection, attempt to use information from the // aggregate type tree to disambiguate it from V2. - if (Projection::isAddrProjection(V1)) { + if (NewProjection::isAddressProjection(V1)) { AliasResult Result = aliasAddressProjection(V1, V2, O1, O2); if (Result != AliasResult::MayAlias) return Result; @@ -668,6 +631,47 @@ AliasResult AliasAnalysis::aliasInner(SILValue V1, SILValue V2, return AliasResult::MayAlias; } +bool AliasAnalysis::canApplyDecrementRefCount(FullApplySite FAS, SILValue Ptr) { + // Treat applications of @noreturn functions as decrementing ref counts. This + // causes the apply to become a sink barrier for ref count increments. + if (FAS.getCallee()->getType().getAs()->isNoReturn()) + return true; + + /// If the pointer cannot escape to the function we are done. + if (!EA->canEscapeTo(Ptr, FAS)) + return false; + + SideEffectAnalysis::FunctionEffects ApplyEffects; + SEA->getEffects(ApplyEffects, FAS); + + auto &GlobalEffects = ApplyEffects.getGlobalEffects(); + if (ApplyEffects.mayReadRC() || GlobalEffects.mayRelease()) + return true; + + /// The function has no unidentified releases, so let's look at the arguments + // in detail. + for (unsigned Idx = 0, End = FAS.getNumArguments(); Idx < End; ++Idx) { + auto &ArgEffect = ApplyEffects.getParameterEffects()[Idx]; + if (ArgEffect.mayRelease()) { + // The function may release this argument, so check if the pointer can + // escape to it. + if (EA->canEscapeToValue(Ptr, FAS.getArgument(Idx))) + return true; + } + } + return false; +} + +bool AliasAnalysis::canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr) { + for (SILValue Arg : BI->getArguments()) { + // A builtin can only release an object if it can escape to one of the + // builtin's arguments. + if (EA->canEscapeToValue(Ptr, Arg)) + return true; + } + return false; +} + bool swift::isLetPointer(SILValue V) { // Traverse the "access" path for V and check that it starts with "let" // and everything along this path is a value-type (i.e. struct or tuple). @@ -698,6 +702,7 @@ bool swift::isLetPointer(SILValue V) { void AliasAnalysis::initialize(SILPassManager *PM) { SEA = PM->getAnalysis(); + EA = PM->getAnalysis(); } SILAnalysis *swift::createAliasAnalysis(SILModule *M) { @@ -706,11 +711,13 @@ SILAnalysis *swift::createAliasAnalysis(SILModule *M) { AliasKeyTy AliasAnalysis::toAliasKey(SILValue V1, SILValue V2, SILType Type1, SILType Type2) { - size_t idx1 = ValueBaseToIndex.getIndex(V1.getDef()); - size_t idx2 = ValueBaseToIndex.getIndex(V2.getDef()); - unsigned R1 = V1.getResultNumber(); - unsigned R2 = V2.getResultNumber(); + size_t idx1 = AliasValueBaseToIndex.getIndex(V1); + assert(idx1 != std::numeric_limits::max() && + "~0 index reserved for empty/tombstone keys"); + size_t idx2 = AliasValueBaseToIndex.getIndex(V2); + assert(idx2 != std::numeric_limits::max() && + "~0 index reserved for empty/tombstone keys"); void *t1 = Type1.getOpaqueValue(); void *t2 = Type2.getOpaqueValue(); - return {idx1, idx2, R1, R2, t1, t2}; + return {idx1, idx2, t1, t2}; } diff --git a/lib/SILOptimizer/Analysis/Analysis.cpp b/lib/SILOptimizer/Analysis/Analysis.cpp index eea8c76b325e9..3358e94627b5b 100644 --- a/lib/SILOptimizer/Analysis/Analysis.cpp +++ b/lib/SILOptimizer/Analysis/Analysis.cpp @@ -1,8 +1,8 @@ -//===----- Analysis.cpp - Swift Analysis ----------------------------------===// +//===--- Analysis.cpp - Swift Analysis ------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp index 8df7d680f1763..143695b7eaf51 100644 --- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp +++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp @@ -1,8 +1,8 @@ -//===- ArraySemantic.cpp - Wrapper around array semantic calls. -*- C++ -*-===// +//===--- ArraySemantic.cpp - Wrapper around array semantic calls. ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -55,7 +55,7 @@ bool swift::ArraySemanticsCall::isValidSignature() { case ArrayCallKind::kCheckIndex: { // Int, @guaranteed/@owned Self if (SemanticsCall->getNumArguments() != 2 || - !SemanticsCall->getArgument(0).getType().isTrivial(Mod)) + !SemanticsCall->getArgument(0)->getType().isTrivial(Mod)) return false; auto SelfConvention = FnTy->getSelfParameter().getConvention(); return SelfConvention == ParameterConvention::Direct_Guaranteed || @@ -64,9 +64,9 @@ bool swift::ArraySemanticsCall::isValidSignature() { case ArrayCallKind::kCheckSubscript: { // Int, Bool, Self if (SemanticsCall->getNumArguments() != 3 || - !SemanticsCall->getArgument(0).getType().isTrivial(Mod)) + !SemanticsCall->getArgument(0)->getType().isTrivial(Mod)) return false; - if (!SemanticsCall->getArgument(1).getType().isTrivial(Mod)) + if (!SemanticsCall->getArgument(1)->getType().isTrivial(Mod)) return false; auto SelfConvention = FnTy->getSelfParameter().getConvention(); return SelfConvention == ParameterConvention::Direct_Guaranteed || @@ -80,7 +80,7 @@ bool swift::ArraySemanticsCall::isValidSignature() { // Make sure that if we are a _adoptStorage call that our storage is // uniquely referenced by us. SILValue Arg0 = SemanticsCall->getArgument(0); - if (Arg0.getType().isExistentialType()) { + if (Arg0->getType().isExistentialType()) { auto *AllocBufferAI = dyn_cast(Arg0); if (!AllocBufferAI) return false; @@ -94,7 +94,7 @@ bool swift::ArraySemanticsCall::isValidSignature() { AllocFuncName != "swift_bufferAllocateOnStack") return false; - if (!hasOneNonDebugUse(*AllocBufferAI)) + if (!hasOneNonDebugUse(AllocBufferAI)) return false; } return true; @@ -111,9 +111,8 @@ swift::ArraySemanticsCall::ArraySemanticsCall(ValueBase *V, if (auto *AI = dyn_cast(V)) if (auto *Fn = AI->getCalleeFunction()) if ((MatchPartialName && - (Fn->hasDefinedSemantics() && - Fn->getSemanticsString().startswith(SemanticStr))) || - (!MatchPartialName && Fn->hasSemanticsString(SemanticStr))) { + Fn->hasSemanticsAttrThatStartsWith(SemanticStr)) || + (!MatchPartialName && Fn->hasSemanticsAttr(SemanticStr))) { SemanticsCall = AI; // Need a 'self' argument otherwise this is not a semantic call that // we recognize. @@ -137,22 +136,32 @@ ArrayCallKind swift::ArraySemanticsCall::getKind() const { auto F = cast(SemanticsCall->getCallee()) ->getReferencedFunction(); - auto Kind = - llvm::StringSwitch(F->getSemanticsString()) - .Case("array.props.isNativeTypeChecked", - ArrayCallKind::kArrayPropsIsNativeTypeChecked) - .Case("array.init", ArrayCallKind::kArrayInit) - .Case("array.uninitialized", ArrayCallKind::kArrayUninitialized) - .Case("array.check_subscript", ArrayCallKind::kCheckSubscript) - .Case("array.check_index", ArrayCallKind::kCheckIndex) - .Case("array.get_count", ArrayCallKind::kGetCount) - .Case("array.get_capacity", ArrayCallKind::kGetCapacity) - .Case("array.get_element", ArrayCallKind::kGetElement) - .Case("array.owner", ArrayCallKind::kGetArrayOwner) - .Case("array.make_mutable", ArrayCallKind::kMakeMutable) - .Case("array.get_element_address", ArrayCallKind::kGetElementAddress) - .Case("array.mutate_unknown", ArrayCallKind::kMutateUnknown) - .Default(ArrayCallKind::kNone); + ArrayCallKind Kind = ArrayCallKind::kNone; + + for (auto &Attrs : F->getSemanticsAttrs()) { + auto Tmp = + llvm::StringSwitch(Attrs) + .Case("array.props.isNativeTypeChecked", + ArrayCallKind::kArrayPropsIsNativeTypeChecked) + .Case("array.init", ArrayCallKind::kArrayInit) + .Case("array.uninitialized", ArrayCallKind::kArrayUninitialized) + .Case("array.check_subscript", ArrayCallKind::kCheckSubscript) + .Case("array.check_index", ArrayCallKind::kCheckIndex) + .Case("array.get_count", ArrayCallKind::kGetCount) + .Case("array.get_capacity", ArrayCallKind::kGetCapacity) + .Case("array.get_element", ArrayCallKind::kGetElement) + .Case("array.owner", ArrayCallKind::kGetArrayOwner) + .Case("array.make_mutable", ArrayCallKind::kMakeMutable) + .Case("array.get_element_address", + ArrayCallKind::kGetElementAddress) + .Case("array.mutate_unknown", ArrayCallKind::kMutateUnknown) + .Default(ArrayCallKind::kNone); + if (Tmp != ArrayCallKind::kNone) { + assert(Kind == ArrayCallKind::kNone && "Multiple array semantic " + "strings?!"); + Kind = Tmp; + } + } return Kind; } @@ -221,7 +230,7 @@ static bool canHoistArrayArgument(ApplyInst *SemanticsCall, SILValue Arr, Convention != ParameterConvention::Direct_Guaranteed) return false; - auto *SelfVal = Arr.getDef(); + ValueBase *SelfVal = Arr; auto *SelfBB = SelfVal->getParentBB(); if (DT->dominates(SelfBB, InsertBefore->getParent())) return true; @@ -229,14 +238,14 @@ static bool canHoistArrayArgument(ApplyInst *SemanticsCall, SILValue Arr, if (auto LI = dyn_cast(SelfVal)) { // Are we loading a value from an address in a struct defined at a point // dominating the hoist point. - auto Val = LI->getOperand().getDef(); + auto Val = LI->getOperand(); bool DoesNotDominate; StructElementAddrInst *SEI; while ((DoesNotDominate = !DT->dominates(Val->getParentBB(), InsertBefore->getParent())) && (SEI = dyn_cast(Val))) - Val = SEI->getOperand().getDef(); - return DoesNotDominate == false; + Val = SEI->getOperand(); + return !DoesNotDominate; } return false; @@ -262,7 +271,7 @@ bool swift::ArraySemanticsCall::canHoist(SILInstruction *InsertBefore, case ArrayCallKind::kCheckSubscript: { auto IsNativeArg = getArrayPropertyIsNativeTypeChecked(); - ArraySemanticsCall IsNative(IsNativeArg.getDef(), + ArraySemanticsCall IsNative(IsNativeArg, "array.props.isNativeTypeChecked", true); if (!IsNative) { // Do we have a constant parameter? @@ -290,23 +299,23 @@ bool swift::ArraySemanticsCall::canHoist(SILInstruction *InsertBefore, static SILValue copyArrayLoad(SILValue ArrayStructValue, SILInstruction *InsertBefore, DominanceInfo *DT) { - if (DT->dominates(ArrayStructValue.getDef()->getParentBB(), + if (DT->dominates(ArrayStructValue->getParentBB(), InsertBefore->getParent())) return ArrayStructValue; - auto *LI = cast(ArrayStructValue.getDef()); + auto *LI = cast(ArrayStructValue); // Recursively move struct_element_addr. - auto *Val = LI->getOperand().getDef(); + ValueBase *Val = LI->getOperand(); auto *InsertPt = InsertBefore; while (!DT->dominates(Val->getParentBB(), InsertBefore->getParent())) { auto *Inst = cast(Val); Inst->moveBefore(InsertPt); - Val = Inst->getOperand().getDef(); + Val = Inst->getOperand(); InsertPt = Inst; } - return SILValue(LI->clone(InsertBefore), 0); + return LI->clone(InsertBefore); } static ApplyInst *hoistOrCopyCall(ApplyInst *AI, SILInstruction *InsertBefore, @@ -384,7 +393,7 @@ ApplyInst *swift::ArraySemanticsCall::hoistOrCopy(SILInstruction *InsertBefore, if (Kind == ArrayCallKind::kCheckSubscript) { // Copy the array.props argument call. auto IsNativeArg = getArrayPropertyIsNativeTypeChecked(); - ArraySemanticsCall IsNative(IsNativeArg.getDef(), + ArraySemanticsCall IsNative(IsNativeArg, "array.props.isNativeTypeChecked", true); if (!IsNative) { // Do we have a constant parameter? @@ -456,16 +465,17 @@ void swift::ArraySemanticsCall::removeCall() { break; case ArrayCallKind::kGetElement: { // Remove the matching isNativeTypeChecked and check_subscript call. - ArraySemanticsCall IsNative(SemanticsCall->getArgument(2).getDef(), + ArraySemanticsCall IsNative(SemanticsCall->getArgument(2), "array.props.isNativeTypeChecked"); - ArraySemanticsCall SubscriptCheck(SemanticsCall->getArgument(3).getDef(), + ArraySemanticsCall SubscriptCheck(SemanticsCall->getArgument(3), "array.check_subscript"); if (SubscriptCheck) SubscriptCheck.removeCall(); // array.isNativeTypeChecked might be shared among several get_element // calls. The last user should delete it. - if (IsNative && getSingleNonDebugUser(*IsNative) == SemanticsCall) { + if (IsNative && getSingleNonDebugUser((ApplyInst *)IsNative) == + SemanticsCall) { deleteAllDebugUses(IsNative); (*IsNative).replaceAllUsesWithUndef(); IsNative.removeCall(); @@ -505,12 +515,12 @@ swift::ArraySemanticsCall::getArrayPropertyIsNativeTypeChecked() const { bool swift::ArraySemanticsCall::mayHaveBridgedObjectElementType() const { assert(hasSelf() && "Need self parameter"); - auto Ty = getSelf().getType().getSwiftRValueType(); - auto Cannonical = Ty.getCanonicalTypeOrNull(); - if (Cannonical.isNull()) + auto Ty = getSelf()->getType().getSwiftRValueType(); + auto Canonical = Ty.getCanonicalTypeOrNull(); + if (Canonical.isNull()) return true; - auto *Struct = Cannonical->getStructOrBoundGenericStruct(); + auto *Struct = Canonical->getStructOrBoundGenericStruct(); assert(Struct && "Array must be a struct !?"); if (Struct) { auto BGT = dyn_cast(Ty); @@ -539,7 +549,7 @@ SILValue swift::ArraySemanticsCall::getInitializationCount() const { // argument. The count is the second argument. // A call to _allocateUninitialized has the count as first argument. SILValue Arg0 = SemanticsCall->getArgument(0); - if (Arg0.getType().isExistentialType()) + if (Arg0->getType().isExistentialType()) return SemanticsCall->getArgument(1); else return SemanticsCall->getArgument(0); } @@ -612,7 +622,7 @@ bool swift::ArraySemanticsCall::replaceByValue(SILValue V) { assert(getKind() == ArrayCallKind::kGetElement && "Must be a get_element call"); // We only handle loadable types. - if (!V.getType().isLoadable(SemanticsCall->getModule())) + if (!V->getType().isLoadable(SemanticsCall->getModule())) return false; auto Dest = SemanticsCall->getArgument(0); @@ -622,15 +632,15 @@ bool swift::ArraySemanticsCall::replaceByValue(SILValue V) { if (!ASI) return false; - // Expect a check_subscript call or the empty dependence dependence. + // Expect a check_subscript call or the empty dependence. auto SubscriptCheck = SemanticsCall->getArgument(3); - ArraySemanticsCall Check(SubscriptCheck.getDef(), "array.check_subscript"); + ArraySemanticsCall Check(SubscriptCheck, "array.check_subscript"); auto *EmptyDep = dyn_cast(SubscriptCheck); if (!Check && (!EmptyDep || !EmptyDep->getElements().empty())) return false; SILBuilderWithScope Builder(SemanticsCall); - auto &ValLowering = Builder.getModule().getTypeLowering(V.getType()); + auto &ValLowering = Builder.getModule().getTypeLowering(V->getType()); ValLowering.emitRetainValue(Builder, SemanticsCall->getLoc(), V); ValLowering.emitStoreOfCopy(Builder, SemanticsCall->getLoc(), V, Dest, IsInitialization_t::IsInitialization); diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index 3069a4b6f40cd..72beb575fc19d 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -1,8 +1,8 @@ -//===- BasicCalleeAnalysis.cpp - Determine callees per call site ----------===// +//===--- BasicCalleeAnalysis.cpp - Determine callees per call site --------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Analysis/CFG.cpp b/lib/SILOptimizer/Analysis/CFG.cpp index e202b4e9120f6..28f161af6e34a 100644 --- a/lib/SILOptimizer/Analysis/CFG.cpp +++ b/lib/SILOptimizer/Analysis/CFG.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,17 +19,20 @@ using namespace swift; static bool isSafeNonExitTerminator(TermInst *TI) { - switch (TI->getKind()) { - case ValueKind::BranchInst: - case ValueKind::CondBranchInst: - case ValueKind::SwitchValueInst: - case ValueKind::SwitchEnumInst: - case ValueKind::SwitchEnumAddrInst: - case ValueKind::DynamicMethodBranchInst: - case ValueKind::CheckedCastBranchInst: - case ValueKind::CheckedCastAddrBranchInst: + switch (TI->getTermKind()) { + case TermKind::BranchInst: + case TermKind::CondBranchInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastAddrBranchInst: return true; - default: + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::TryApplyInst: return false; } } diff --git a/lib/SILOptimizer/Analysis/ClassHierarchyAnalysis.cpp b/lib/SILOptimizer/Analysis/ClassHierarchyAnalysis.cpp index 6f196279faff6..5d9f44e12b802 100644 --- a/lib/SILOptimizer/Analysis/ClassHierarchyAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/ClassHierarchyAnalysis.cpp @@ -1,8 +1,8 @@ -//===- ClassHierarchyAnalysis.cpp - Analysis of class hierarchy -*- C++ -*-===// +//===--- ClassHierarchyAnalysis.cpp - Class hierarchy analysis ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,6 +12,7 @@ #include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/Module.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" @@ -77,7 +78,7 @@ void ClassHierarchyAnalysis::init() { /// \brief Get all subclasses of a given class. /// Does not include any direct subclasses of given base class. /// -/// \p Base base class, whose direct subclasses are to be excluded +/// \p Base class, whose direct subclasses are to be excluded /// \p Current class, whose direct and indirect subclasses are /// to be collected. /// \p IndirectSubs placeholder for collected results diff --git a/lib/SILOptimizer/Analysis/ColdBlockInfo.cpp b/lib/SILOptimizer/Analysis/ColdBlockInfo.cpp index 65b558e08a7ea..b62e96a2247be 100644 --- a/lib/SILOptimizer/Analysis/ColdBlockInfo.cpp +++ b/lib/SILOptimizer/Analysis/ColdBlockInfo.cpp @@ -1,8 +1,8 @@ -//===----- ColdBlocks.cpp - Fast/slow path analysis for the SIL CFG -------===// +//===--- ColdBlockInfo.cpp - Fast/slow path analysis for the SIL CFG ------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,7 @@ enum BranchHint : unsigned { }; } // namespace -/// \return a BranHint if this call is a builtin branch hint. +/// \return a BranchHint if this call is a builtin branch hint. static BranchHint getBranchHint(SILValue Cond) { // Handle the fully inlined Builtin. if (auto *BI = dyn_cast(Cond)) { @@ -57,8 +57,8 @@ static BranchHint getBranchHint(SILValue Cond) { return BranchHint::None; if (auto *F = AI->getCalleeFunction()) { - if (F->hasDefinedSemantics()) { - if (F->getSemanticsString() == "branchhint") { + if (F->hasSemanticsAttrs()) { + if (F->hasSemanticsAttr("branchhint")) { // A "branchint" model takes a Bool expected value as the second // argument. if (auto *SI = dyn_cast(AI->getArgument(1))) { @@ -72,9 +72,9 @@ static BranchHint getBranchHint(SILValue Cond) { } // fastpath/slowpath attrs are untested because the inliner luckily // inlines them before the downstream calls. - else if (F->getSemanticsString() == "slowpath") + else if (F->hasSemanticsAttr("slowpath")) return BranchHint::LikelyFalse; - else if (F->getSemanticsString() == "fastpath") + else if (F->hasSemanticsAttr("fastpath")) return BranchHint::LikelyTrue; } } diff --git a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp index fe0cca5f6317f..4896b9cac4cb4 100644 --- a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp @@ -40,7 +40,7 @@ bool DestructorAnalysis::isSafeType(Type Ty) { } // Before we recurse mark the type as safe i.e if we see it in a recursive - // possition it is safe in the absence of another fact that proves otherwise. + // position it is safe in the absence of another fact that proves otherwise. // We will reset this value to the correct value once we return from the // recursion below. cacheResult(Canonical, true); diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 993c785b1ee32..b7089fca8d5c2 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -1,8 +1,8 @@ -//===-------------- EscapeAnalysis.cpp - SIL Escape Analysis --------------===// +//===--- EscapeAnalysis.cpp - SIL Escape Analysis -------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -65,7 +65,7 @@ static ValueBase *skipProjections(ValueBase *V) { for (;;) { if (!isProjection(V)) return V; - V = cast(V)->getOperand(0).getDef(); + V = cast(V)->getOperand(0); } llvm_unreachable("there is no escape from an infinite loop"); } @@ -80,13 +80,28 @@ void EscapeAnalysis::ConnectionGraph::clear() { } EscapeAnalysis::CGNode *EscapeAnalysis::ConnectionGraph:: -getOrCreateNode(ValueBase *V) { +getNode(ValueBase *V, EscapeAnalysis *EA, bool createIfNeeded) { + if (isa(V)) + return nullptr; + + if (!V->hasValue()) + return nullptr; + + if (!EA->isPointer(V)) + return nullptr; + + V = skipProjections(V); + + if (!createIfNeeded) + return lookupNode(V); + CGNode * &Node = Values2Nodes[V]; if (!Node) { if (SILArgument *Arg = dyn_cast(V)) { if (Arg->isFunctionArg()) { Node = allocNode(V, NodeType::Argument); - Node->mergeEscapeState(EscapeState::Arguments); + if (!isSummaryGraph) + Node->mergeEscapeState(EscapeState::Arguments); } else { Node = allocNode(V, NodeType::Value); } @@ -99,7 +114,7 @@ getOrCreateNode(ValueBase *V) { EscapeAnalysis::CGNode *EscapeAnalysis::ConnectionGraph::getContentNode( CGNode *AddrNode) { - // Do we already have a content node (which is not necessarliy an immediate + // Do we already have a content node (which is not necessarily an immediate // successor of AddrNode)? if (AddrNode->pointsTo) return AddrNode->pointsTo; @@ -112,7 +127,7 @@ EscapeAnalysis::CGNode *EscapeAnalysis::ConnectionGraph::getContentNode( } bool EscapeAnalysis::ConnectionGraph::addDeferEdge(CGNode *From, CGNode *To) { - if (!From->addDefered(To)) + if (!From->addDeferred(To)) return false; CGNode *FromPointsTo = From->pointsTo; @@ -135,8 +150,8 @@ bool EscapeAnalysis::ConnectionGraph::addDeferEdge(CGNode *From, CGNode *To) { void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { while (!ToMerge.empty()) { CGNode *From = ToMerge.pop_back_val(); - CGNode *To = From->mergeTo; - assert(To && "Node scheduled to merge but no merge target set"); + CGNode *To = From->getMergeTarget(); + assert(To != From && "Node scheduled to merge but no merge target set"); assert(!From->isMerged && "Merge source is already merged"); assert(From->Type == NodeType::Content && "Can only merge content nodes"); assert(To->Type == NodeType::Content && "Can only merge content nodes"); @@ -153,7 +168,7 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { PredNode->setPointsTo(To); } else { assert(PredNode != From); - auto Iter = PredNode->findDefered(From); + auto Iter = PredNode->findDeferred(From); assert(Iter != PredNode->defersTo.end() && "Incoming defer-edge not found in predecessor's defer list"); PredNode->defersTo.erase(Iter); @@ -180,9 +195,11 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { Defers->removeFromPreds(Predecessor(From, EdgeType::Defer)); } // Redirect the incoming defer edges. This may trigger other node merges. - for (Predecessor Pred : From->Preds) { - CGNode *PredNode = Pred.getPointer(); - if (Pred.getInt() == EdgeType::Defer) { + // Note that the Pred iterator may be invalidated (because we may add + // edges in the loop). So we don't do: for (Pred : From->Preds) {...} + for (unsigned PredIdx = 0; PredIdx < From->Preds.size(); ++PredIdx) { + CGNode *PredNode = From->Preds[PredIdx].getPointer(); + if (From->Preds[PredIdx].getInt() == EdgeType::Defer) { assert(PredNode != From && "defer edge may not form a self-cycle"); addDeferEdge(PredNode, To); } @@ -192,29 +209,36 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { for (CGNode *Defers : From->defersTo) { addDeferEdge(To, Defers); } - - // Ensure that graph invariance 4) is kept. At this point there may be still - // some violations because of the new adjacent edges of the To node. - for (Predecessor Pred : To->Preds) { - if (Pred.getInt() == EdgeType::PointsTo) { - CGNode *PredNode = Pred.getPointer(); - for (Predecessor PredOfPred : PredNode->Preds) { - if (PredOfPred.getInt() == EdgeType::Defer) - updatePointsTo(PredOfPred.getPointer(), To); + // There is no point in updating the pointsTo if the To node will be + // merged to another node eventually. + if (!To->mergeTo) { + // Ensure that graph invariance 4) is kept. At this point there may be still + // some violations because of the new adjacent edges of the To node. + for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) { + if (To->Preds[PredIdx].getInt() == EdgeType::PointsTo) { + CGNode *PredNode = To->Preds[PredIdx].getPointer(); + for (unsigned PPIdx = 0; PPIdx < PredNode->Preds.size(); ++PPIdx) { + if (PredNode->Preds[PPIdx].getInt() == EdgeType::Defer) + updatePointsTo(PredNode->Preds[PPIdx].getPointer(), To); + } + for (CGNode *Def : PredNode->defersTo) { + updatePointsTo(Def, To); + } } } - } - if (CGNode *ToPT = To->getPointsToEdge()) { - for (CGNode *ToDef : To->defersTo) { - updatePointsTo(ToDef, ToPT); - } - for (Predecessor Pred : To->Preds) { - if (Pred.getInt() == EdgeType::Defer) - updatePointsTo(Pred.getPointer(), ToPT); + if (CGNode *ToPT = To->getPointsToEdge()) { + ToPT = ToPT->getMergeTarget(); + for (CGNode *ToDef : To->defersTo) { + updatePointsTo(ToDef, ToPT); + assert(!ToPT->mergeTo); + } + for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) { + if (To->Preds[PredIdx].getInt() == EdgeType::Defer) + updatePointsTo(To->Preds[PredIdx].getPointer(), ToPT); + } } + To->mergeEscapeState(From->State); } - To->mergeEscapeState(From->State); - // Cleanup the merged node. From->isMerged = true; From->Preds.clear(); @@ -226,9 +250,11 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { void EscapeAnalysis::ConnectionGraph:: updatePointsTo(CGNode *InitialNode, CGNode *pointsTo) { // Visit all nodes in the defer web, which don't have the right pointsTo set. + assert(!pointsTo->mergeTo); llvm::SmallVector WorkList; WorkList.push_back(InitialNode); InitialNode->isInWorkList = true; + bool isInitialSet = false; for (unsigned Idx = 0; Idx < WorkList.size(); ++Idx) { auto *Node = WorkList[Idx]; if (Node->pointsTo == pointsTo) @@ -237,6 +263,8 @@ updatePointsTo(CGNode *InitialNode, CGNode *pointsTo) { if (Node->pointsTo) { // Mismatching: we need to merge! scheduleToMerge(Node->pointsTo, pointsTo); + } else { + isInitialSet = true; } // If the node already has a pointsTo _edge_ we don't change it (we don't @@ -253,10 +281,10 @@ updatePointsTo(CGNode *InitialNode, CGNode *pointsTo) { } // Add all adjacent nodes to the WorkList. - for (auto *Defered : Node->defersTo) { - if (!Defered->isInWorkList) { - WorkList.push_back(Defered); - Defered->isInWorkList = true; + for (auto *Deferred : Node->defersTo) { + if (!Deferred->isInWorkList) { + WorkList.push_back(Deferred); + Deferred->isInWorkList = true; } } for (Predecessor Pred : Node->Preds) { @@ -269,6 +297,60 @@ updatePointsTo(CGNode *InitialNode, CGNode *pointsTo) { } } } + if (isInitialSet) { + // Here we handle a special case: all defer-edge paths must eventually end + // in a points-to edge to pointsTo. We ensure this by setting the edge on + // nodes which have no defer-successors (see above). But this does not cover + // the case where there is a terminating cycle in the defer-edge path, + // e.g. A -> B -> C -> B + // We find all nodes which don't reach a points-to edge and add additional + // points-to edges to fix that. + llvm::SmallVector PotentiallyInCycles; + + // Keep all nodes with a points-to edge in the WorkList and remove all other + // nodes. + unsigned InsertionPoint = 0; + for (CGNode *Node : WorkList) { + if (Node->pointsToIsEdge) { + WorkList[InsertionPoint++] = Node; + } else { + Node->isInWorkList = false; + PotentiallyInCycles.push_back(Node); + } + } + WorkList.set_size(InsertionPoint); + unsigned Idx = 0; + while (!PotentiallyInCycles.empty()) { + + // Propagate the "reaches-a-points-to-edge" backwards in the defer-edge + // sub-graph by adding those nodes to the WorkList. + while (Idx < WorkList.size()) { + auto *Node = WorkList[Idx++]; + for (Predecessor Pred : Node->Preds) { + if (Pred.getInt() == EdgeType::Defer) { + CGNode *PredNode = Pred.getPointer(); + if (!PredNode->isInWorkList) { + WorkList.push_back(PredNode); + PredNode->isInWorkList = true; + } + } + } + } + // Check if we still have some nodes which don't reach a points-to edge, + // i.e. points not yet in the WorkList. + while (!PotentiallyInCycles.empty()) { + auto *Node = PotentiallyInCycles.pop_back_val(); + if (!Node->isInWorkList) { + // We create a points-to edge for the first node which doesn't reach + // a points-to edge yet. + Node->setPointsTo(pointsTo); + WorkList.push_back(Node); + Node->isInWorkList = true; + break; + } + } + } + } clearWorkListFlags(WorkList); } @@ -296,7 +378,7 @@ void EscapeAnalysis::ConnectionGraph::computeUsePoints() { /// In addition to releasing instructions (see below) we also add block /// arguments as use points. In case of loops, block arguments can /// "extend" the liferange of a reference in upward direction. - if (CGNode *ArgNode = getNodeOrNull(BBArg)) { + if (CGNode *ArgNode = lookupNode(BBArg)) { addUsePoint(ArgNode, BBArg); } } @@ -310,11 +392,11 @@ void EscapeAnalysis::ConnectionGraph::computeUsePoints() { case ValueKind::TryApplyInst: { /// Actually we only add instructions which may release a reference. /// We need the use points only for getting the end of a reference's - /// liferange. And that must be a releaseing instruction. + /// liferange. And that must be a releasing instruction. int ValueIdx = -1; for (const Operand &Op : I.getAllOperands()) { - ValueBase *OpV = Op.get().getDef(); - if (CGNode *OpNd = getNodeOrNull(skipProjections(OpV))) { + ValueBase *OpV = Op.get(); + if (CGNode *OpNd = lookupNode(skipProjections(OpV))) { if (ValueIdx < 0) { ValueIdx = addUsePoint(OpNd, &I); } else { @@ -425,10 +507,10 @@ bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph, DestFrom = DestFrom->getMergeTarget(); } - for (auto *Defered : SourceReachable->defersTo) { - if (!Defered->isInWorkList) { - WorkList.push_back(Defered); - Defered->isInWorkList = true; + for (auto *Deferred : SourceReachable->defersTo) { + if (!Deferred->isInWorkList) { + WorkList.push_back(Deferred); + Deferred->isInWorkList = true; } } } @@ -438,22 +520,6 @@ bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph, return Changed; } -EscapeAnalysis::CGNode *EscapeAnalysis::ConnectionGraph:: -getNode(ValueBase *V, EscapeAnalysis *EA) { - if (isa(V)) - return nullptr; - - if (!V->hasValue()) - return nullptr; - - if (!EA->isPointer(V)) - return nullptr; - - V = skipProjections(V); - - return getOrCreateNode(V); -} - /// Returns true if \p V is a use of \p Node, i.e. V may (indirectly) /// somehow refer to the Node's value. /// Use-points are only values which are relevant for lifeness computation, @@ -470,7 +536,7 @@ bool EscapeAnalysis::ConnectionGraph::isUsePoint(ValueBase *V, CGNode *Node) { return Node->UsePoints.test(Idx); } -bool EscapeAnalysis::ConnectionGraph::canEscapeTo(CGNode *From, CGNode *To) { +bool EscapeAnalysis::ConnectionGraph::isReachable(CGNode *From, CGNode *To) { // See if we can reach the From-node by transitively visiting the // predecessor nodes of the To-node. // Usually nodes have few predecessor nodes and the graph depth is small. @@ -507,7 +573,7 @@ struct CGForDotView { enum EdgeTypes { PointsTo, - Defered + Deferred }; struct Node { @@ -564,7 +630,7 @@ CGForDotView::CGForDotView(const EscapeAnalysis::ConnectionGraph *CG) : } for (auto *Def : OrigNode->defersTo) { Nd.Children.push_back(Orig2Node[Def]); - Nd.ChildrenTypes.push_back(Defered); + Nd.ChildrenTypes.push_back(Deferred); } } } @@ -585,7 +651,7 @@ std::string CGForDotView::getNodeLabel(const Node *Node) const { default: { std::string Inst; llvm::raw_string_ostream OI(Inst); - SILValue(Node->OrigNode->V).print(OI); + SILValue(Node->OrigNode->V)->print(OI); size_t start = Inst.find(" = "); if (start != std::string::npos) { start += 3; @@ -702,7 +768,7 @@ namespace llvm { unsigned ChildIdx = I - Node->Children.begin(); switch (Node->ChildrenTypes[ChildIdx]) { case CGForDotView::PointsTo: return ""; - case CGForDotView::Defered: return "color=\"gray\""; + case CGForDotView::Deferred: return "color=\"gray\""; } } }; @@ -865,7 +931,7 @@ void EscapeAnalysis::ConnectionGraph::verifyStructure() const { for (Predecessor Pred : Nd->Preds) { CGNode *PredNode = Pred.getPointer(); if (Pred.getInt() == EdgeType::Defer) { - assert(PredNode->findDefered(Nd) != PredNode->defersTo.end()); + assert(PredNode->findDeferred(Nd) != PredNode->defersTo.end()); } else { assert(Pred.getInt() == EdgeType::PointsTo); assert(PredNode->getPointsToEdge() == Nd); @@ -948,13 +1014,12 @@ static bool isOrContainsReference(SILType Ty, SILModule *Mod) { bool EscapeAnalysis::isPointer(ValueBase *V) { assert(V->hasValue()); - SILType Ty = V->getType(0); + SILType Ty = V->getType(); auto Iter = isPointerCache.find(Ty); if (Iter != isPointerCache.end()) return Iter->second; - bool IP = (Ty.isAddress() || Ty.isLocalStorage() || - isOrContainsReference(Ty, M)); + bool IP = (Ty.isAddress() || isOrContainsReference(Ty, M)); isPointerCache[Ty] = IP; return IP; } @@ -1059,7 +1124,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, return; case ArrayCallKind::kGetElement: // This is like a load from a ref_element_addr. - if (FAS.getArgument(0).getType().isAddress()) { + if (FAS.getArgument(0)->getType().isAddress()) { if (CGNode *AddrNode = ConGraph->getNode(ASC.getSelf(), this)) { if (CGNode *DestNode = ConGraph->getNode(FAS.getArgument(0), this)) { // One content node for going from the array buffer pointer to @@ -1121,6 +1186,9 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, case ValueKind::AllocStackInst: case ValueKind::AllocRefInst: case ValueKind::AllocBoxInst: + ConGraph->getNode(I, this); + return; + case ValueKind::DeallocStackInst: case ValueKind::StrongRetainInst: case ValueKind::StrongRetainUnownedInst: @@ -1139,6 +1207,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, return; case ValueKind::StrongReleaseInst: case ValueKind::ReleaseValueInst: + case ValueKind::StrongUnpinInst: case ValueKind::UnownedReleaseInst: { SILValue OpV = I->getOperand(0); if (CGNode *AddrNode = ConGraph->getNode(OpV, this)) { @@ -1148,7 +1217,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, // deallocation). CGNode *CapturedByDeinit = ConGraph->getContentNode(AddrNode); CapturedByDeinit = ConGraph->getContentNode(CapturedByDeinit); - if (isArrayOrArrayStorage(OpV)) { + if (deinitIsKnownToNotCapture(OpV)) { CapturedByDeinit = ConGraph->getContentNode(CapturedByDeinit); } ConGraph->setEscapesGlobal(CapturedByDeinit); @@ -1246,6 +1315,7 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, case ValueKind::BridgeObjectToRefInst: case ValueKind::UncheckedAddrCastInst: case ValueKind::UnconditionalCheckedCastInst: + case ValueKind::StrongPinInst: // A cast is almost like a projection. if (CGNode *OpNode = ConGraph->getNode(I->getOperand(0), this)) { ConGraph->setNode(I, OpNode); @@ -1282,26 +1352,43 @@ analyzeSelectInst(SelectInst *SI, ConnectionGraph *ConGraph) { SILValue CaseVal = SI->getCase(Idx).second; auto *ArgNode = ConGraph->getNode(CaseVal, this); assert(ArgNode && - "there should be an argument node if there is an result node"); + "there should be an argument node if there is a result node"); ConGraph->defer(ResultNode, ArgNode); } // ... also including the default value. auto *DefaultNode = ConGraph->getNode(SI->getDefaultResult(), this); assert(DefaultNode && - "there should be an argument node if there is an result node"); + "there should be an argument node if there is a result node"); ConGraph->defer(ResultNode, DefaultNode); } } -bool EscapeAnalysis::isArrayOrArrayStorage(SILValue V) { +bool EscapeAnalysis::deinitIsKnownToNotCapture(SILValue V) { for (;;) { - if (V.getType().getNominalOrBoundGenericNominal() == ArrayType) + // The deinit of an array buffer does not capture the array elements. + if (V->getType().getNominalOrBoundGenericNominal() == ArrayType) return true; - if (!isProjection(V.getDef())) - return false; + // The deinit of a box does not capture its content. + if (V->getType().is()) + return true; + + if (isa(V)) + return true; - V = dyn_cast(V.getDef())->getOperand(0); + // Check all operands of a partial_apply + if (auto *PAI = dyn_cast(V)) { + for (Operand &Op : PAI->getAllOperands()) { + if (isPointer(Op.get()) && !deinitIsKnownToNotCapture(Op.get())) + return false; + } + return true; + } + if (isProjection(V)) { + V = dyn_cast(V)->getOperand(0); + continue; + } + return false; } } @@ -1317,7 +1404,7 @@ void EscapeAnalysis::setAllEscaping(SILInstruction *I, // In this case we don't even create a node for the resulting int value. for (const Operand &Op : I->getAllOperands()) { SILValue OpVal = Op.get(); - if (!isNonWritableMemoryAddress(OpVal.getDef())) + if (!isNonWritableMemoryAddress(OpVal)) setEscapesGlobal(ConGraph, OpVal); } // Even if the instruction does not write memory it could e.g. return the @@ -1429,13 +1516,22 @@ bool EscapeAnalysis::mergeCalleeGraph(FullApplySite FAS, // If there are more callee parameters than arguments it means that the // callee is the result of a partial_apply - a thick function. A thick // function also references the boxed partially applied arguments. - // Therefore we map all the extra callee paramters to the callee operand + // Therefore we map all the extra callee parameters to the callee operand // of the apply site. SILValue CallerArg = (Idx < numCallerArgs ? FAS.getArgument(Idx) : FAS.getCallee()); - if (CGNode *CalleeNd = CalleeGraph->getNode(Callee->getArgument(Idx), this)) { - Callee2CallerMapping.add(CalleeNd, CallerGraph->getNode(CallerArg, this)); - } + CGNode *CalleeNd = CalleeGraph->getNode(Callee->getArgument(Idx), this); + if (!CalleeNd) + continue; + + CGNode *CallerNd = CallerGraph->getNode(CallerArg, this); + // There can be the case that we see a callee argument as pointer but not + // the caller argument. E.g. if the callee argument has a @convention(c) + // function type and the caller passes a function_ref. + if (!CallerNd) + continue; + + Callee2CallerMapping.add(CalleeNd, CallerNd); } // Map the return value. @@ -1469,45 +1565,191 @@ bool EscapeAnalysis::mergeSummaryGraph(ConnectionGraph *SummaryGraph, return SummaryGraph->mergeFrom(Graph, Mapping); } - bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, ValueBase *UsePoint, ConnectionGraph *ConGraph) { - CGNode *Node = ConGraph->getNode(V, this); + + assert((FullApplySite::isa(UsePoint) || isa(UsePoint)) && + "use points are only created for calls and refcount instructions"); + + CGNode *Node = ConGraph->getNodeOrNull(V, this); if (!Node) - return false; + return true; - // First check if there are escape pathes which we don't explicitly see + // First check if there are escape paths which we don't explicitly see // in the graph. - switch (Node->getEscapeState()) { - case EscapeState::None: - case EscapeState::Return: - break; - case EscapeState::Arguments: - if (!isNotAliasingArgument(V)) - return true; - break; - case EscapeState::Global: - return true; - } + if (Node->escapesInsideFunction(isNotAliasingArgument(V))) + return true; + // No hidden escapes: check if the Node is reachable from the UsePoint. return ConGraph->isUsePoint(UsePoint, Node); } -bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2, - ConnectionGraph *ConGraph) { - CGNode *Node1 = ConGraph->getNode(V1, this); - assert(Node1 && "value is not a pointer"); - CGNode *Node2 = ConGraph->getNode(V2, this); - assert(Node2 && "value is not a pointer"); +bool EscapeAnalysis::canEscapeTo(SILValue V, FullApplySite FAS) { + // If it's not a local object we don't know anything about the value. + if (!pointsToLocalObject(V)) + return true; + auto *ConGraph = getConnectionGraph(FAS.getFunction()); + return canEscapeToUsePoint(V, FAS.getInstruction(), ConGraph); +} - // If both nodes escape, the relation of the nodes may not be explicitly - // represented in the graph. - if (Node1->escapesInsideFunction() && Node2->escapesInsideFunction()) +static bool hasReferenceSemantics(SILType T) { + // Exclude address types. + return T.isObject() && T.hasReferenceSemantics(); +} + +bool EscapeAnalysis::canObjectOrContentEscapeTo(SILValue V, FullApplySite FAS) { + // If it's not a local object we don't know anything about the value. + if (!pointsToLocalObject(V)) + return true; + + auto *ConGraph = getConnectionGraph(FAS.getFunction()); + CGNode *Node = ConGraph->getNodeOrNull(V, this); + if (!Node) return true; + // First check if there are escape paths which we don't explicitly see + // in the graph. + if (Node->escapesInsideFunction(isNotAliasingArgument(V))) + return true; + + // Check if the object itself can escape to the called function. + SILInstruction *UsePoint = FAS.getInstruction(); + if (ConGraph->isUsePoint(UsePoint, Node)) + return true; + + if (hasReferenceSemantics(V->getType())) { + // Check if the object "content", i.e. a pointer to one of its stored + // properties, can escape to the called function. + CGNode *ContentNode = ConGraph->getContentNode(Node); + if (ContentNode->escapesInsideFunction(false)) + return true; + + if (ConGraph->isUsePoint(UsePoint, ContentNode)) + return true; + } + return false; +} + +bool EscapeAnalysis::canEscapeTo(SILValue V, RefCountingInst *RI) { + // If it's not a local object we don't know anything about the value. + if (!pointsToLocalObject(V)) + return true; + auto *ConGraph = getConnectionGraph(RI->getFunction()); + return canEscapeToUsePoint(V, RI, ConGraph); +} + +/// Utility to get the function which contains both values \p V1 and \p V2. +static SILFunction *getCommonFunction(SILValue V1, SILValue V2) { + SILBasicBlock *BB1 = V1->getParentBB(); + SILBasicBlock *BB2 = V2->getParentBB(); + if (!BB1 || !BB2) + return nullptr; + + SILFunction *F = BB1->getParent(); + assert(BB2->getParent() == F && "values not in same function"); + return F; +} + +bool EscapeAnalysis::canEscapeToValue(SILValue V, SILValue To) { + if (!pointsToLocalObject(V)) + return true; + + SILFunction *F = getCommonFunction(V, To); + if (!F) + return true; + auto *ConGraph = getConnectionGraph(F); + + CGNode *Node = ConGraph->getNodeOrNull(V, this); + if (!Node) + return true; + CGNode *ToNode = ConGraph->getNodeOrNull(To, this); + if (!ToNode) + return true; + return ConGraph->isReachable(Node, ToNode); +} + +bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) { + // At least one of the values must be a non-escaping local object. + bool isLocal1 = pointsToLocalObject(V1); + bool isLocal2 = pointsToLocalObject(V2); + if (!isLocal1 && !isLocal2) + return true; + + SILFunction *F = getCommonFunction(V1, V2); + if (!F) + return true; + auto *ConGraph = getConnectionGraph(F); + + CGNode *Node1 = ConGraph->getNodeOrNull(V1, this); + if (!Node1) + return true; + CGNode *Node2 = ConGraph->getNodeOrNull(V2, this); + if (!Node2) + return true; + + // Finish the check for one value being a non-escaping local object. + if (isLocal1 && Node1->escapesInsideFunction(isNotAliasingArgument(V1))) + isLocal1 = false; + + if (isLocal2 && Node2->escapesInsideFunction(isNotAliasingArgument(V2))) + isLocal2 = false; + + if (!isLocal1 && !isLocal2) + return true; + + // Check if both nodes may point to the same content. CGNode *Content1 = ConGraph->getContentNode(Node1); CGNode *Content2 = ConGraph->getContentNode(Node2); - return Content1 == Content2; + + SILType T1 = V1->getType(); + SILType T2 = V2->getType(); + if (T1.isAddress() && T2.isAddress()) { + return Content1 == Content2; + } + if (hasReferenceSemantics(T1) && hasReferenceSemantics(T2)) { + return Content1 == Content2; + } + // As we model the ref_element_addr instruction as a content-relationship, we + // have to go down one content level if just one of the values is a + // ref-counted object. + if (T1.isAddress() && hasReferenceSemantics(T2)) { + Content2 = ConGraph->getContentNode(Content2); + return Content1 == Content2; + } + if (T2.isAddress() && hasReferenceSemantics(T1)) { + Content1 = ConGraph->getContentNode(Content1); + return Content1 == Content2; + } + return true; +} + +bool EscapeAnalysis::canParameterEscape(FullApplySite FAS, int ParamIdx, + bool checkContentOfIndirectParam) { + CalleeList Callees = BCA->getCalleeList(FAS); + if (!Callees.allCalleesVisible()) + return true; + + // Derive the connection graph of the apply from the known callees. + for (SILFunction *Callee : Callees) { + FunctionInfo *FInfo = getFunctionInfo(Callee); + if (!FInfo->isValid()) + recompute(FInfo); + + CGNode *Node = FInfo->SummaryGraph.getNodeOrNull( + Callee->getArgument(ParamIdx), this); + if (!Node) + return true; + + if (checkContentOfIndirectParam) { + Node = Node->getContentNodeOrNull(); + if (!Node) + continue; + } + + if (Node->escapes()) + return true; + } + return false; } void EscapeAnalysis::invalidate(InvalidationKind K) { diff --git a/lib/SILOptimizer/Analysis/FunctionOrder.cpp b/lib/SILOptimizer/Analysis/FunctionOrder.cpp index 384d5af7bc467..b069e51bd791d 100644 --- a/lib/SILOptimizer/Analysis/FunctionOrder.cpp +++ b/lib/SILOptimizer/Analysis/FunctionOrder.cpp @@ -1,8 +1,8 @@ -//===----- FunctionOrder.cpp - Utility for function ordering --------------===// +//===--- FunctionOrder.cpp - Utility for function ordering ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Analysis/IVAnalysis.cpp b/lib/SILOptimizer/Analysis/IVAnalysis.cpp index 76e0d8d364272..fbf86b56f03d1 100644 --- a/lib/SILOptimizer/Analysis/IVAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/IVAnalysis.cpp @@ -1,8 +1,8 @@ -//===----------------- IVAnalysis.cpp - SIL IV Analysis -------*- C++ -*---===// +//===--- IVAnalysis.cpp - SIL IV Analysis ---------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -70,7 +70,7 @@ SILArgument *IVInfo::isInductionSequence(SCCType &SCC) { } case ValueKind::TupleExtractInst: { - assert(inSCC(cast(I)->getOperand().getDef(), SCC) && + assert(inSCC(cast(I)->getOperand(), SCC) && "TupleExtract operand not an induction var"); break; } diff --git a/lib/SILOptimizer/Analysis/LoopAnalysis.cpp b/lib/SILOptimizer/Analysis/LoopAnalysis.cpp index db64e0ea3e8d6..3cf702a73fb7f 100644 --- a/lib/SILOptimizer/Analysis/LoopAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/LoopAnalysis.cpp @@ -1,8 +1,8 @@ -//===-------------- LoopAnalysis.cpp - SIL Loop Analysis -*- C++ -*--------===// +//===--- LoopAnalysis.cpp - SIL Loop Analysis -----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp index 3870e4defb83f..e98cdeafd5087 100644 --- a/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/LoopRegionAnalysis.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -159,7 +159,6 @@ LoopRegionFunctionInfo::~LoopRegionFunctionInfo() { void LoopRegionFunctionInfo::verify() { #ifndef NDEBUG llvm::SmallVector UniquePredList; - llvm::SmallVector UniqueSuccList; for (auto *R : IDToRegionMap) { // Make sure that our region has a pred list without duplicates. We do not // care if the predecessor list is sorted, just that it is unique. @@ -177,7 +176,7 @@ void LoopRegionFunctionInfo::verify() { if (!R->ParentID.hasValue()) { auto NLSuccs = R->getNonLocalSuccs(); assert(NLSuccs.begin() == NLSuccs.end() && - "Can not have non local " + "Cannot have non local " "successors without a parent node"); continue; } @@ -917,16 +916,6 @@ struct alledge_iterator return SuccIter->getValue().IsNonLocal; } - Optional getSuccIndex() const { - if (isSubregion()) - return None; - // Since we have a bidirectional iterator, this will perform increments - // until we get to SuccIter. This is the behavior we want so that we ensure - // that we skip over any dead successor edges. We are just performing - // graphing, so performance is not a concern. - return std::distance(Wrapper->Region->succ_begin(), SuccIter); - } - LoopRegionWrapper *operator*() const { if (SubregionIter != Wrapper->Region->subregion_end()) { return &Wrapper->FuncInfo.Data[*SubregionIter]; diff --git a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp index 7f2ad76e1c5c6..5acef4972c81d 100644 --- a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp +++ b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,6 +13,7 @@ #define DEBUG_TYPE "sil-membehavior" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SIL/SILVisitor.h" @@ -43,6 +44,8 @@ class MemoryBehaviorVisitor SideEffectAnalysis *SEA; + EscapeAnalysis *EA; + /// The value we are attempting to discover memory behavior relative to. SILValue V; @@ -54,9 +57,10 @@ class MemoryBehaviorVisitor RetainObserveKind InspectionMode; public: - MemoryBehaviorVisitor(AliasAnalysis *AA, SideEffectAnalysis *SEA, SILValue V, + MemoryBehaviorVisitor(AliasAnalysis *AA, SideEffectAnalysis *SEA, + EscapeAnalysis *EA, SILValue V, RetainObserveKind IgnoreRefCountIncs) - : AA(AA), SEA(SEA), V(V), InspectionMode(IgnoreRefCountIncs) {} + : AA(AA), SEA(SEA), EA(EA), V(V), InspectionMode(IgnoreRefCountIncs) {} SILType getValueTBAAType() { if (!TypedAccessTy) @@ -99,14 +103,14 @@ class MemoryBehaviorVisitor MemBehavior visitReleaseValueInst(ReleaseValueInst *BI); // Instructions which are none if our SILValue does not alias one of its - // arguments. If we can not prove such a thing, return the relevant memory + // arguments. If we cannot prove such a thing, return the relevant memory // behavior. #define OPERANDALIAS_MEMBEHAVIOR_INST(Name) \ MemBehavior visit##Name(Name *I) { \ for (Operand &Op : I->getAllOperands()) { \ - if (!AA->isNoAlias(Op.get(), V)) { \ + if (!AA->isNoAlias(Op.get(), V)) { \ DEBUG(llvm::dbgs() << " " #Name \ - " does alias inst. Returning Normal behavior.\n"); \ + " does alias inst. Returning Normal behavior.\n"); \ return I->getMemoryBehavior(); \ } \ } \ @@ -172,7 +176,7 @@ MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) { return MemBehavior::None; // If the store dest cannot alias the pointer in question, then the - // specified value can not be modified by the store. + // specified value cannot be modified by the store. if (AA->isNoAlias(SI->getDest(), V, computeTBAAType(SI->getDest()), getValueTBAAType())) { DEBUG(llvm::dbgs() << " Store Dst does not alias inst. Returning " @@ -219,11 +223,9 @@ MemBehavior MemoryBehaviorVisitor::visitBuiltinInst(BuiltinInst *BI) { MemBehavior MemoryBehaviorVisitor::visitTryApplyInst(TryApplyInst *AI) { MemBehavior Behavior = MemBehavior::MayHaveSideEffects; - // If it is an allocstack which does not escape, tryapply instruction can not - // read/modify the memory. - if (auto *ASI = dyn_cast(getUnderlyingObject(V))) - if (isNonEscapingLocalObject(ASI->getAddressResult())) - Behavior = MemBehavior::None; + // Ask escape analysis. + if (!EA->canObjectOrContentEscapeTo(V, AI)) + Behavior = MemBehavior::None; // Otherwise be conservative and return that we may have side effects. DEBUG(llvm::dbgs() << " Found tryapply, returning " << Behavior << '\n'); @@ -251,58 +253,46 @@ MemBehavior MemoryBehaviorVisitor::visitApplyInst(ApplyInst *AI) { Idx < End && Behavior < MemBehavior::MayHaveSideEffects; ++Idx) { auto &ArgEffect = ApplyEffects.getParameterEffects()[Idx]; auto ArgBehavior = ArgEffect.getMemBehavior(InspectionMode); - if (ArgBehavior > Behavior) { + auto NewBehavior = combineMemoryBehavior(Behavior, ArgBehavior); + if (NewBehavior != Behavior) { SILValue Arg = AI->getArgument(Idx); // We only consider the argument effects if the argument aliases V. - if (!Arg.getType().isAddress() || + if (!Arg->getType().isAddress() || !AA->isNoAlias(Arg, V, computeTBAAType(Arg), getValueTBAAType())) { - Behavior = ArgBehavior; + Behavior = NewBehavior; } } } } - if (Behavior > MemBehavior::MayRead && isLetPointer(V)) - Behavior = MemBehavior::MayRead; + if (Behavior > MemBehavior::None) { + if (Behavior > MemBehavior::MayRead && isLetPointer(V)) + Behavior = MemBehavior::MayRead; - // If it is an allocstack which does not escape, apply instruction can not - // read/modify the memory. - if (auto *ASI = dyn_cast(getUnderlyingObject(V))) - if (isNonEscapingLocalObject(ASI->getAddressResult())) { + // Ask escape analysis. + if (!EA->canObjectOrContentEscapeTo(V, AI)) Behavior = MemBehavior::None; - } - + } DEBUG(llvm::dbgs() << " Found apply, returning " << Behavior << '\n'); return Behavior; } MemBehavior MemoryBehaviorVisitor::visitStrongReleaseInst(StrongReleaseInst *SI) { - // Need to make sure that the allocated memory does not escape. - // AllocBox to stack does not check for whether the address of promoted - // allocstack can escape. - // - // TODO: come up with a test case which shows isNonEscapingLocalObject is - // necessary. - if (AllocStackInst *ASI = dyn_cast(getUnderlyingObject(V))) - if (isNonEscapingLocalObject(ASI->getAddressResult())) - return MemBehavior::None; + if (!EA->canEscapeTo(V, SI)) + return MemBehavior::None; return MemBehavior::MayHaveSideEffects; } MemBehavior MemoryBehaviorVisitor::visitUnownedReleaseInst(UnownedReleaseInst *SI) { - // Need to make sure that the allocated memory does not escape. - if (AllocStackInst *ASI = dyn_cast(getUnderlyingObject(V))) - if (isNonEscapingLocalObject(ASI->getAddressResult())) - return MemBehavior::None; + if (!EA->canEscapeTo(V, SI)) + return MemBehavior::None; return MemBehavior::MayHaveSideEffects; } MemBehavior MemoryBehaviorVisitor::visitReleaseValueInst(ReleaseValueInst *SI) { - // Need to make sure that the allocated memory does not escape. - if (AllocStackInst *ASI = dyn_cast(getUnderlyingObject(V))) - if (isNonEscapingLocalObject(ASI->getAddressResult())) - return MemBehavior::None; + if (!EA->canEscapeTo(V, SI)) + return MemBehavior::None; return MemBehavior::MayHaveSideEffects; } @@ -324,7 +314,10 @@ AliasAnalysis::computeMemoryBehavior(SILInstruction *Inst, SILValue V, // Flush the cache if the size of the cache is too large. if (MemoryBehaviorCache.size() > MemoryBehaviorAnalysisMaxCacheSize) { MemoryBehaviorCache.clear(); - ValueBaseToIndex.clear(); + MemoryBehaviorValueBaseToIndex.clear(); + + // Key is no longer valid as we cleared the MemoryBehaviorValueBaseToIndex. + Key = toMemoryBehaviorKey(SILValue(Inst), V, InspectionMode); } // Calculate the aliasing result and store it in the cache. @@ -337,15 +330,18 @@ MemBehavior AliasAnalysis::computeMemoryBehaviorInner(SILInstruction *Inst, SILValue V, RetainObserveKind InspectionMode) { DEBUG(llvm::dbgs() << "GET MEMORY BEHAVIOR FOR:\n " << *Inst << " " - << *V.getDef()); + << *V); assert(SEA && "SideEffectsAnalysis must be initialized!"); - return MemoryBehaviorVisitor(this, SEA, V, InspectionMode).visit(Inst); + return MemoryBehaviorVisitor(this, SEA, EA, V, InspectionMode).visit(Inst); } MemBehaviorKeyTy AliasAnalysis::toMemoryBehaviorKey(SILValue V1, SILValue V2, RetainObserveKind M) { - size_t idx1 = ValueBaseToIndex.getIndex(V1.getDef()); - size_t idx2 = ValueBaseToIndex.getIndex(V2.getDef()); - unsigned R2 = V2.getResultNumber(); - return {idx1, idx2, R2, M}; + size_t idx1 = MemoryBehaviorValueBaseToIndex.getIndex(V1); + assert(idx1 != std::numeric_limits::max() && + "~0 index reserved for empty/tombstone keys"); + size_t idx2 = MemoryBehaviorValueBaseToIndex.getIndex(V2); + assert(idx2 != std::numeric_limits::max() && + "~0 index reserved for empty/tombstone keys"); + return {idx1, idx2, M}; } diff --git a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp index aefdb0991cdd0..b2949384b3c82 100644 --- a/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -51,23 +51,13 @@ static bool isRCIdentityPreservingCast(ValueKind Kind) { } //===----------------------------------------------------------------------===// -// RCIdentityRoot Analysis +// RC Identity Root Instruction Casting //===----------------------------------------------------------------------===// -/// Returns true if FirstIV is a SILArgument or SILInstruction in a BB that -/// dominates the BB of A. -static bool dominatesArgument(DominanceInfo *DI, SILArgument *A, - SILValue FirstIV) { - SILBasicBlock *OtherBB = FirstIV->getParentBB(); - if (!OtherBB || OtherBB == A->getParent()) - return false; - return DI->dominates(OtherBB, A->getParent()); -} - static SILValue stripRCIdentityPreservingInsts(SILValue V) { // First strip off RC identity preserving casts. if (isRCIdentityPreservingCast(V->getKind())) - return cast(V.getDef())->getOperand(0); + return cast(V)->getOperand(0); // Then if we have a struct_extract that is extracting a non-trivial member // from a struct with no other non-trivial members, a ref count operation on @@ -108,9 +98,37 @@ static SILValue stripRCIdentityPreservingInsts(SILValue V) { if (SILValue NewValue = TI->getUniqueNonTrivialElt()) return NewValue; + // Any SILArgument with a single predecessor from a "phi" perspective is + // dead. In such a case, the SILArgument must be rc-identical. + // + // This is the easy case. The difficult case is when you have an argument with + // /multiple/ predecessors. + // + // We do not need to insert this SILArgument into the visited SILArgument set + // since we will only visit it twice if we go around a back edge due to a + // different SILArgument that is actually being used for its phi node like + // purposes. + if (auto *A = dyn_cast(V)) + if (SILValue Result = A->getSingleIncomingValue()) + return Result; + return SILValue(); } +//===----------------------------------------------------------------------===// +// RC Identity Dominance Argument Analysis +//===----------------------------------------------------------------------===// + +/// Returns true if FirstIV is a SILArgument or SILInstruction in a BB that +/// dominates the BB of A. +static bool dominatesArgument(DominanceInfo *DI, SILArgument *A, + SILValue FirstIV) { + SILBasicBlock *OtherBB = FirstIV->getParentBB(); + if (!OtherBB || OtherBB == A->getParent()) + return false; + return DI->dominates(OtherBB, A->getParent()); +} + /// V is the incoming value for the SILArgument A on at least one path. Find a /// value that is trivially RC-identical to V and dominates the argument's /// block. If such a value exists, it is a candidate for RC-identity with the @@ -162,7 +180,7 @@ static llvm::Optional proveNonPayloadedEnumCase(SILBasicBlock *BB, bool RCIdentityFunctionInfo:: findDominatingNonPayloadedEdge(SILBasicBlock *IncomingEdgeBB, SILValue RCIdentity) { - // First grab the NonPayloadedEnumBB and RCIdentityBB. If we can not find + // First grab the NonPayloadedEnumBB and RCIdentityBB. If we cannot find // either of them, return false. SILBasicBlock *RCIdentityBB = RCIdentity->getParentBB(); if (!RCIdentityBB) @@ -226,7 +244,19 @@ findDominatingNonPayloadedEdge(SILBasicBlock *IncomingEdgeBB, return false; } -/// Return the underlying SILValue after stripping off SILArguments that can not +static SILValue allIncomingValuesEqual( + llvm::SmallVectorImpl> &IncomingValues) { + SILValue First = stripRCIdentityPreservingInsts(IncomingValues[0].second); + if (std::all_of(std::next(IncomingValues.begin()), IncomingValues.end(), + [&First](std::pair P) -> bool { + return stripRCIdentityPreservingInsts(P.second) == First; + })) + return First; + return SILValue(); +} + +/// Return the underlying SILValue after stripping off SILArguments that cannot /// affect RC identity. /// /// This code is meant to enable RCIdentity to be ascertained in the following @@ -283,11 +313,16 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingArgs(SILValue V, unsigned IVListSize = IncomingValues.size(); - // If we only have one incoming value, just return the identity root of that - // incoming value. There can be no loop problems. - if (IVListSize == 1) { - return IncomingValues[0].second; - } + assert(IVListSize != 1 && "Should have been handled in " + "stripRCIdentityPreservingInsts"); + + // Ok, we have multiple predecessors. See if all of them are the same + // value. If so, just return that value. + // + // This returns a SILValue to save a little bit of compile time since we + // already compute that value here. + if (SILValue V = allIncomingValuesEqual(IncomingValues)) + return V; // Ok, we have multiple predecessors. First find the first non-payloaded enum. llvm::SmallVector NoPayloadEnumBBs; @@ -317,7 +352,7 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingArgs(SILValue V, continue; } - // Try to strip off the RCIdentityPresrvingArg for IV. If it matches + // Try to strip off the RCIdentityPreservingArg for IV. If it matches // FirstIV, we may be able to succeed here. if (FirstIV == stripOneRCIdentityIncomingValue(A, IV)) continue; @@ -334,7 +369,7 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingArgs(SILValue V, // At this point, we know that we have *some* NoPayloadEnums. If FirstIV is // not an enum, then we must bail. We do not try to analyze this case. - if (!FirstIV.getType().getEnumOrBoundGenericEnum()) + if (!FirstIV->getType().getEnumOrBoundGenericEnum()) return SILValue(); // Now we know that FirstIV is an enum and that all payloaded enum cases after @@ -358,6 +393,10 @@ llvm::cl::opt StripOffArgs( "enable-rc-identity-arg-strip", llvm::cl::init(true), llvm::cl::desc("Should RC identity try to strip off arguments")); +//===----------------------------------------------------------------------===// +// Top Level RC Identity Root Entrypoints +//===----------------------------------------------------------------------===// + SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingOps(SILValue V, unsigned RecursionDepth) { while (true) { @@ -385,6 +424,37 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingOps(SILValue V, return V; } + +SILValue RCIdentityFunctionInfo::getRCIdentityRootInner(SILValue V, + unsigned RecursionDepth) { + // Only allow this method to be recursed on for a limited number of times to + // make sure we don't explode compile time. + if (RecursionDepth >= MaxRecursionDepth) + return SILValue(); + + SILValue NewValue = stripRCIdentityPreservingOps(V, RecursionDepth); + if (!NewValue) + return SILValue(); + + // We can get back V if our analysis completely fails. There is no point in + // storing this value into the cache so just return it. + if (NewValue == V) + return V; + + return NewValue; +} + +SILValue RCIdentityFunctionInfo::getRCIdentityRoot(SILValue V) { + SILValue Root = getRCIdentityRootInner(V, 0); + VisitedArgs.clear(); + + // If we fail to find a root, return V. + if (!Root) + return V; + + return Root; +} + //===----------------------------------------------------------------------===// // RCUser Analysis //===----------------------------------------------------------------------===// @@ -429,7 +499,7 @@ void RCIdentityFunctionInfo::getRCUsers( SILValue V = Worklist.pop_back_val(); // For each user of V... - for (auto *Op : V.getUses()) { + for (auto *Op : V->getUses()) { SILInstruction *User = Op->getUser(); // If we have already visited this user, continue. @@ -455,9 +525,7 @@ void RCIdentityFunctionInfo::getRCUsers( } // Otherwise, add all of User's uses to our list to continue searching. - for (unsigned i = 0, e = User->getNumTypes(); i != e; ++i) { - Worklist.push_back(SILValue(User, i)); - } + Worklist.push_back(User); } } } @@ -466,36 +534,6 @@ void RCIdentityFunctionInfo::getRCUsers( // Main Entry Point //===----------------------------------------------------------------------===// -SILValue RCIdentityFunctionInfo::getRCIdentityRootInner(SILValue V, - unsigned RecursionDepth) { - // Only allow this method to be recursed on for a limited number of times to - // make sure we don't explode compile time. - if (RecursionDepth >= MaxRecursionDepth) - return SILValue(); - - SILValue NewValue = stripRCIdentityPreservingOps(V, RecursionDepth); - if (!NewValue) - return SILValue(); - - // We can get back V if our analysis completely fails. There is no point in - // storing this value into the cache so just return it. - if (NewValue == V) - return V; - - return NewValue; -} - -SILValue RCIdentityFunctionInfo::getRCIdentityRoot(SILValue V) { - SILValue Root = getRCIdentityRootInner(V, 0); - VisitedArgs.clear(); - - // If we fail to find a root, return V. - if (!Root) - return V; - - return Root; -} - void RCIdentityAnalysis::initialize(SILPassManager *PM) { DA = PM->getAnalysis(); } diff --git a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp index 99ee708d80f7e..e3afce42487a9 100644 --- a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp @@ -1,8 +1,8 @@ -//===---------- SideEffectAnalysis.cpp - SIL Side Effect Analysis ---------===// +//===--- SideEffectAnalysis.cpp - SIL Side Effect Analysis ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,8 +37,7 @@ FunctionEffects::getMemBehavior(RetainObserveKind ScanKind) const { for (auto &ParamEffect : ParamEffects) { MemoryBehavior ArgBehavior = ParamEffect.getMemBehavior(ScanKind); - if (ArgBehavior > Behavior) - Behavior = ArgBehavior; + Behavior = combineMemoryBehavior(Behavior, ArgBehavior); // Stop the scan if we've reached the highest level of side effect. if (Behavior == MemoryBehavior::MayHaveSideEffects) @@ -95,6 +94,7 @@ static SILValue skipAddrProjections(SILValue V) { case ValueKind::StructElementAddrInst: case ValueKind::TupleElementAddrInst: case ValueKind::RefElementAddrInst: + case ValueKind::ProjectBoxInst: case ValueKind::UncheckedTakeEnumDataAddrInst: case ValueKind::PointerToAddressInst: V = cast(V)->getOperand(0); @@ -293,7 +293,11 @@ void SideEffectAnalysis::analyzeInstruction(FunctionInfo *FInfo, if (RecursionDepth < MaxRecursionDepth) { CalleeList Callees = BCA->getCalleeList(FAS); - if (Callees.allCalleesVisible()) { + if (Callees.allCalleesVisible() && + // @callee_owned function calls implicitly release the context, which + // may call deinits of boxed values. + // TODO: be less conservative about what destructors might be called. + !FAS.getOrigCalleeType()->isCalleeConsumed()) { // Derive the effects of the apply from the known callees. for (SILFunction *Callee : Callees) { FunctionInfo *CalleeInfo = getFunctionInfo(Callee); @@ -313,6 +317,11 @@ void SideEffectAnalysis::analyzeInstruction(FunctionInfo *FInfo, } // Handle some kind of instructions specially. switch (I->getKind()) { + case ValueKind::FixLifetimeInst: + // A fix_lifetime instruction acts like a read on the operand. Retains can move after it + // but the last release can't move before it. + FInfo->FE.getEffectsOn(I->getOperand(0))->Reads = true; + return; case ValueKind::AllocStackInst: case ValueKind::DeallocStackInst: return; @@ -462,7 +471,11 @@ void SideEffectAnalysis::getEffects(FunctionEffects &ApplyEffects, FullApplySite } auto Callees = BCA->getCalleeList(FAS); - if (!Callees.allCalleesVisible()) { + if (!Callees.allCalleesVisible() || + // @callee_owned function calls implicitly release the context, which + // may call deinits of boxed values. + // TODO: be less conservative about what destructors might be called. + FAS.getOrigCalleeType()->isCalleeConsumed()) { ApplyEffects.setWorstEffects(); return; } diff --git a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp index d6e7b40a59124..f81aa9c1e431e 100644 --- a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp +++ b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -29,7 +29,6 @@ namespace { public: SILValue visitSILInstruction(SILInstruction *I) { return SILValue(); } - SILValue visitProjectBoxInst(ProjectBoxInst *PBI); SILValue visitTupleExtractInst(TupleExtractInst *TEI); SILValue visitStructExtractInst(StructExtractInst *SEI); SILValue visitEnumInst(EnumInst *EI); @@ -70,7 +69,7 @@ SILValue InstSimplifier::visitStructInst(StructInst *SI) { if (auto *Ex0 = dyn_cast(SI->getOperand(0))) { // Check that the constructed struct and the extracted struct are of the // same type. - if (SI->getType() != Ex0->getOperand().getType()) + if (SI->getType() != Ex0->getOperand()->getType()) return SILValue(); // Check that all of the operands are extracts of the correct kind. @@ -105,7 +104,7 @@ SILValue InstSimplifier::visitTupleInst(TupleInst *TI) { if (auto *Ex0 = dyn_cast(TI->getOperand(0))) { // Check that the constructed tuple and the extracted tuple are of the // same type. - if (TI->getType() != Ex0->getOperand().getType()) + if (TI->getType() != Ex0->getOperand()->getType()) return SILValue(); // Check that all of the operands are extracts of the correct kind. @@ -130,16 +129,6 @@ SILValue InstSimplifier::visitTupleInst(TupleInst *TI) { return SILValue(); } -SILValue InstSimplifier::visitProjectBoxInst(ProjectBoxInst *PBI) { - // project_box(alloc_box#0) -> alloc_box#1 - if (auto TheBox = dyn_cast(PBI->getOperand())) { - assert(PBI->getOperand().getResultNumber() == 0 - && "should only be able to project box result of alloc_box"); - return TheBox->getAddressResult(); - } - return SILValue(); -} - SILValue InstSimplifier::visitTupleExtractInst(TupleExtractInst *TEI) { // tuple_extract(tuple(x, y), 0) -> x if (TupleInst *TheTuple = dyn_cast(TEI->getOperand())) @@ -191,10 +180,10 @@ static SILValue simplifyEnumFromUncheckedEnumData(EnumInst *EI) { SILValue EnumOp = UEDI->getOperand(); - // Same enum elements don't necesserily imply same enum types. + // Same enum elements don't necessarily imply same enum types. // Enum types may be different if the enum is generic, e.g. // E.Case and E.Case. - SILType OriginalEnum = EnumOp.getType(); + SILType OriginalEnum = EnumOp->getType(); SILType NewEnum = EI->getType(); if (OriginalEnum != NewEnum) @@ -206,8 +195,8 @@ static SILValue simplifyEnumFromUncheckedEnumData(EnumInst *EI) { SILValue InstSimplifier::visitSelectEnumInst(SelectEnumInst *SEI) { auto *EI = dyn_cast(SEI->getEnumOperand()); - if (EI && EI->getType() == SEI->getEnumOperand().getType()) { - // Simplify a select_enum on a enum instruction. + if (EI && EI->getType() == SEI->getEnumOperand()->getType()) { + // Simplify a select_enum on an enum instruction. // %27 = enum $Optional, #Optional.Some!enumelt.1, %20 : $Int // %28 = integer_literal $Builtin.Int1, -1 // %29 = integer_literal $Builtin.Int1, 0 @@ -253,7 +242,7 @@ SILValue InstSimplifier::visitEnumInst(EnumInst *EI) { auto Case = SEI->getUniqueCaseForDestination(EI->getParent()); if (Case && Case.getPtrOrNull() == EI->getElement() && - SEI->getOperand().getType() == EI->getType()) { + SEI->getOperand()->getType() == EI->getType()) { return SEI->getOperand(); } @@ -273,7 +262,7 @@ SILValue InstSimplifier::visitEnumInst(EnumInst *EI) { return SILValue(); if (auto *SEI = dyn_cast(Pred->getTerminator())) { - if (EI->getType() != SEI->getOperand().getType()) + if (EI->getType() != SEI->getOperand()->getType()) return SILValue(); if (EI->getElement() == SEI->getUniqueCaseForDestination(BB).getPtrOrNull()) @@ -286,7 +275,7 @@ SILValue InstSimplifier::visitEnumInst(EnumInst *EI) { SILValue InstSimplifier::visitAddressToPointerInst(AddressToPointerInst *ATPI) { // (address_to_pointer (pointer_to_address x)) -> x if (auto *PTAI = dyn_cast(ATPI->getOperand())) - if (PTAI->getType() == ATPI->getOperand().getType()) + if (PTAI->getType() == ATPI->getOperand()->getType()) return PTAI->getOperand(); return SILValue(); @@ -295,7 +284,7 @@ SILValue InstSimplifier::visitAddressToPointerInst(AddressToPointerInst *ATPI) { SILValue InstSimplifier::visitPointerToAddressInst(PointerToAddressInst *PTAI) { // (pointer_to_address (address_to_pointer x)) -> x if (auto *ATPI = dyn_cast(PTAI->getOperand())) - if (ATPI->getOperand().getType() == PTAI->getType()) + if (ATPI->getOperand()->getType() == PTAI->getType()) return ATPI->getOperand(); return SILValue(); @@ -318,7 +307,7 @@ InstSimplifier:: visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) { // (UCCI downcast (upcast x #type1 to #type2) #type2 to #type1) -> x if (auto *upcast = dyn_cast(UCCI->getOperand())) - if (UCCI->getType() == upcast->getOperand().getType()) + if (UCCI->getType() == upcast->getOperand()->getType()) return upcast->getOperand(); return SILValue(); @@ -329,21 +318,21 @@ InstSimplifier:: visitUncheckedRefCastInst(UncheckedRefCastInst *OPRI) { // (unchecked-ref-cast Y->X (unchecked-ref-cast x X->Y)) -> x if (auto *ROPI = dyn_cast(&*OPRI->getOperand())) - if (ROPI->getOperand().getType() == OPRI->getType()) + if (ROPI->getOperand()->getType() == OPRI->getType()) return ROPI->getOperand(); // (unchecked-ref-cast Y->X (upcast x X->Y)) -> x if (auto *UI = dyn_cast(OPRI->getOperand())) - if (UI->getOperand().getType() == OPRI->getType()) + if (UI->getOperand()->getType() == OPRI->getType()) return UI->getOperand(); // (unchecked-ref-cast Y->X (open_existential_ref x X->Y)) -> x if (auto *OER = dyn_cast(OPRI->getOperand())) - if (OER->getOperand().getType() == OPRI->getType()) + if (OER->getOperand()->getType() == OPRI->getType()) return OER->getOperand(); // (unchecked-ref-cast X->X x) -> x - if (OPRI->getOperand().getType() == OPRI->getType()) + if (OPRI->getOperand()->getType() == OPRI->getType()) return OPRI->getOperand(); return SILValue(); @@ -354,11 +343,11 @@ InstSimplifier:: visitUncheckedAddrCastInst(UncheckedAddrCastInst *UACI) { // (unchecked-addr-cast Y->X (unchecked-addr-cast x X->Y)) -> x if (auto *OtherUACI = dyn_cast(&*UACI->getOperand())) - if (OtherUACI->getOperand().getType() == UACI->getType()) + if (OtherUACI->getOperand()->getType() == UACI->getType()) return OtherUACI->getOperand(); // (unchecked-addr-cast X->X x) -> x - if (UACI->getOperand().getType() == UACI->getType()) + if (UACI->getOperand()->getType() == UACI->getType()) return UACI->getOperand(); return SILValue(); @@ -367,7 +356,7 @@ visitUncheckedAddrCastInst(UncheckedAddrCastInst *UACI) { SILValue InstSimplifier::visitUpcastInst(UpcastInst *UI) { // (upcast Y->X (unchecked-ref-cast x X->Y)) -> x if (auto *URCI = dyn_cast(UI->getOperand())) - if (URCI->getOperand().getType() == UI->getType()) + if (URCI->getOperand()->getType() == UI->getType()) return URCI->getOperand(); return SILValue(); @@ -376,7 +365,7 @@ SILValue InstSimplifier::visitUpcastInst(UpcastInst *UI) { SILValue InstSimplifier::visitRefToUnownedInst(RefToUnownedInst *RUI) { if (auto *URI = dyn_cast(RUI->getOperand())) - if (URI->getOperand().getType() == RUI->getType()) + if (URI->getOperand()->getType() == RUI->getType()) return URI->getOperand(); return SILValue(); @@ -385,7 +374,7 @@ InstSimplifier::visitRefToUnownedInst(RefToUnownedInst *RUI) { SILValue InstSimplifier::visitUnownedToRefInst(UnownedToRefInst *URI) { if (auto *RUI = dyn_cast(URI->getOperand())) - if (RUI->getOperand().getType() == URI->getType()) + if (RUI->getOperand()->getType() == URI->getType()) return RUI->getOperand(); return SILValue(); @@ -394,7 +383,7 @@ InstSimplifier::visitUnownedToRefInst(UnownedToRefInst *URI) { SILValue InstSimplifier::visitRefToUnmanagedInst(RefToUnmanagedInst *RUI) { if (auto *URI = dyn_cast(RUI->getOperand())) - if (URI->getOperand().getType() == RUI->getType()) + if (URI->getOperand()->getType() == RUI->getType()) return URI->getOperand(); return SILValue(); @@ -403,7 +392,7 @@ InstSimplifier::visitRefToUnmanagedInst(RefToUnmanagedInst *RUI) { SILValue InstSimplifier::visitUnmanagedToRefInst(UnmanagedToRefInst *URI) { if (auto *RUI = dyn_cast(URI->getOperand())) - if (RUI->getOperand().getType() == URI->getType()) + if (RUI->getOperand()->getType() == URI->getType()) return RUI->getOperand(); return SILValue(); @@ -413,12 +402,12 @@ SILValue InstSimplifier:: visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *UTBCI) { // (unchecked_trivial_bit_cast X->X x) -> x - if (UTBCI->getOperand().getType() == UTBCI->getType()) + if (UTBCI->getOperand()->getType() == UTBCI->getType()) return UTBCI->getOperand(); // (unchecked_trivial_bit_cast Y->X (unchecked_trivial_bit_cast X->Y x)) -> x if (auto *Op = dyn_cast(UTBCI->getOperand())) - if (Op->getOperand().getType() == UTBCI->getType()) + if (Op->getOperand()->getType() == UTBCI->getType()) return Op->getOperand(); return SILValue(); @@ -428,13 +417,13 @@ SILValue InstSimplifier:: visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) { // (unchecked_bitwise_cast X->X x) -> x - if (UBCI->getOperand().getType() == UBCI->getType()) + if (UBCI->getOperand()->getType() == UBCI->getType()) return UBCI->getOperand(); // A round-trip cast implies X and Y have the same size: // (unchecked_bitwise_cast Y->X (unchecked_bitwise_cast X->Y x)) -> x if (auto *Op = dyn_cast(UBCI->getOperand())) - if (Op->getOperand().getType() == UBCI->getType()) + if (Op->getOperand()->getType() == UBCI->getType()) return Op->getOperand(); return SILValue(); @@ -443,7 +432,7 @@ visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *UBCI) { SILValue InstSimplifier::visitThinFunctionToPointerInst(ThinFunctionToPointerInst *TFTPI) { // (thin_function_to_pointer (pointer_to_thin_function x)) -> x if (auto *PTTFI = dyn_cast(TFTPI->getOperand())) - if (PTTFI->getOperand().getType() == TFTPI->getType()) + if (PTTFI->getOperand()->getType() == TFTPI->getType()) return PTTFI->getOperand(); return SILValue(); @@ -452,7 +441,7 @@ SILValue InstSimplifier::visitThinFunctionToPointerInst(ThinFunctionToPointerIns SILValue InstSimplifier::visitPointerToThinFunctionInst(PointerToThinFunctionInst *PTTFI) { // (pointer_to_thin_function (thin_function_to_pointer x)) -> x if (auto *TFTPI = dyn_cast(PTTFI->getOperand())) - if (TFTPI->getOperand().getType() == PTTFI->getType()) + if (TFTPI->getOperand()->getType() == PTTFI->getType()) return TFTPI->getOperand(); return SILValue(); @@ -490,7 +479,7 @@ static SILValue simplifyBuiltin(BuiltinInst *BI) { // trunc(extOrBitCast(x)) -> x if (match(Op, m_ExtOrBitCast(m_SILValue(Result)))) { // Truncated back to the same bits we started with. - if (Result.getType() == BI->getType()) + if (Result->getType() == BI->getType()) return Result; } @@ -500,7 +489,7 @@ static SILValue simplifyBuiltin(BuiltinInst *BI) { m_ExtOrBitCast(m_SILValue(Result))), 0))) { // If the top bit of Result is known to be 0, then // it is safe to replace the whole pattern by original bits of x - if (Result.getType() == BI->getType()) { + if (Result->getType() == BI->getType()) { if (auto signBit = computeSignBit(Result)) if (!signBit.getValue()) return Result; @@ -524,11 +513,11 @@ static SILValue simplifyBuiltin(BuiltinInst *BI) { m_SILValue(val2)))))) { if (val2 == val3) - return val1.getDef(); + return val1; if (val1 == val3) - return val2.getDef(); + return val2; if (val1 == val2) - return val3.getDef(); + return val3; } } } @@ -640,7 +629,7 @@ SILValue InstSimplifier::simplifyOverflowBuiltin(BuiltinInst *BI) { SILValue Result; // CheckedConversion(ExtOrBitCast(x)) -> x if (match(BI, m_CheckedConversion(m_ExtOrBitCast(m_SILValue(Result))))) - if (Result.getType() == BI->getType().getTupleElementType(0)) { + if (Result->getType() == BI->getType().getTupleElementType(0)) { assert (!computeSignBit(Result).getValue() && "Sign bit should be 0"); return Result; } @@ -654,7 +643,7 @@ SILValue InstSimplifier::simplifyOverflowBuiltin(BuiltinInst *BI) { SILValue Result; // CheckedTrunc(Ext(x)) -> x if (match(BI, m_CheckedTrunc(m_Ext(m_SILValue(Result))))) - if (Result.getType() == BI->getType().getTupleElementType(0)) + if (Result->getType() == BI->getType().getTupleElementType(0)) if (auto signBit = computeSignBit(Result)) if (!signBit.getValue()) return Result; diff --git a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp index 090892353446b..ed2f5e271cd5e 100644 --- a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp @@ -1,8 +1,8 @@ -//===---------- TypeExpansionAnalysis.cpp - Type Expansion Analysis -------===// +//===--- TypeExpansionAnalysis.cpp - Type Expansion Analysis --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,9 +23,8 @@ using namespace swift; // memory usage of this cache. static const int TypeExpansionAnalysisMaxCacheSize = 4096; -const ProjectionPathList & -TypeExpansionAnalysis::getTypeExpansionProjectionPaths(SILType B, SILModule *Mod, - TEKind Kind) { +const NewProjectionPathList & +TypeExpansionAnalysis::getTypeExpansion(SILType B, SILModule *Mod, TEKind Kind){ // Which cache we should be looking up. bool IsLeaf = Kind == TEKind::TELeaf; TypeExpansionMap &Cache = IsLeaf ? TELeafCache : TENodeCache; @@ -43,12 +42,12 @@ TypeExpansionAnalysis::getTypeExpansionProjectionPaths(SILType B, SILModule *Mod // Build the type expansion for the leaf nodes. if (IsLeaf) { - ProjectionPath::expandTypeIntoLeafProjectionPaths(B, Mod, Cache[B]); + NewProjectionPath::expandTypeIntoLeafProjectionPaths(B, Mod, Cache[B]); return Cache[B]; } // Build the type expansion for the internal and leaf nodes. - ProjectionPath::expandTypeIntoNodeProjectionPaths(B, Mod, Cache[B]); + NewProjectionPath::expandTypeIntoNodeProjectionPaths(B, Mod, Cache[B]); return Cache[B]; } diff --git a/lib/SILOptimizer/Analysis/ValueTracking.cpp b/lib/SILOptimizer/Analysis/ValueTracking.cpp index a476b475442a3..f2798b11e749c 100644 --- a/lib/SILOptimizer/Analysis/ValueTracking.cpp +++ b/lib/SILOptimizer/Analysis/ValueTracking.cpp @@ -1,8 +1,8 @@ -//===-- ValueTracking.h - SIL Value Tracking Analysis ----------*- C++ -*--===// +//===--- ValueTracking.cpp - SIL Value Tracking Analysis ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,350 +16,52 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Utils/Local.h" #include "swift/SIL/PatternMatch.h" #include "llvm/Support/Debug.h" using namespace swift; using namespace swift::PatternMatch; -/// Strip off casts/indexing insts/address projections from V until there is -/// nothing left to strip. -/// FIXME: Maybe put this on SILValue? -/// FIXME: Why don't we strip projections after stripping indexes? -SILValue swift::getUnderlyingObject(SILValue V) { - while (true) { - SILValue V2 = V.stripCasts().stripAddressProjections().stripIndexingInsts(); - if (V2 == V) - return V2; - V = V2; - } -} - -/// Returns true if the ValueBase inside V is an apply whose callee is a no read -/// builtin. -static bool isNoReadBuiltinInst(SILValue V) { - auto *BI = dyn_cast(V); - return BI && !BI->mayReadOrWriteMemory(); -} - -/// Is Inst an instruction which escapes if and only if one of its results -/// escape? -static bool isTransitiveEscapeInst(SILInstruction *Inst) { - switch (Inst->getKind()) { - case ValueKind::AllocBoxInst: - case ValueKind::AllocExistentialBoxInst: - case ValueKind::AllocRefInst: - case ValueKind::AllocRefDynamicInst: - case ValueKind::AllocStackInst: - case ValueKind::AllocValueBufferInst: - case ValueKind::BuiltinInst: - case ValueKind::ApplyInst: - case ValueKind::TryApplyInst: - case ValueKind::WitnessMethodInst: - case ValueKind::CopyAddrInst: - case ValueKind::RetainValueInst: - case ValueKind::DeallocBoxInst: - case ValueKind::DeallocExistentialBoxInst: - case ValueKind::DeallocRefInst: - case ValueKind::DeallocPartialRefInst: - case ValueKind::DeallocStackInst: - case ValueKind::DeallocValueBufferInst: - case ValueKind::DebugValueAddrInst: - case ValueKind::DebugValueInst: - case ValueKind::DestroyAddrInst: - case ValueKind::ReleaseValueInst: - case ValueKind::AutoreleaseValueInst: - case ValueKind::FloatLiteralInst: - case ValueKind::FunctionRefInst: - case ValueKind::IntegerLiteralInst: - case ValueKind::LoadInst: - case ValueKind::LoadUnownedInst: - case ValueKind::LoadWeakInst: - case ValueKind::MetatypeInst: - case ValueKind::ObjCProtocolInst: - case ValueKind::GlobalAddrInst: - case ValueKind::StoreInst: - case ValueKind::StoreUnownedInst: - case ValueKind::StoreWeakInst: - case ValueKind::StringLiteralInst: - case ValueKind::CopyBlockInst: - case ValueKind::StrongReleaseInst: - case ValueKind::StrongPinInst: // Pin handle is independently managed - case ValueKind::StrongRetainInst: - case ValueKind::StrongRetainUnownedInst: - case ValueKind::StrongUnpinInst: - case ValueKind::UnownedReleaseInst: - case ValueKind::UnownedRetainInst: - case ValueKind::IsUniqueInst: - case ValueKind::IsUniqueOrPinnedInst: - case ValueKind::InjectEnumAddrInst: - case ValueKind::DeinitExistentialAddrInst: - case ValueKind::UnreachableInst: - case ValueKind::IsNonnullInst: - case ValueKind::CondFailInst: - case ValueKind::DynamicMethodBranchInst: - case ValueKind::ReturnInst: - case ValueKind::ThrowInst: - case ValueKind::FixLifetimeInst: - return false; - - case ValueKind::AddressToPointerInst: - case ValueKind::ValueMetatypeInst: - case ValueKind::BranchInst: - case ValueKind::CheckedCastBranchInst: - case ValueKind::CheckedCastAddrBranchInst: - case ValueKind::ClassMethodInst: - case ValueKind::CondBranchInst: - case ValueKind::ConvertFunctionInst: - case ValueKind::DynamicMethodInst: - case ValueKind::EnumInst: - case ValueKind::IndexAddrInst: - case ValueKind::IndexRawPointerInst: - case ValueKind::InitBlockStorageHeaderInst: - case ValueKind::InitEnumDataAddrInst: - case ValueKind::InitExistentialAddrInst: - case ValueKind::InitExistentialMetatypeInst: - case ValueKind::InitExistentialRefInst: - case ValueKind::ObjCExistentialMetatypeToObjectInst: - case ValueKind::ObjCMetatypeToObjectInst: - case ValueKind::ObjCToThickMetatypeInst: - case ValueKind::UncheckedRefCastInst: - case ValueKind::UncheckedRefCastAddrInst: - case ValueKind::UncheckedAddrCastInst: - case ValueKind::UncheckedTrivialBitCastInst: - case ValueKind::UncheckedBitwiseCastInst: - case ValueKind::MarkDependenceInst: - case ValueKind::OpenExistentialAddrInst: - case ValueKind::OpenExistentialMetatypeInst: - case ValueKind::OpenExistentialRefInst: - case ValueKind::OpenExistentialBoxInst: - case ValueKind::PartialApplyInst: - case ValueKind::ProjectBoxInst: - case ValueKind::ProjectValueBufferInst: - case ValueKind::PointerToAddressInst: - case ValueKind::PointerToThinFunctionInst: - case ValueKind::ProjectBlockStorageInst: - case ValueKind::ExistentialMetatypeInst: - case ValueKind::RawPointerToRefInst: - case ValueKind::RefElementAddrInst: - case ValueKind::RefToRawPointerInst: - case ValueKind::RefToUnmanagedInst: - case ValueKind::RefToUnownedInst: - case ValueKind::SelectEnumInst: - case ValueKind::SelectEnumAddrInst: - case ValueKind::SelectValueInst: - case ValueKind::StructElementAddrInst: - case ValueKind::StructExtractInst: - case ValueKind::StructInst: - case ValueKind::SuperMethodInst: - case ValueKind::SwitchEnumAddrInst: - case ValueKind::SwitchEnumInst: - case ValueKind::SwitchValueInst: - case ValueKind::UncheckedEnumDataInst: - case ValueKind::UncheckedTakeEnumDataAddrInst: - case ValueKind::ThickToObjCMetatypeInst: - case ValueKind::ThinFunctionToPointerInst: - case ValueKind::ThinToThickFunctionInst: - case ValueKind::TupleElementAddrInst: - case ValueKind::TupleExtractInst: - case ValueKind::TupleInst: - case ValueKind::UnconditionalCheckedCastInst: - case ValueKind::UnconditionalCheckedCastAddrInst: - case ValueKind::UnmanagedToRefInst: - case ValueKind::UnownedToRefInst: - case ValueKind::UpcastInst: - case ValueKind::RefToBridgeObjectInst: - case ValueKind::BridgeObjectToRefInst: - case ValueKind::BridgeObjectToWordInst: - return true; - - case ValueKind::AssignInst: - case ValueKind::MarkFunctionEscapeInst: - case ValueKind::MarkUninitializedInst: - llvm_unreachable("Invalid in canonical SIL."); - - case ValueKind::SILArgument: - case ValueKind::SILUndef: - llvm_unreachable("These do not use other values."); - } -} - -/// Maximum amount of ValueCapture queries. -static unsigned const ValueCaptureSearchThreshold = 32; - -namespace { - -/// Are there any uses that should be ignored as capture uses. -/// -/// TODO: Expand this if we ever do the store of pointer analysis mentioned in -/// Basic AA. -enum CaptureException : unsigned { - None=0, - ReturnsCannotCapture=1, -}; - -} // end anonymous namespace - -/// Returns true if V is a value that is used in a manner such that we know its -/// captured or we don't understand whether or not it was captured. In such a -/// case to be conservative, we must assume it is captured. -/// FIXME: Maybe put this on SILValue? -static bool valueMayBeCaptured(SILValue V, CaptureException Exception) { - llvm::SmallVector Worklist; - llvm::SmallPtrSet Visited; - unsigned Count = 0; - - DEBUG(llvm::dbgs() << " Checking for capture.\n"); - - - // All all uses of V to the worklist. - for (auto *UI : V.getUses()) { - // If we have more uses than the threshold, be conservative and bail so we - // don't use too much compile time. - if (Count++ >= ValueCaptureSearchThreshold) - return true; - Visited.insert(UI); - Worklist.push_back(UI); - } - - // Until the worklist is empty... - while (!Worklist.empty()) { - // Pop off an operand and grab the operand's user... - Operand *Op = Worklist.pop_back_val(); - SILInstruction *Inst = Op->getUser(); - - DEBUG(llvm::dbgs() << " Visiting: " << *Inst); - - // If Inst is an instruction with the transitive escape property, V escapes - // if and only if the results of Inst escape as well. - if (isTransitiveEscapeInst(Inst)) { - DEBUG(llvm::dbgs() << " Found transitive escape " - "instruction!\n"); - for (auto *UI : Inst->getUses()) { - // If we have more uses than the threshold, be conservative and bail - // so we don't use too much compile time. - if (Count++ >= ValueCaptureSearchThreshold) - return true; - - if (Visited.insert(UI).second) { - Worklist.push_back(UI); - } - } - continue; - } - - // An apply of a builtin that does not read memory can not capture a value. - // - // TODO: Use analysis of the other function perhaps to see if it captures - // memory in some manner? - // TODO: Add in knowledge about how parameters work on swift to make this - // more aggressive. - if (isNoReadBuiltinInst(Inst)) - continue; - - // Loading from a pointer does not cause it to be captured. - if (isa(Inst)) - continue; - - // If we have a store and are storing into the pointer, this is not a - // capture. Otherwise it is safe. - if (auto *SI = dyn_cast(Inst)) { - if (SI->getDest() == Op->get()) { - continue; - } else { - return true; - } - } - - // Deallocation instructions don't capture. - if (isa(Inst)) - continue; - - // Debug instructions don't capture. - if (isa(Inst) || isa(Inst)) - continue; - - // RefCountOperations don't capture. - // - // The release case is true since Swift does not allow destructors to - // resurrect objects. This is enforced via a runtime failure. - if (isa(Inst)) - continue; - - // If we have a return instruction and we are assuming that returns don't - // capture, we are safe. - if (Exception == CaptureException::ReturnsCannotCapture && - isa(Inst)) - continue; - - // We could not prove that Inst does not capture V. Be conservative and - // return true. - DEBUG(llvm::dbgs() << " Could not prove that inst does not capture " - "V!\n"); - return true; - } - - // We successfully proved that V is not captured. Return false. - DEBUG(llvm::dbgs() << " V was not captured!\n"); - return false; -} - -bool swift::isNotAliasingArgument(SILValue V) { +bool swift::isNotAliasingArgument(SILValue V, + InoutAliasingAssumption isInoutAliasing) { auto *Arg = dyn_cast(V); - if (!Arg) + if (!Arg || !Arg->isFunctionArg()) return false; - return Arg->isFunctionArg() && V.getType().isAddress(); + return isNotAliasedIndirectParameter(Arg->getParameterInfo().getConvention(), + isInoutAliasing); } -/// Return true if the pointer is to a function-local object that never escapes -/// from the function. -bool swift::isNonEscapingLocalObject(SILValue V) { - // If this is a local allocation, or the result of a no read apply inst (which - // can not affect memory in the caller), check to see if the allocation - // escapes. - if (isa(*V) || isNoReadBuiltinInst(V)) - return !valueMayBeCaptured(V, CaptureException::ReturnsCannotCapture); - - // If this is a no alias argument then it has not escaped before entering the - // function. Check if it escapes inside the function. - if (isNotAliasingArgument(V)) - return !valueMayBeCaptured(V, CaptureException::ReturnsCannotCapture); - - // If this is an enum value. If it or its operand does not escape, it is - // local. - if (auto *EI = dyn_cast(V)) - return !EI->hasOperand() || - !valueMayBeCaptured(EI->getOperand(), - CaptureException::ReturnsCannotCapture); - - // Otherwise we could not prove that V is a non escaping local object. Be - // conservative and return false. - return false; +bool swift::pointsToLocalObject(SILValue V, + InoutAliasingAssumption isInoutAliasing) { + V = getUnderlyingObject(V); + return isa(V) || + isNotAliasingArgument(V, isInoutAliasing); } /// Check if the value \p Value is known to be zero, non-zero or unknown. IsZeroKind swift::isZeroValue(SILValue Value) { // Inspect integer literals. - if (auto *L = dyn_cast(Value.getDef())) { + if (auto *L = dyn_cast(Value)) { if (!L->getValue()) return IsZeroKind::Zero; return IsZeroKind::NotZero; } // Inspect Structs. - switch (Value.getDef()->getKind()) { + switch (Value->getKind()) { // Bitcast of zero is zero. case ValueKind::UncheckedTrivialBitCastInst: // Extracting from a zero class returns a zero. case ValueKind::StructExtractInst: - return isZeroValue(cast(Value.getDef())->getOperand(0)); + return isZeroValue(cast(Value)->getOperand(0)); default: break; } // Inspect casts. - if (auto *BI = dyn_cast(Value.getDef())) { + if (auto *BI = dyn_cast(Value)) { switch (BI->getBuiltinInfo().ID) { case BuiltinValueKind::IntToPtr: case BuiltinValueKind::PtrToInt: @@ -387,7 +89,7 @@ IsZeroKind swift::isZeroValue(SILValue Value) { } // Handle results of XXX_with_overflow arithmetic. - if (auto *T = dyn_cast(Value.getDef())) { + if (auto *T = dyn_cast(Value)) { // Make sure we are extracting the number value and not // the overflow flag. if (T->getFieldNo() != 0) @@ -401,9 +103,9 @@ IsZeroKind swift::isZeroValue(SILValue Value) { } //Inspect allocations and pointer literals. - if (isa(Value.getDef()) || - isa(Value.getDef()) || - isa(Value.getDef())) + if (isa(Value) || + isa(Value) || + isa(Value)) return IsZeroKind::NotZero; return IsZeroKind::Unknown; @@ -414,7 +116,7 @@ IsZeroKind swift::isZeroValue(SILValue Value) { Optional swift::computeSignBit(SILValue V) { SILValue Value = V; while (true) { - auto *Def = Value.getDef(); + ValueBase *Def = Value; // Inspect integer literals. if (auto *L = dyn_cast(Def)) { if (L->getValue().isNonNegative()) diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index 6a1c72ddb1dbb..9d9c244b1d990 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -365,33 +365,28 @@ computeNewArgInterfaceTypes(SILFunction *F, } } -static llvm::SmallString<64> getSpecializedName(SILFunction *F, - IndicesSet &PromotableIndices) { - llvm::SmallString<64> Name; +static std::string getSpecializedName(SILFunction *F, + IndicesSet &PromotableIndices) { + Mangle::Mangler M; + auto P = SpecializationPass::CapturePromotion; + FunctionSignatureSpecializationMangler FSSM(P, M, F); + CanSILFunctionType FTy = F->getLoweredFunctionType(); - { - llvm::raw_svector_ostream buffer(Name); - Mangle::Mangler M(buffer); - auto P = Mangle::SpecializationPass::CapturePromotion; - Mangle::FunctionSignatureSpecializationMangler FSSM(P, M, F); - CanSILFunctionType FTy = F->getLoweredFunctionType(); - - ArrayRef Parameters = FTy->getParameters(); - for (unsigned Index : indices(Parameters)) { - if (!PromotableIndices.count(Index)) - continue; - FSSM.setArgumentBoxToValue(Index); - } - - FSSM.mangle(); + ArrayRef Parameters = FTy->getParameters(); + for (unsigned Index : indices(Parameters)) { + if (!PromotableIndices.count(Index)) + continue; + FSSM.setArgumentBoxToValue(Index); } - return Name; + FSSM.mangle(); + + return M.finalize(); } /// \brief Create the function corresponding to the clone of the original /// closure with the signature modified to reflect promotable captures (which -/// are givien by PromotableIndices, such that each entry in the set is the +/// are given by PromotableIndices, such that each entry in the set is the /// index of the box containing the variable in the closure's argument list, and /// the address of the box's contents is the argument immediately following each /// box argument); does not actually clone the body of the function @@ -435,7 +430,8 @@ ClosureCloner::initCloned(SILFunction *Orig, StringRef ClonedName, Orig->getLocation(), Orig->isBare(), IsNotTransparent, Orig->isFragile(), Orig->isThunk(), Orig->getClassVisibility(), Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope()); - Fn->setSemanticsAttr(Orig->getSemanticsAttr()); + for (auto &Attr : Orig->getSemanticsAttrs()) + Fn->addSemanticsAttr(Attr); Fn->setDeclCtx(Orig->getDeclContext()); return Fn; } @@ -496,7 +492,6 @@ ClosureCloner::populateCloned() { void ClosureCloner::visitDebugValueAddrInst(DebugValueAddrInst *Inst) { SILValue Operand = Inst->getOperand(); if (auto *A = dyn_cast(Operand)) { - assert(Operand.getResultNumber() == 0); auto I = ProjectBoxArgumentMap.find(A); if (I != ProjectBoxArgumentMap.end()) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); @@ -517,13 +512,12 @@ void ClosureCloner::visitStrongReleaseInst(StrongReleaseInst *Inst) { SILValue Operand = Inst->getOperand(); if (SILArgument *A = dyn_cast(Operand)) { - assert(Operand.getResultNumber() == 0); auto I = BoxArgumentMap.find(A); if (I != BoxArgumentMap.end()) { // Releases of the box arguments get replaced with ReleaseValue of the new // object type argument. SILFunction &F = getBuilder().getFunction(); - auto &typeLowering = F.getModule().getTypeLowering(I->second.getType()); + auto &typeLowering = F.getModule().getTypeLowering(I->second->getType()); SILBuilderWithPostProcess B(this, Inst); typeLowering.emitReleaseValue(B, Inst->getLoc(), I->second); return; @@ -540,7 +534,6 @@ void ClosureCloner::visitStructElementAddrInst(StructElementAddrInst *Inst) { SILValue Operand = Inst->getOperand(); if (auto *A = dyn_cast(Operand)) { - assert(Operand.getResultNumber() == 0); auto I = ProjectBoxArgumentMap.find(A); if (I != ProjectBoxArgumentMap.end()) return; @@ -566,7 +559,6 @@ void ClosureCloner::visitLoadInst(LoadInst *Inst) { SILValue Operand = Inst->getOperand(); if (auto *A = dyn_cast(Operand)) { - assert(Operand.getResultNumber() == 0); auto I = ProjectBoxArgumentMap.find(A); if (I != ProjectBoxArgumentMap.end()) { // Loads of the address argument get eliminated completely; the uses of @@ -575,9 +567,7 @@ ClosureCloner::visitLoadInst(LoadInst *Inst) { return; } } else if (auto *SEAI = dyn_cast(Operand)) { - assert(Operand.getResultNumber() == 0); if (auto *A = dyn_cast(SEAI->getOperand())) { - assert(SEAI->getOperand().getResultNumber() == 0); auto I = ProjectBoxArgumentMap.find(A); if (I != ProjectBoxArgumentMap.end()) { // Loads of a struct_element_addr of an argument get replaced with @@ -730,9 +720,7 @@ examineAllocBoxInst(AllocBoxInst *ABI, ReachabilityInfo &RI, SmallVector Mutations; // Scan the box for interesting uses. - SILValue Box = ABI->getContainerResult(); - - for (Operand *O : Box.getUses()) { + for (Operand *O : ABI->getUses()) { if (auto *PAI = dyn_cast(O->getUser())) { unsigned OpNo = O->getOperandNumber(); assert(OpNo != 0 && "Alloc box used as callee of partial apply?"); @@ -744,7 +732,7 @@ examineAllocBoxInst(AllocBoxInst *ABI, ReachabilityInfo &RI, return false; auto Callee = PAI->getCallee(); - auto CalleeTy = Callee.getType().castTo(); + auto CalleeTy = Callee->getType().castTo(); // Bail if the signature has any dependent types as we do not // currently support these. @@ -782,33 +770,38 @@ examineAllocBoxInst(AllocBoxInst *ABI, ReachabilityInfo &RI, IM.insert(std::make_pair(PAI, Index)); continue; } + if (auto *PBI = dyn_cast(O->getUser())) { + // Check for mutations of the address component. + SILValue Addr = PBI; + // If the AllocBox is used by a mark_uninitialized, scan the MUI for + // interesting uses. + if (Addr->hasOneUse()) { + SILInstruction *SingleAddrUser = Addr->use_begin()->getUser(); + if (isa(SingleAddrUser)) + Addr = SILValue(SingleAddrUser); + } - // Verify that this this use does not otherwise allow the alloc_box to + for (Operand *AddrOp : Addr->getUses()) { + if (!isNonescapingUse(AddrOp, Mutations)) + return false; + } + continue; + } + // Verify that this use does not otherwise allow the alloc_box to // escape. if (!isNonescapingUse(O, Mutations)) return false; } - - // Check for mutations of the address component. - // If the AllocBox is used by a mark_uninitialized, scan the MUI for - // interesting uses. - SILValue Addr = ABI->getAddressResult(); - if (Addr.hasOneUse()) - if (auto MUI = dyn_cast(Addr.use_begin()->getUser())) - Addr = SILValue(MUI); - - for (Operand *O : Addr.getUses()) { - if (!isNonescapingUse(O, Mutations)) - return false; - } // Helper lambda function to determine if instruction b is strictly after // instruction a, assuming both are in the same basic block. auto isAfter = [](SILInstruction *a, SILInstruction *b) { - SILInstruction *f = &*b->getParent()->begin(); - while (b != f) { - b = b->getPrevNode(); - if (a == b) + auto fIter = b->getParent()->begin(); + auto bIter = b->getIterator(); + auto aIter = a->getIterator(); + while (bIter != fIter) { + --bIter; + if (aIter == bIter) return true; } return false; @@ -886,7 +879,6 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, SILModule &M = PAI->getModule(); auto *FRI = dyn_cast(PAI->getCallee()); - assert(FRI && PAI->getCallee().getResultNumber() == 0); // Clone the closure with the given promoted captures. SILFunction *ClonedFn = constructClonedFunction(PAI, FRI, PromotableIndices); @@ -896,12 +888,12 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, // closure. SILBuilderWithScope B(PAI); SILValue FnVal = B.createFunctionRef(PAI->getLoc(), ClonedFn); - SILType FnTy = FnVal.getType(); + SILType FnTy = FnVal->getType(); // Populate the argument list for a new partial_apply instruction, taking into // consideration any captures. auto CalleePInfo = - PAI->getCallee().getType().castTo()->getParameters(); + PAI->getCallee()->getType().castTo()->getParameters(); auto PInfo = PAI->getType().castTo()->getParameters(); unsigned FirstIndex = PInfo.size(); unsigned OpNo = 1, OpCount = PAI->getNumOperands(); @@ -910,11 +902,10 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, unsigned Index = OpNo - 1 + FirstIndex; if (PromotableIndices.count(Index)) { SILValue BoxValue = PAI->getOperand(OpNo); - assert(isa(BoxValue) && - BoxValue.getResultNumber() == 0); + AllocBoxInst *ABI = cast(BoxValue); SILParameterInfo CPInfo = CalleePInfo[Index]; - assert(CPInfo.getSILType() == BoxValue.getType() && + assert(CPInfo.getSILType() == BoxValue->getType() && "SILType of parameter info does not match type of parameter"); // Cleanup the captured argument. releasePartialApplyCapturedArg(B, PAI->getLoc(), BoxValue, @@ -922,15 +913,25 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, // Load and copy from the address value, passing the result as an argument // to the new closure. - SILValue Addr = cast(BoxValue)->getAddressResult(); - // If the address is marked uninitialized, load through the mark, so that - // DI can reason about it. - if (Addr.hasOneUse()) - if (auto MUI = dyn_cast( - Addr.use_begin()->getUser())) - Addr = SILValue(MUI); - - auto &typeLowering = M.getTypeLowering(Addr.getType()); + SILValue Addr; + for (Operand *BoxUse : ABI->getUses()) { + auto *PBI = dyn_cast(BoxUse->getUser()); + // If the address is marked uninitialized, load through the mark, so + // that DI can reason about it. + if (PBI && PBI->hasOneUse()) { + SILInstruction *PBIUser = PBI->use_begin()->getUser(); + if (isa(PBIUser)) + Addr = PBIUser; + break; + } + } + // We only reuse an existing project_box if it directly follows the + // alloc_box. This makes sure that the project_box dominates the + // partial_apply. + if (!Addr) + Addr = getOrCreateProjectBox(ABI); + + auto &typeLowering = M.getTypeLowering(Addr->getType()); Args.push_back( typeLowering.emitLoadOfCopy(B, PAI->getLoc(), Addr, IsNotTake)); ++NumCapturesPromoted; @@ -946,7 +947,7 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, auto *NewPAI = B.createPartialApply(PAI->getLoc(), FnVal, SubstFnTy, PAI->getSubstitutions(), Args, PAI->getType()); - SILValue(PAI, 0).replaceAllUsesWith(NewPAI); + PAI->replaceAllUsesWith(NewPAI); PAI->eraseFromParent(); if (FRI->use_empty()) { FRI->eraseFromParent(); @@ -956,8 +957,8 @@ processPartialApplyInst(PartialApplyInst *PAI, IndicesSet &PromotableIndices, } static void -constructMapFromPartialApplyToPromoteableIndices(SILFunction *F, - PartialApplyIndicesMap &Map) { +constructMapFromPartialApplyToPromotableIndices(SILFunction *F, + PartialApplyIndicesMap &Map) { ReachabilityInfo RS(F); // This is a map from each partial apply to a single index which is a @@ -985,7 +986,7 @@ processFunction(SILFunction *F, SmallVectorImpl &Worklist) { // This is a map from each partial apply to a set of indices of promotable // box variables. PartialApplyIndicesMap IndicesMap; - constructMapFromPartialApplyToPromoteableIndices(F, IndicesMap); + constructMapFromPartialApplyToPromotableIndices(F, IndicesMap); // Do the actual promotions; all promotions on a single partial_apply are // handled together. diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index 8a904a8aacd3d..8f2f6d4657bd8 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -1,8 +1,8 @@ -//===---- CapturePropagation.cpp - Propagate closure capture constants ----===// +//===--- CapturePropagation.cpp - Propagate closure capture constants -----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -65,14 +65,11 @@ static bool isConstant(SILValue V) { return V && isOptimizableConstant(V); } -static llvm::SmallString<64> getClonedName(PartialApplyInst *PAI, - SILFunction *F) { - llvm::SmallString<64> ClonedName; +static std::string getClonedName(PartialApplyInst *PAI, SILFunction *F) { - llvm::raw_svector_ostream buffer(ClonedName); - Mangle::Mangler M(buffer); - auto P = Mangle::SpecializationPass::CapturePropagation; - Mangle::FunctionSignatureSpecializationMangler Mangler(P, M, F); + Mangle::Mangler M; + auto P = SpecializationPass::CapturePropagation; + FunctionSignatureSpecializationMangler Mangler(P, M, F); // We know that all arguments are literal insts. auto Args = PAI->getArguments(); @@ -80,7 +77,7 @@ static llvm::SmallString<64> getClonedName(PartialApplyInst *PAI, Mangler.setArgumentConstantProp(i, getConstant(Args[i])); Mangler.mangle(); - return ClonedName; + return M.finalize(); } namespace { @@ -217,11 +214,11 @@ void CapturePropagationCloner::cloneBlocks( /// function body. SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI, SILFunction *OrigF) { - llvm::SmallString<64> Name = getClonedName(PAI, OrigF); + std::string Name = getClonedName(PAI, OrigF); // See if we already have a version of this function in the module. If so, // just return it. - if (auto *NewF = OrigF->getModule().lookUpFunction(Name.str())) { + if (auto *NewF = OrigF->getModule().lookUpFunction(Name)) { DEBUG(llvm::dbgs() << " Found an already specialized version of the callee: "; NewF->printName(llvm::dbgs()); llvm::dbgs() << "\n"); diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index ad72e7ee48518..f9b8889aa3d78 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -1,8 +1,8 @@ -//===---- ClosureSpecializer.cpp ------ Performs Closure Specialization----===// +//===--- ClosureSpecializer.cpp - Performs Closure Specialization ---------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -190,18 +190,18 @@ class CallSiteDescriptor { createNewClosure(SILBuilder &B, SILValue V, llvm::SmallVectorImpl &Args) const { if (isa(getClosure())) - return B.createPartialApply(getClosure()->getLoc(), V, V.getType(), {}, - Args, getClosure()->getType(0)); + return B.createPartialApply(getClosure()->getLoc(), V, V->getType(), {}, + Args, getClosure()->getType()); assert(isa(getClosure()) && "We only support partial_apply and thin_to_thick_function"); return B.createThinToThickFunction(getClosure()->getLoc(), V, - getClosure()->getType(0)); + getClosure()->getType()); } FullApplySite getApplyInst() const { return AI; } - void createName(llvm::SmallString<64> &NewName) const; + std::string createName() const; OperandValueArrayRef getArguments() const { if (auto *PAI = dyn_cast(getClosure())) @@ -288,7 +288,7 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc, for (auto Arg : CSDesc.getArguments()) { NewArgs.push_back(Arg); - SILType ArgTy = Arg.getType(); + SILType ArgTy = Arg->getType(); // If our argument is of trivial type, continue... if (ArgTy.isTrivial(M)) @@ -314,7 +314,7 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc, // executed more frequently than the closure (for example, if the closure is // created in a loop preheader and the callee taking the closure is executed // in the loop). In such a case we must keep the argument live across the - // call site of the callee and emit a matching retain for every innvocation + // call site of the callee and emit a matching retain for every invocation // of the callee. // // %closure = partial_apply (%arg) @@ -386,20 +386,21 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc, // AI from parent? } -void CallSiteDescriptor::createName(llvm::SmallString<64> &NewName) const { - llvm::raw_svector_ostream buffer(NewName); - Mangle::Mangler M(buffer); - auto P = Mangle::SpecializationPass::ClosureSpecializer; - Mangle::FunctionSignatureSpecializationMangler FSSM(P, M, getApplyCallee()); +std::string CallSiteDescriptor::createName() const { + Mangle::Mangler M; + auto P = SpecializationPass::ClosureSpecializer; + FunctionSignatureSpecializationMangler FSSM(P, M, getApplyCallee()); + if (auto *PAI = dyn_cast(getClosure())) { FSSM.setArgumentClosureProp(getClosureIndex(), PAI); FSSM.mangle(); - return; + return M.finalize(); } auto *TTTFI = cast(getClosure()); FSSM.setArgumentClosureProp(getClosureIndex(), TTTFI); FSSM.mangle(); + return M.finalize(); } void CallSiteDescriptor::extendArgumentLifetime(SILValue Arg) const { @@ -418,8 +419,7 @@ void CallSiteDescriptor::extendArgumentLifetime(SILValue Arg) const { static void specializeClosure(ClosureInfo &CInfo, CallSiteDescriptor &CallDesc) { - llvm::SmallString<64> NewFName; - CallDesc.createName(NewFName); + auto NewFName = CallDesc.createName(); DEBUG(llvm::dbgs() << " Perform optimizations with new name " << NewFName << '\n'); @@ -454,7 +454,7 @@ static bool isSupportedClosure(const SILInstruction *Closure) { // If any arguments are not objects, return false. This is a temporary // limitation. for (SILValue Arg : PAI->getArguments()) - if (!Arg.getType().isObject()) + if (!Arg->getType().isObject()) return false; // Ok, it is a closure we support, set Callee. @@ -559,7 +559,8 @@ ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc, ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(), ClosureUser, ClosureUser->getDebugScope()); Fn->setDeclCtx(ClosureUser->getDeclContext()); - Fn->setSemanticsAttr(ClosureUser->getSemanticsAttr()); + for (auto &Attr : ClosureUser->getSemanticsAttrs()) + Fn->addSemanticsAttr(Attr); return Fn; } @@ -721,7 +722,7 @@ void ClosureSpecializer::gatherCallSites( // Go through all uses of our closure. for (auto *Use : II.getUses()) { - // If this use use is not an apply inst or an apply inst with + // If this use is not an apply inst or an apply inst with // substitutions, there is nothing interesting for us to do, so // continue... auto AI = FullApplySite::isa(Use->getUser()); diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index f450ae759c9d2..b20b7bafdc2cb 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -87,7 +87,7 @@ class FunctionLivenessComputation { /// Gets or creates the MethodInfo for a vtable or witness table method. /// \p decl The method declaration. In case of a vtable method this is always - /// the most overriden method. + /// the most overridden method. MethodInfo *getMethodInfo(AbstractFunctionDecl *decl) { MethodInfo *&entry = MethodInfos[decl]; if (entry == nullptr) { @@ -188,7 +188,7 @@ class FunctionLivenessComputation { MethodInfo *mi = getMethodInfo(funcDecl); ClassDecl *MethodCl = nullptr; if (MI->getNumOperands() == 1) - MethodCl = MI->getOperand(0)->getType(0).getClassOrBoundGenericClass(); + MethodCl = MI->getOperand(0)->getType().getClassOrBoundGenericClass(); ensureAlive(mi, dyn_cast(funcDecl), MethodCl); } else if (auto *FRI = dyn_cast(&I)) { ensureAlive(FRI->getReferencedFunction()); @@ -389,7 +389,6 @@ class DeadFunctionElimination : FunctionLivenessComputation { F.dropAllReferences(); // Next step: delete all dead functions. - bool NeedUpdate = false; for (auto FI = Module->begin(), EI = Module->end(); FI != EI;) { SILFunction *F = &*FI; ++FI; @@ -397,7 +396,6 @@ class DeadFunctionElimination : FunctionLivenessComputation { DEBUG(llvm::dbgs() << " erase dead function " << F->getName() << "\n"); NumDeadFunc++; Module->eraseFunction(F); - NeedUpdate = true; DFEPass->invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything); } } @@ -446,7 +444,7 @@ class ExternalFunctionDefinitionsElimination : FunctionLivenessComputation { bool findAliveFunctions() { /// TODO: Once there is a proper support for IPO, /// bodies of all external functions can be removed. - /// Therefore there is no need for a livesness computation. + /// Therefore there is no need for a liveness computation. /// The next line can be just replaced by: /// return false; return FunctionLivenessComputation::findAliveFunctions(); diff --git a/lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp b/lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp index c8879c075e531..9eeaeab78181d 100644 --- a/lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp +++ b/lib/SILOptimizer/IPO/ExternalDefsToDecls.cpp @@ -1,8 +1,8 @@ -//===--- ExternalDefinitionsToDeclarations.cpp - external defs to decls ---===// +//===--- ExternalDefsToDecls.cpp - external defs to decls -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/IPO/FunctionSignatureOpts.cpp b/lib/SILOptimizer/IPO/FunctionSignatureOpts.cpp index 1b6a7c8b15d7d..b7bb1262fae33 100644 --- a/lib/SILOptimizer/IPO/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/IPO/FunctionSignatureOpts.cpp @@ -1,8 +1,8 @@ -//===-- FunctionSignatureOpts.cpp - Optimizes function signatures ---------===// +//===--- FunctionSignatureOpts.cpp - Optimizes function signatures --------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -101,7 +101,7 @@ getNonTrivialNonDebugReleaseUse(SILArgument *Arg) { } // Otherwise add all non-debug uses of I to the worklist. - for (Operand *I : getNonDebugUses(*U)) + for (Operand *I : getNonDebugUses(U)) Worklist.push_back(I->getUser()); } @@ -229,16 +229,16 @@ void ArgumentDescriptor::computeOptimizedInterfaceParams( return; } - // If this argument is live, but we can not optimize it. + // If this argument is live, but we cannot optimize it. if (!canOptimizeLiveArg()) { - DEBUG(llvm::dbgs() << " Can not optimize live arg!\n"); + DEBUG(llvm::dbgs() << " Cannot optimize live arg!\n"); Out.push_back(ParameterInfo); return; } - // If we can not explode this value, handle callee release and return. + // If we cannot explode this value, handle callee release and return. if (!shouldExplode()) { - DEBUG(llvm::dbgs() << " ProjTree can not explode arg.\n"); + DEBUG(llvm::dbgs() << " ProjTree cannot explode arg.\n"); // If we found a release in the callee in the last BB on an @owned // parameter, change the parameter to @guaranteed and continue... if (CalleeRelease) { @@ -345,7 +345,7 @@ unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder, // // TODO: This should not be necessary. if (CalleeRelease) { - SILType CalleeReleaseTy = CalleeRelease->getOperand(0).getType(); + SILType CalleeReleaseTy = CalleeRelease->getOperand(0)->getType(); CalleeRelease->setOperand( 0, SILUndef::get(CalleeReleaseTy, Builder.getModule())); @@ -397,8 +397,8 @@ unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder, // Replace all uses of the original arg with undef so it does not have any // uses. - SILValue OrigArg = SILValue(BB->getBBArg(OldArgOffset)); - OrigArg.replaceAllUsesWith(SILUndef::get(OrigArg.getType(), BB->getModule())); + SILArgument *OrigArg = BB->getBBArg(OldArgOffset); + OrigArg->replaceAllUsesWith(SILUndef::get(OrigArg->getType(), BB->getModule())); // Now erase the old argument since it does not have any uses. We also // decrement ArgOffset since we have one less argument now. @@ -409,19 +409,14 @@ unsigned ArgumentDescriptor::updateOptimizedBBArgs(SILBuilder &Builder, } //===----------------------------------------------------------------------===// -// Function Analyzer +// Signature Optimizer //===----------------------------------------------------------------------===// namespace { -template -inline T1 getFirstPairElt(const std::pair &P) { - return P.first; -} - /// A class that contains all analysis information we gather about our /// function. Also provides utility methods for creating the new empty function. -class FunctionAnalyzer { +class SignatureOptimizer { llvm::BumpPtrAllocator &Allocator; RCIdentityFunctionInfo *RCIA; @@ -433,9 +428,6 @@ class FunctionAnalyzer { /// generic argument of the callee. bool MayBindDynamicSelf; - /// Did we ascertain that we can optimize this function? - bool ShouldOptimize; - /// Did we change the self argument. If so we need to change the calling /// convention 'method' to 'freestanding'. bool HaveModifiedSelfArgument; @@ -445,29 +437,28 @@ class FunctionAnalyzer { llvm::SmallVector ArgDescList; public: - ArrayRef getArgList() const { return ArgDescList; } - FunctionAnalyzer() = delete; - FunctionAnalyzer(const FunctionAnalyzer &) = delete; - FunctionAnalyzer(FunctionAnalyzer &&) = delete; + SignatureOptimizer() = delete; + SignatureOptimizer(const SignatureOptimizer &) = delete; + SignatureOptimizer(SignatureOptimizer &&) = delete; - FunctionAnalyzer(llvm::BumpPtrAllocator &Allocator, - RCIdentityFunctionInfo *RCIA, SILFunction *F) + SignatureOptimizer(llvm::BumpPtrAllocator &Allocator, + RCIdentityFunctionInfo *RCIA, SILFunction *F) : Allocator(Allocator), RCIA(RCIA), F(F), - MayBindDynamicSelf(computeMayBindDynamicSelf(F)), ShouldOptimize(false), + MayBindDynamicSelf(computeMayBindDynamicSelf(F)), HaveModifiedSelfArgument(false), ArgDescList() {} /// Analyze the given function. bool analyze(); - /// Returns the managled name of the function that should be generated from + /// Returns the mangled name of the function that should be generated from /// this function analyzer. - llvm::SmallString<64> getOptimizedName(); + std::string getOptimizedName(); /// Create a new empty function with the optimized signature found by this /// analysis. /// /// *NOTE* This occurs in the same module as F. - SILFunction *createEmptyFunctionWithOptimizedSig(llvm::SmallString<64> &Name); + SILFunction *createEmptyFunctionWithOptimizedSig(const std::string &Name); ArrayRef getArgDescList() const { return ArgDescList; } MutableArrayRef getArgDescList() { return ArgDescList; } @@ -492,7 +483,7 @@ class FunctionAnalyzer { /// This function goes through the arguments of F and sees if we have anything /// to optimize in which case it returns true. If we have nothing to optimize, /// it returns false. -bool FunctionAnalyzer::analyze() { +bool SignatureOptimizer::analyze() { // For now ignore functions with indirect results. if (F->getLoweredFunctionType()->hasIndirectResult()) return false; @@ -505,6 +496,9 @@ bool FunctionAnalyzer::analyze() { ConsumedArgToEpilogueReleaseMatcher ArgToThrowReleaseMap( RCIA, F, ConsumedArgToEpilogueReleaseMatcher::ExitKind::Throw); + // Did we decide we should optimize any parameter? + bool ShouldOptimize = false; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { ArgumentDescriptor A(Allocator, Args[i]); bool HaveOptimizedArg = false; @@ -512,7 +506,7 @@ bool FunctionAnalyzer::analyze() { bool isABIRequired = isArgumentABIRequired(Args[i]); auto OnlyRelease = getNonTrivialNonDebugReleaseUse(Args[i]); - // If this argument is not ABI required and has not uses except for debug + // If this argument is not ABI required and has no uses except for debug // instructions, remove it. if (!isABIRequired && OnlyRelease && OnlyRelease.getValue().isNull()) { A.IsDead = true; @@ -568,7 +562,7 @@ bool FunctionAnalyzer::analyze() { // Creating the New Function //===----------------------------------------------------------------------===// -CanSILFunctionType FunctionAnalyzer::createOptimizedSILFunctionType() { +CanSILFunctionType SignatureOptimizer::createOptimizedSILFunctionType() { const ASTContext &Ctx = F->getModule().getASTContext(); CanSILFunctionType FTy = F->getLoweredFunctionType(); @@ -594,8 +588,8 @@ CanSILFunctionType FunctionAnalyzer::createOptimizedSILFunctionType() { InterfaceResult, InterfaceErrorResult, Ctx); } -SILFunction *FunctionAnalyzer::createEmptyFunctionWithOptimizedSig( - llvm::SmallString<64> &NewFName) { +SILFunction *SignatureOptimizer::createEmptyFunctionWithOptimizedSig( + const std::string &NewFName) { SILModule &M = F->getModule(); // Create the new optimized function type. @@ -612,8 +606,9 @@ SILFunction *FunctionAnalyzer::createEmptyFunctionWithOptimizedSig( // Array semantic clients rely on the signature being as in the original // version. - if (!F->getSemanticsAttr().startswith("array.")) - NewF->setSemanticsAttr(F->getSemanticsAttr()); + for (auto &Attr : F->getSemanticsAttrs()) + if (!StringRef(Attr).startswith("array.")) + NewF->addSemanticsAttr(Attr); return NewF; } @@ -622,38 +617,33 @@ SILFunction *FunctionAnalyzer::createEmptyFunctionWithOptimizedSig( // Mangling //===----------------------------------------------------------------------===// -llvm::SmallString<64> FunctionAnalyzer::getOptimizedName() { - llvm::SmallString<64> Name; - - { - llvm::raw_svector_ostream buffer(Name); - Mangle::Mangler M(buffer); - auto P = Mangle::SpecializationPass::FunctionSignatureOpts; - Mangle::FunctionSignatureSpecializationMangler FSSM(P, M, F); - - for (unsigned i : indices(ArgDescList)) { - const ArgumentDescriptor &Arg = ArgDescList[i]; - if (Arg.IsDead) { - FSSM.setArgumentDead(i); - } +std::string SignatureOptimizer::getOptimizedName() { + Mangle::Mangler M; + auto P = SpecializationPass::FunctionSignatureOpts; + FunctionSignatureSpecializationMangler FSSM(P, M, F); - // If we have an @owned argument and found a callee release for it, - // convert the argument to guaranteed. - if (Arg.CalleeRelease) { - FSSM.setArgumentOwnedToGuaranteed(i); - } + for (unsigned i : indices(ArgDescList)) { + const ArgumentDescriptor &Arg = ArgDescList[i]; + if (Arg.IsDead) { + FSSM.setArgumentDead(i); + } - // If this argument is not dead and we can explode it, add 's' to the - // mangling. - if (Arg.shouldExplode() && !Arg.IsDead) { - FSSM.setArgumentSROA(i); - } + // If we have an @owned argument and found a callee release for it, + // convert the argument to guaranteed. + if (Arg.CalleeRelease) { + FSSM.setArgumentOwnedToGuaranteed(i); } - FSSM.mangle(); + // If this argument is not dead and we can explode it, add 's' to the + // mangling. + if (Arg.shouldExplode() && !Arg.IsDead) { + FSSM.setArgumentSROA(i); + } } - return Name; + FSSM.mangle(); + + return M.finalize(); } //===----------------------------------------------------------------------===// @@ -662,7 +652,7 @@ llvm::SmallString<64> FunctionAnalyzer::getOptimizedName() { /// This function takes in OldF and all callsites of OldF and rewrites the /// callsites to call the new function. -static void rewriteApplyInstToCallNewFunction(FunctionAnalyzer &Analyzer, +static void rewriteApplyInstToCallNewFunction(SignatureOptimizer &Optimizer, SILFunction *NewF, const ApplyList &CallSites) { for (auto FAS : CallSites) { @@ -674,7 +664,7 @@ static void rewriteApplyInstToCallNewFunction(FunctionAnalyzer &Analyzer, // Create the args for the new apply, ignoring any dead arguments. llvm::SmallVector NewArgs; - ArrayRef ArgDescs = Analyzer.getArgDescList(); + ArrayRef ArgDescs = Optimizer.getArgDescList(); for (auto &ArgDesc : ArgDescs) { ArgDesc.addCallerArgs(Builder, FAS, NewArgs); } @@ -686,18 +676,17 @@ static void rewriteApplyInstToCallNewFunction(FunctionAnalyzer &Analyzer, SILLocation Loc = AI->getLoc(); // Create the new apply. - SILInstruction *NewAI; if (ApplyInst *RealAI = dyn_cast(AI)) { - NewAI = Builder.createApply(Loc, FRI, LoweredType, ResultType, - ArrayRef(), NewArgs, - RealAI->isNonThrowing()); + auto *NewAI = Builder.createApply(Loc, FRI, LoweredType, ResultType, + ArrayRef(), NewArgs, + RealAI->isNonThrowing()); // Replace all uses of the old apply with the new apply. AI->replaceAllUsesWith(NewAI); } else { auto *TAI = cast(AI); - NewAI = Builder.createTryApply(Loc, FRI, LoweredType, - ArrayRef(), NewArgs, - TAI->getNormalBB(), TAI->getErrorBB()); + Builder.createTryApply(Loc, FRI, LoweredType, + ArrayRef(), NewArgs, + TAI->getNormalBB(), TAI->getErrorBB()); Builder.setInsertionPoint(TAI->getErrorBB(), TAI->getErrorBB()->begin()); // If we have any arguments that were consumed but are now guaranteed, @@ -729,7 +718,7 @@ static void rewriteApplyInstToCallNewFunction(FunctionAnalyzer &Analyzer, } static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF, - FunctionAnalyzer &Analyzer) { + SignatureOptimizer &Optimizer) { // TODO: What is the proper location to use here? SILLocation Loc = BB->getParent()->getLocation(); SILBuilder Builder(BB); @@ -739,7 +728,7 @@ static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF, // Create the args for the thunk's apply, ignoring any dead arguments. llvm::SmallVector ThunkArgs; - ArrayRef ArgDescs = Analyzer.getArgDescList(); + ArrayRef ArgDescs = Optimizer.getArgDescList(); for (auto &ArgDesc : ArgDescs) { ArgDesc.addThunkArgs(Builder, BB, ThunkArgs); } @@ -800,15 +789,15 @@ static void createThunkBody(SILBasicBlock *BB, SILFunction *NewF, static SILFunction * moveFunctionBodyToNewFunctionWithName(SILFunction *F, - llvm::SmallString<64> &NewFName, - FunctionAnalyzer &Analyzer) { + const std::string &NewFName, + SignatureOptimizer &Optimizer) { // First we create an empty function (i.e. no BB) whose function signature has // had its arity modified. // // We only do this to remove dead arguments. All other function signature // optimization is done later by modifying the function signature elements // themselves. - SILFunction *NewF = Analyzer.createEmptyFunctionWithOptimizedSig(NewFName); + SILFunction *NewF = Optimizer.createEmptyFunctionWithOptimizedSig(NewFName); // Then we transfer the body of F to NewF. At this point, the arguments of the // first BB will not match. NewF->spliceBody(F); @@ -816,7 +805,7 @@ moveFunctionBodyToNewFunctionWithName(SILFunction *F, // Then perform any updates to the arguments of NewF. SILBasicBlock *NewFEntryBB = &*NewF->begin(); - MutableArrayRef ArgDescs = Analyzer.getArgDescList(); + MutableArrayRef ArgDescs = Optimizer.getArgDescList(); unsigned ArgOffset = 0; SILBuilder Builder(NewFEntryBB->begin()); Builder.setCurrentDebugScope(NewFEntryBB->getParent()->getDebugScope()); @@ -834,7 +823,7 @@ moveFunctionBodyToNewFunctionWithName(SILFunction *F, for (auto &ArgDesc : ArgDescs) { ThunkBody->createBBArg(ArgDesc.ParameterInfo.getSILType(), ArgDesc.Decl); } - createThunkBody(ThunkBody, NewF, Analyzer); + createThunkBody(ThunkBody, NewF, Optimizer); F->setThunk(IsThunk); assert(F->getDebugScope()->SILFn != NewF->getDebugScope()->SILFn); @@ -857,13 +846,9 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA, assert(!CallSites.empty() && "Unexpected empty set of call sites!"); - // An array containing our ArgumentDescriptor objects that contain information - // from our analysis. - llvm::SmallVector Arguments; - // Analyze function arguments. If there is no work to be done, exit early. - FunctionAnalyzer Analyzer(BPA, RCIA, F); - if (!Analyzer.analyze()) { + SignatureOptimizer Optimizer(BPA, RCIA, F); + if (!Optimizer.analyze()) { DEBUG(llvm::dbgs() << " Has no optimizable arguments... " "bailing...\n"); return false; @@ -874,7 +859,7 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA, ++NumFunctionSignaturesOptimized; - llvm::SmallString<64> NewFName = Analyzer.getOptimizedName(); + auto NewFName = Optimizer.getOptimizedName(); // If we already have a specialized version of this function, do not // respecialize. For now just bail. @@ -888,13 +873,13 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA, // Otherwise, move F over to NewF. SILFunction *NewF = - moveFunctionBodyToNewFunctionWithName(F, NewFName, Analyzer); + moveFunctionBodyToNewFunctionWithName(F, NewFName, Optimizer); // And remove all Callee releases that we found and made redundant via owned // to guaranteed conversion. // // TODO: If more stuff needs to be placed here, refactor into its own method. - for (auto &A : Analyzer.getArgDescList()) { + for (auto &A : Optimizer.getArgDescList()) { if (A.CalleeRelease) { A.CalleeRelease->eraseFromParent(); if (A.CalleeReleaseInThrowBlock) { @@ -905,7 +890,7 @@ static bool optimizeFunctionSignature(llvm::BumpPtrAllocator &BPA, // Rewrite all apply insts calling F to call NewF. Update each call site as // appropriate given the form of function signature optimization performed. - rewriteApplyInstToCallNewFunction(Analyzer, NewF, CallSites); + rewriteApplyInstToCallNewFunction(Optimizer, NewF, CallSites); return true; } diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 1f2ef051590e0..1286d5f4989e7 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -1,8 +1,8 @@ -//===---------- SILGlobalOpt.cpp - Optimize global initializers -----------===// +//===--- GlobalOpt.cpp - Optimize global initializers ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -137,7 +137,7 @@ class InstructionsCloner : public SILClonerWithScopes { void postProcess(SILInstruction *Orig, SILInstruction *Cloned) { DestBB->push_back(Cloned); SILClonerWithScopes::postProcess(Orig, Cloned); - AvailVals.push_back(std::make_pair(Orig, SILValue(Cloned, 0))); + AvailVals.push_back(std::make_pair(Orig, Cloned)); } // Clone all instructions from Insns into DestBB @@ -164,7 +164,7 @@ void SILGlobalOpt::collectGlobalLoad(LoadInst *LI, SILGlobalVariable *SILG) { //assert(SILG->isLet()); // This is read from a let variable. - // Figure out if the value of this variable is statitcally known. + // Figure out if the value of this variable is statically known. GlobalLoadMap[SILG].push_back(LI); } @@ -195,13 +195,13 @@ static void removeToken(SILValue Op) { static SILFunction *genGetterFromInit(StoreInst *Store, SILGlobalVariable *SILG) { auto *varDecl = SILG->getDecl(); - llvm::SmallString<20> getterBuffer; - llvm::raw_svector_ostream getterStream(getterBuffer); - Mangle::Mangler getterMangler(getterStream); + + Mangle::Mangler getterMangler; getterMangler.mangleGlobalGetterEntity(varDecl); + auto getterName = getterMangler.finalize(); // Check if a getter was generated already. - if (auto *F = Store->getModule().lookUpFunction(getterStream.str())) + if (auto *F = Store->getModule().lookUpFunction(getterName)) return F; // Find the code that performs the initialization first. @@ -231,7 +231,7 @@ static SILFunction *genGetterFromInit(StoreInst *Store, ParameterConvention::Direct_Owned, { }, ResultInfo, None, Store->getModule().getASTContext()); auto *GetterF = Store->getModule().getOrCreateFunction(Store->getLoc(), - getterStream.str(), SILLinkage::PrivateExternal, LoweredType, + getterName, SILLinkage::PrivateExternal, LoweredType, IsBare_t::IsBare, IsTransparent_t::IsNotTransparent, IsFragile_t::IsFragile); GetterF->setDebugScope(Store->getFunction()->getDebugScope()); @@ -241,10 +241,16 @@ static SILFunction *genGetterFromInit(StoreInst *Store, Cloner.clone(); GetterF->setInlined(); - // Find the store instruction + // Find the store instruction and turn it into return. + // Remove the alloc_global instruction. auto BB = EntryBB; SILValue Val; - for (auto &I : *BB) { + for (auto II = BB->begin(), E = BB->end(); II != E;) { + auto &I = *II++; + if (isa(&I)) { + I.eraseFromParent(); + continue; + } if (StoreInst *SI = dyn_cast(&I)) { Val = SI->getSrc(); SILBuilderWithScope B(SI); @@ -343,10 +349,10 @@ static bool isAvailabilityCheck(SILBasicBlock *BB) { return false; SILFunction *F = AI->getCalleeFunction(); - if (!F || !F->hasDefinedSemantics()) + if (!F || !F->hasSemanticsAttrs()) return false; - - return F->getSemanticsString().startswith("availability"); + + return F->hasSemanticsAttrThatStartsWith("availability"); } /// Returns true if there are any availability checks along the dominator tree @@ -457,13 +463,13 @@ void SILGlobalOpt::placeInitializers(SILFunction *InitF, /// Create a getter function from the initializer function. static SILFunction *genGetterFromInit(SILFunction *InitF, VarDecl *varDecl) { // Generate a getter from the global init function without side-effects. - llvm::SmallString<20> getterBuffer; - llvm::raw_svector_ostream getterStream(getterBuffer); - Mangle::Mangler getterMangler(getterStream); + + Mangle::Mangler getterMangler; getterMangler.mangleGlobalGetterEntity(varDecl); + auto getterName = getterMangler.finalize(); // Check if a getter was generated already. - if (auto *F = InitF->getModule().lookUpFunction(getterStream.str())) + if (auto *F = InitF->getModule().lookUpFunction(getterName)) return F; auto refType = varDecl->getType().getCanonicalTypeOrNull(); @@ -475,7 +481,7 @@ static SILFunction *genGetterFromInit(SILFunction *InitF, VarDecl *varDecl) { ParameterConvention::Direct_Owned, { }, ResultInfo, None, InitF->getASTContext()); auto *GetterF = InitF->getModule().getOrCreateFunction(InitF->getLocation(), - getterStream.str(), SILLinkage::PrivateExternal, LoweredType, + getterName, SILLinkage::PrivateExternal, LoweredType, IsBare_t::IsBare, IsTransparent_t::IsNotTransparent, IsFragile_t::IsFragile); @@ -489,7 +495,13 @@ static SILFunction *genGetterFromInit(SILFunction *InitF, VarDecl *varDecl) { auto BB = EntryBB; SILValue Val; SILInstruction *Store; - for (auto &I : *BB) { + for (auto II = BB->begin(), E = BB->end(); II != E;) { + auto &I = *II++; + if (isa(&I)) { + I.eraseFromParent(); + continue; + } + if (StoreInst *SI = dyn_cast(&I)) { Val = SI->getSrc(); Store = SI; @@ -549,7 +561,7 @@ static bool isAssignedOnlyOnceInInitializer(SILGlobalVariable *SILG) { return false; } -/// Replace load sequence which may contian +/// Replace load sequence which may contain /// a chain of struct_element_addr followed by a load. /// The sequence is traversed starting from the load /// instruction. diff --git a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp index ebd7a3a7997e8..172c2e35c363c 100644 --- a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -35,7 +35,7 @@ namespace { /// The GlobalPropertyOpt performs an analysis on the whole module to determine /// the values of high-level properties. /// -/// Currently only one property is handled and thats the isNativeTypeChecked +/// Currently only one property is handled and that's the isNativeTypeChecked /// property for arrays. If the property can be proved to be true, the /// corresponding semantics-call is replaced by a true-literal. class GlobalPropertyOpt { @@ -70,11 +70,11 @@ class GlobalPropertyOpt { friend raw_ostream &operator<<(raw_ostream &os, const Entry &entry) { if (entry.Field) { os << "field " << entry.Field->getName() << '\n'; - } else if (!entry.Value.getDef()) { + } else if (!entry.Value) { os << "unknown-address\n"; - } else if (auto *Inst = dyn_cast(entry.Value.getDef())) { + } else if (auto *Inst = dyn_cast(entry.Value)) { os << Inst->getParent()->getParent()->getName() << ": " << entry.Value; - } else if (auto *Arg = dyn_cast(entry.Value.getDef())) { + } else if (auto *Arg = dyn_cast(entry.Value)) { os << Arg->getParent()->getParent()->getName() << ": " << entry.Value; } else { os << entry.Value; @@ -148,7 +148,7 @@ class GlobalPropertyOpt { return false; } - static bool canAddressEscape(SILValue V, bool acceptWrite); + static bool canAddressEscape(SILValue V, bool acceptStore); /// Gets the entry for a struct or class field. Entry *getFieldEntry(VarDecl *Field) { @@ -164,7 +164,7 @@ class GlobalPropertyOpt { /// Gets the entry for a value at an address, e.g. a struct/class field or /// an alloc_stack. Entry *getAddrEntry(SILValue value) { - ValueBase *def = value.getDef(); + ValueBase *def = value; if (auto *MDI = dyn_cast(def)) { return getAddrEntry(MDI->getOperand(0)); } @@ -174,7 +174,7 @@ class GlobalPropertyOpt { if (auto *SEI = dyn_cast(def)) { return getFieldEntry(SEI->getField()); } - if (isa(def) && value.getResultNumber() == 1) { + if (isa(def)) { Entry * &entry = ValueEntries[value]; if (!entry) { entry = new (EntryAllocator.Allocate()) Entry(value, nullptr); @@ -233,7 +233,7 @@ class GlobalPropertyOpt { /// Checks if an address value does escape. If \p acceptStore is false, then /// we handle a store to the address like if the address would escape. bool GlobalPropertyOpt::canAddressEscape(SILValue V, bool acceptStore) { - for (auto UI : V.getUses()) { + for (auto UI : V->getUses()) { auto *User = UI->getUser(); // These instructions do not cause the address to escape. @@ -307,22 +307,22 @@ void GlobalPropertyOpt::scanInstruction(swift::SILInstruction *Inst) { if (isArrayType(LI->getType())) { // Add a dependency from the value at the address to the loaded value. SILValue loadAddr = LI->getOperand(); - assert(loadAddr.getType().isAddress()); + assert(loadAddr->getType().isAddress()); addDependency(getAddrEntry(loadAddr), getValueEntry(LI)); return; } } else if (StoreInst *SI = dyn_cast(Inst)) { SILValue src = SI->getSrc(); - if (isArrayType(src.getType())) { + if (isArrayType(src->getType())) { // Add a dependency from the operand to the value at the store-address. // SILValue dst = SI->getDest(); - assert(dst.getType().isAddress()); + assert(dst->getType().isAddress()); addDependency(getValueEntry(src), getAddrEntry(dst)); return; } } else if (isa(Inst) || isa(Inst)) { - if (isArrayAddressType(Inst->getType(0))) { + if (isArrayAddressType(Inst->getType())) { // If the address of an array-field escapes, we give up for that field. if (canAddressEscape(Inst, true)) { setAddressEscapes(getAddrEntry(Inst)); @@ -331,7 +331,7 @@ void GlobalPropertyOpt::scanInstruction(swift::SILInstruction *Inst) { return; } } else if (StructExtractInst *SEI = dyn_cast(Inst)) { - if (isArrayType(SEI->getType(0))) { + if (isArrayType(SEI->getType())) { // Add a dependency from the field to the extracted value. VarDecl *Field = SEI->getField(); addDependency(getFieldEntry(Field), getValueEntry(SEI)); @@ -349,7 +349,7 @@ void GlobalPropertyOpt::scanInstruction(swift::SILInstruction *Inst) { // Add dependencies from array elements to the tuple itself. for (Operand &Op : TI->getAllOperands()) { SILValue V = Op.get(); - if (isArrayType(V.getType())) { + if (isArrayType(V->getType())) { addDependency(getValueEntry(V), getValueEntry(TI)); } } @@ -364,7 +364,7 @@ void GlobalPropertyOpt::scanInstruction(swift::SILInstruction *Inst) { for (auto I = Range.begin(), E = Range.end(); I != E; ++I, ++Index) { VarDecl *VD = *I; const Operand &Op = Operands[Index]; - if (isArrayType(Op.get().getType())) { + if (isArrayType(Op.get()->getType())) { addDependency(getValueEntry(Op.get()), getFieldEntry(VD)); } } @@ -376,12 +376,10 @@ void GlobalPropertyOpt::scanInstruction(swift::SILInstruction *Inst) { // For everything else which we didn't handle above: we set the property of // the instruction value to false. - for (int TI = 0, NumTypes = Inst->getNumTypes(); TI < NumTypes; ++TI) { - SILType Type = Inst->getType(TI); + if (SILType Type = Inst->getType()) { if (isArrayType(Type) || isTupleWithArray(Type.getSwiftRValueType())) { - SILValue RV(Inst, TI); - DEBUG(llvm::dbgs() << " value could be non-native array: " << *RV); - setNotNative(getValueEntry(RV)); + DEBUG(llvm::dbgs() << " value could be non-native array: " << *Inst); + setNotNative(getValueEntry(Inst)); } } } @@ -398,7 +396,7 @@ void GlobalPropertyOpt::scanInstructions() { int argIdx = 0; for (auto *BBArg : BB.getBBArgs()) { bool hasPreds = false; - SILType Type = BBArg->getType(0); + SILType Type = BBArg->getType(); if (isArrayType(Type) || isTupleWithArray(Type.getSwiftRValueType())) { for (auto *Pred : BB.getPreds()) { hasPreds = true; diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp index f7c9ec09f1e34..a34409d2080f6 100644 --- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp +++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp @@ -1,8 +1,8 @@ -//===---------- LetPropertiesOpt.cpp - Optimize let properties ------------===// +//===--- LetPropertiesOpts.cpp - Optimize let properties ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -98,7 +98,7 @@ class InstructionsCloner : public SILClonerWithScopes { Dest->getParent()->push_front(Cloned); Cloned->moveBefore(Dest); SILClonerWithScopes::postProcess(Orig, Cloned); - AvailVals.push_back(std::make_pair(Orig, SILValue(Cloned, 0))); + AvailVals.push_back(std::make_pair(Orig, Cloned)); } // Clone all instructions from Insns into DestBB @@ -222,12 +222,11 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property, /// Compare to SILValues structurally. static bool CmpSILValues(SILValue LHS, SILValue RHS) { - if (LHS.getResultNumber() != RHS.getResultNumber() || - LHS.getType() != RHS.getType()) + if (LHS->getType() != RHS->getType()) return false; - auto L = dyn_cast(LHS.getDef()); - return L->isIdenticalTo(dyn_cast(RHS.getDef()), CmpSILValues); + auto L = dyn_cast(LHS); + return L->isIdenticalTo(dyn_cast(RHS), CmpSILValues); }; /// Compare two sequences of SIL instructions. They should be structurally equivalent. diff --git a/lib/SILOptimizer/IPO/PerformanceInliner.cpp b/lib/SILOptimizer/IPO/PerformanceInliner.cpp index 14da742b83d1c..1a12963adf76c 100644 --- a/lib/SILOptimizer/IPO/PerformanceInliner.cpp +++ b/lib/SILOptimizer/IPO/PerformanceInliner.cpp @@ -1,8 +1,8 @@ -//===- PerformanceInliner.cpp - Basic cost based inlining for performance -===// +//===--- PerformanceInliner.cpp - Basic cost based performance inlining ---===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -74,6 +74,9 @@ namespace { // increasing the code size. const unsigned TrivialFunctionThreshold = 20; + // Configuration for the caller block limit. + const unsigned BlockLimitDenominator = 10000; + // Represents a value in integer constant evaluation. struct IntConst { IntConst() : isValid(false), isFromCaller(false) { } @@ -216,7 +219,7 @@ namespace { }; class SILPerformanceInliner { - /// The inline threashold. + /// The inline threshold. const int InlineCostThreshold; /// Specifies which functions not to inline, based on @_semantics and /// global_init attributes. @@ -234,7 +237,8 @@ namespace { bool isProfitableToInline(FullApplySite AI, unsigned loopDepthOfAI, DominanceAnalysis *DA, SILLoopAnalysis *LA, - ConstantTracker &constTracker); + ConstantTracker &constTracker, + unsigned &NumCallerBlocks); void visitColdBlocks(SmallVectorImpl &AppliesToInline, SILBasicBlock *root, DominanceInfo *DT); @@ -310,7 +314,7 @@ SILValue ConstantTracker::scanProjections(SILValue addr, SmallVectorImpl *Result) { for (;;) { if (Projection::isAddrProjection(addr)) { - SILInstruction *I = cast(addr.getDef()); + SILInstruction *I = cast(addr); if (Result) { Optional P = Projection::addressProjectionForInstruction(I); Result->push_back(P.getValue()); @@ -534,9 +538,11 @@ bool SILPerformanceInliner::hasInliningCycle(SILFunction *Caller, StringRef CallerName = Caller->getName(); StringRef CalleeName = Callee->getName(); - bool InlinedBefore = InlinedFunctions.count(std::make_pair(CallerName, CalleeName)); + bool InlinedBefore = + InlinedFunctions.count(std::make_pair(CallerName, CalleeName)); - // If the Callee was inlined into the Caller in previous inlining iterations then + // If the Callee was inlined into the Caller in previous inlining iterations + // then // we need to reject this inlining request to prevent a cycle. return InlinedBefore; } @@ -560,7 +566,7 @@ static bool calleeHasMinimalSelfRecursion(SILFunction *Callee) { return false; } -// Returns the callee of an apply_inst if it is basically inlinable. +// Returns the callee of an apply_inst if it is basically inlineable. SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) { SILFunction *Callee = AI.getCalleeFunction(); @@ -572,16 +578,16 @@ SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) { // Don't inline functions that are marked with the @_semantics or @effects // attribute if the inliner is asked not to inline them. - if (Callee->hasDefinedSemantics() || Callee->hasEffectsKind()) { + if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) { if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) { DEBUG(llvm::dbgs() << " FAIL: Function " << Callee->getName() << " has special semantics or effects attribute.\n"); return nullptr; } // The "availability" semantics attribute is treated like global-init. - if (Callee->hasDefinedSemantics() && + if (Callee->hasSemanticsAttrs() && WhatToInline != InlineSelection::Everything && - Callee->getSemanticsString().startswith("availability")) { + Callee->hasSemanticsAttrThatStartsWith("availability")) { return nullptr; } } else if (Callee->isGlobalInit()) { @@ -715,7 +721,7 @@ static SILBasicBlock *getTakenBlock(TermInst *term, if (CheckedCastBranchInst *CCB = dyn_cast(term)) { if (SILInstruction *def = constTracker.getDefInCaller(CCB->getOperand())) { if (UpcastInst *UCI = dyn_cast(def)) { - SILType castType = UCI->getOperand()->getType(0); + SILType castType = UCI->getOperand()->getType(); if (CCB->getCastType().isSuperclassOf(castType)) { return CCB->getSuccessBB(); } @@ -733,7 +739,8 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI, unsigned loopDepthOfAI, DominanceAnalysis *DA, SILLoopAnalysis *LA, - ConstantTracker &callerTracker) { + ConstantTracker &callerTracker, + unsigned &NumCallerBlocks) { SILFunction *Callee = AI.getCalleeFunction(); if (Callee->getInlineStrategy() == AlwaysInline) @@ -776,7 +783,8 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI, SILInstruction *def = constTracker.getDefInCaller(AI->getCallee()); if (def && (isa(def) || isa(def))) { - DEBUG(llvm::dbgs() << " Boost: apply const function at" << *AI); + DEBUG(llvm::dbgs() << " Boost: apply const function at" + << *AI); Benefit += ConstCalleeBenefit + loopDepth * LoopBenefitFactor; testThreshold *= 2; } @@ -805,6 +813,18 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI, // Only inline trivial functions into thunks (which will not increase the // code size). Threshold = TrivialFunctionThreshold; + } else { + // The default case. + // We reduce the benefit if the caller is too large. For this we use a + // cubic function on the number of caller blocks. This starts to prevent + // inlining at about 800 - 1000 caller blocks. + unsigned blockMinus = + (NumCallerBlocks * NumCallerBlocks) / BlockLimitDenominator * + NumCallerBlocks / BlockLimitDenominator; + if (Threshold > blockMinus + TrivialFunctionThreshold) + Threshold -= blockMinus; + else + Threshold = TrivialFunctionThreshold; } if (CalleeCost > Threshold) { @@ -814,6 +834,7 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI, } DEBUG(llvm::dbgs() << " YES: ready to inline, " "cost: " << CalleeCost << ", threshold: " << Threshold << "\n"); + NumCallerBlocks += Callee->size(); return true; } @@ -1011,6 +1032,8 @@ void SILPerformanceInliner::collectAppliesToInline( ConstantTracker constTracker(Caller); DominanceOrder domOrder(&Caller->front(), DT, Caller->size()); + unsigned NumCallerBlocks = Caller->size(); + // Go through all instructions and find candidates for inlining. // We do this in dominance order for the constTracker. SmallVector InitialCandidates; @@ -1029,7 +1052,8 @@ void SILPerformanceInliner::collectAppliesToInline( auto *Callee = getEligibleFunction(AI); if (Callee) { - if (isProfitableToInline(AI, loopDepth, DA, LA, constTracker)) + if (isProfitableToInline(AI, loopDepth, DA, LA, constTracker, + NumCallerBlocks)) InitialCandidates.push_back(AI); } } @@ -1286,7 +1310,7 @@ void SILPerformanceInliner::visitColdBlocks( //===----------------------------------------------------------------------===// -// Performane Inliner Pass +// Performance Inliner Pass //===----------------------------------------------------------------------===// namespace { diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index 31cfe1739758f..021343561ea1b 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -1,8 +1,8 @@ -//===------- UsePrespecialized.cpp - use pre-specialized functions -------===// +//===--- UsePrespecialized.cpp - use pre-specialized functions ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -99,12 +99,12 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) { continue; // Create a name of the specialization. - llvm::SmallString<64> ClonedName; + std::string ClonedName; { - llvm::raw_svector_ostream buffer(ClonedName); - Mangle::Mangler M(buffer); - Mangle::GenericSpecializationMangler Mangler(M, ReferencedF, Subs); + Mangle::Mangler M; + GenericSpecializationMangler Mangler(M, ReferencedF, Subs); Mangler.mangle(); + ClonedName = M.finalize(); } SILFunction *NewF = nullptr; @@ -123,7 +123,7 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) { if (!NewF) continue; - // An existing specializaiton was found. + // An existing specialization was found. DEBUG( llvm::dbgs() << "Found a specialization of " << ReferencedF->getName() << " : " << NewF->getName() << "\n"); diff --git a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp index a2356bdc1ff81..d8df23159a103 100644 --- a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp +++ b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp @@ -1,8 +1,8 @@ -//===----- ArrayBoundsCheckOpts.cpp - Bounds check elim ---*- C++ -*-------===// +//===--- ArrayBoundsCheckOpts.cpp - Bounds check elim ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,6 +33,7 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/InstructionUtils.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PointerIntPair.h" @@ -77,7 +78,7 @@ static SILValue getArrayStructPointer(ArrayCallKind K, SILValue Array) { assert(K != ArrayCallKind::kNone); if (K < ArrayCallKind::kMakeMutable) { - auto LI = dyn_cast(Array.getDef()); + auto LI = dyn_cast(Array); if (!LI) { return Array; } @@ -113,9 +114,9 @@ static bool isArrayEltStore(StoreInst *SI) { Dest = MD->getOperand(0); if (auto *PtrToAddr = - dyn_cast(Dest.stripAddressProjections())) + dyn_cast(stripAddressProjections(Dest))) if (auto *SEI = dyn_cast(PtrToAddr->getOperand())) { - ArraySemanticsCall Call(SEI->getOperand().getDef()); + ArraySemanticsCall Call(SEI->getOperand()); if (Call && Call.getKind() == ArrayCallKind::kGetElementAddress) return true; } @@ -184,7 +185,7 @@ mayChangeArraySize(SILInstruction *I, ArrayCallKind &Kind, SILValue &Array, // stored in a runtime allocated object sub field of an alloca. if (auto *SI = dyn_cast(I)) { auto Ptr = SI->getDest(); - return isa(Ptr.getDef()) || isArrayEltStore(SI) + return isa(Ptr) || isArrayEltStore(SI) ? ArrayBoundsEffect::kNone : ArrayBoundsEffect::kMayChangeAny; } @@ -192,17 +193,17 @@ mayChangeArraySize(SILInstruction *I, ArrayCallKind &Kind, SILValue &Array, return ArrayBoundsEffect::kMayChangeAny; } -/// Two allocations of a mutable array struct can not reference the same +/// Two allocations of a mutable array struct cannot reference the same /// storage after modification. So we can treat them as not aliasing for the /// purpose of bound checking. The change would only be tracked through one of /// the allocations. static bool isIdentifiedUnderlyingArrayObject(SILValue V) { // Allocations are safe. - if (isa(V.getDef())) + if (isa(V)) return true; // Function arguments are safe. - if (auto Arg = dyn_cast(V.getDef())) + if (auto Arg = dyn_cast(V)) return Arg->isFunctionArg(); return false; @@ -250,7 +251,7 @@ class ABCAnalysis { ABCAnalysis(const ABCAnalysis &) = delete; ABCAnalysis &operator=(const ABCAnalysis &) = delete; - /// Find safe array bounds check in a loop. An bounds_check is safe if no size + /// Find safe array bounds check in a loop. A bounds_check is safe if no size /// modifying instruction to the same array has been seen so far. /// /// The code relies on isIdentifiedUnderlyingArrayObject' to make sure that a @@ -311,7 +312,7 @@ class ABCAnalysis { if (Array && !isIdentifiedUnderlyingArrayObject(Array)) { DEBUG(llvm::dbgs() << " not safe because of not identified underlying object " - << *Array.getDef() << " in " << *Inst); + << *Array << " in " << *Inst); allArraysInMemoryAreUnsafe = true; // No need to store specific arrays in this case. UnsafeArrays.clear(); @@ -335,8 +336,8 @@ getArrayIndexPair(SILValue Array, SILValue ArrayIndex, ArrayCallKind K) { K == ArrayCallKind::kCheckSubscript) && "Must be a bounds check call"); return std::make_pair( - Array.getDef(), - ArrayAccessDesc(ArrayIndex.getDef(), K == ArrayCallKind::kCheckIndex)); + Array, + ArrayAccessDesc(ArrayIndex, K == ArrayCallKind::kCheckIndex)); } /// Remove redundant checks in a basic block. This pass will reset the state @@ -380,7 +381,7 @@ static bool removeRedundantChecksInBlock(SILBasicBlock &BB, ArraySet &Arrays, // Is this an unsafe array whose size could have been changed? if (ABC.isUnsafe(Array)) { - DEBUG(llvm::dbgs() << " not a safe array argument " << *Array.getDef()); + DEBUG(llvm::dbgs() << " not a safe array argument " << *Array); continue; } @@ -390,14 +391,14 @@ static bool removeRedundantChecksInBlock(SILBasicBlock &BB, ArraySet &Arrays, continue; auto IndexedArray = - getArrayIndexPair(Array.getDef(), ArrayIndex.getDef(), Kind); - DEBUG(llvm::dbgs() << " IndexedArray: " << *Array.getDef() << " and " - << *ArrayIndex.getDef()); + getArrayIndexPair(Array, ArrayIndex, Kind); + DEBUG(llvm::dbgs() << " IndexedArray: " << *Array << " and " + << *ArrayIndex); // Saw a check for the first time. if (!RedundantChecks.count(IndexedArray)) { DEBUG(llvm::dbgs() << " first time: " << *Inst - << " with array argument: " << *Array.getDef()); + << " with array argument: " << *Array); RedundantChecks.insert(IndexedArray); continue; } @@ -443,7 +444,7 @@ static bool removeRedundantChecks(DominanceInfoNode *CurBB, // Is this an unsafe array whose size could have been changed? if (ABC.isUnsafe(Array)) { - DEBUG(llvm::dbgs() << " not a safe array argument " << *Array.getDef()); + DEBUG(llvm::dbgs() << " not a safe array argument " << *Array); continue; } @@ -452,12 +453,12 @@ static bool removeRedundantChecks(DominanceInfoNode *CurBB, if (!ArrayIndex) continue; auto IndexedArray = - getArrayIndexPair(Array.getDef(), ArrayIndex.getDef(), Kind); + getArrayIndexPair(Array, ArrayIndex, Kind); // Saw a check for the first time. if (!DominatingSafeChecks.count(IndexedArray)) { DEBUG(llvm::dbgs() << " first time: " << *Inst - << " with array arg: " << *Array.getDef()); + << " with array arg: " << *Array); DominatingSafeChecks.insert(IndexedArray); SafeChecksToPop.push_back(IndexedArray); continue; @@ -493,7 +494,6 @@ static CondFailInst *hasCondFailUse(SILInstruction *I) { /// a cond_fail on the second result. static CondFailInst *isOverflowChecked(BuiltinInst *AI) { for (auto *Op : AI->getUses()) { - SILValue Extract; if (!match(Op->getUser(), m_TupleExtractInst(m_ValueBase(), 1))) continue; @@ -511,7 +511,7 @@ static bool isSignedLessEqual(SILValue Start, SILValue End, SILBasicBlock &BB) { // "up + 1" but the overflow check is on "up". SILValue PreInclusiveEnd; if (!match( - End.getDef(), + End, m_TupleExtractInst(m_ApplyInst(BuiltinValueKind::SAddOver, m_SILValue(PreInclusiveEnd), m_One()), 0))) @@ -522,28 +522,28 @@ static bool isSignedLessEqual(SILValue Start, SILValue End, SILBasicBlock &BB) { for (auto &Inst : BB) if (auto CF = dyn_cast(&Inst)) { // Try to match a cond_fail on "XOR , (SLE Start, End), 1". - if (match(CF->getOperand().getDef(), + if (match(CF->getOperand(), m_ApplyInst(BuiltinValueKind::Xor, m_ApplyInst(BuiltinValueKind::ICMP_SLE, - m_Specific(Start.getDef()), - m_Specific(End.getDef())), + m_Specific(Start), + m_Specific(End)), m_One()))) return true; // Inclusive ranges will have a check on the upper value (before adding // one). if (PreInclusiveEnd) { - if (match(CF->getOperand().getDef(), + if (match(CF->getOperand(), m_ApplyInst(BuiltinValueKind::Xor, m_ApplyInst(BuiltinValueKind::ICMP_SLE, - m_Specific(Start.getDef()), - m_Specific(PreInclusiveEnd.getDef())), + m_Specific(Start), + m_Specific(PreInclusiveEnd)), m_One()))) IsPreInclusiveEndLEQ = true; - if (match(CF->getOperand().getDef(), + if (match(CF->getOperand(), m_ApplyInst(BuiltinValueKind::Xor, m_ApplyInst(BuiltinValueKind::ICMP_SGT, - m_Specific(End.getDef()), - m_Specific(PreInclusiveEnd.getDef())), + m_Specific(End), + m_Specific(PreInclusiveEnd)), m_One()))) IsPreInclusiveEndGTEnd = true; if (IsPreInclusiveEndLEQ && IsPreInclusiveEndGTEnd) @@ -555,10 +555,10 @@ static bool isSignedLessEqual(SILValue Start, SILValue End, SILBasicBlock &BB) { } static bool isLessThan(SILValue Start, SILValue End) { - auto S = dyn_cast(Start.getDef()); + auto S = dyn_cast(Start); if (!S) return false; - auto E = dyn_cast(End.getDef()); + auto E = dyn_cast(End); if (!E) return false; return S->getValue().slt(E->getValue()); @@ -609,7 +609,7 @@ static SILValue getZeroToCountArray(SILValue Start, SILValue End) { if (!SEI) return SILValue(); - ArraySemanticsCall SemCall(SEI->getOperand().getDef()); + ArraySemanticsCall SemCall(SEI->getOperand()); if (SemCall.getKind() != ArrayCallKind::kGetCount) return SILValue(); @@ -689,7 +689,7 @@ static bool isRangeChecked(SILValue Start, SILValue End, } static bool dominates(DominanceInfo *DT, SILValue V, SILBasicBlock *B) { - if (auto ValueBB = V.getDef()->getParentBB()) + if (auto ValueBB = V->getParentBB()) return DT->dominates(ValueBB, B); return false; } @@ -698,7 +698,7 @@ static bool dominates(DominanceInfo *DT, SILValue V, SILBasicBlock *B) { static SILValue getSub(SILLocation Loc, SILValue Val, unsigned SubVal, SILBuilder &B) { SmallVector Args(1, Val); - Args.push_back(B.createIntegerLiteral(Loc, Val.getType(), SubVal)); + Args.push_back(B.createIntegerLiteral(Loc, Val->getType(), SubVal)); Args.push_back(B.createIntegerLiteral( Loc, SILType::getBuiltinIntegerType(1, B.getASTContext()), -1)); @@ -748,7 +748,7 @@ struct InductionInfo { auto Loc = Inc->getLoc(); auto ResultTy = SILType::getBuiltinIntegerType(1, Builder.getASTContext()); auto *CmpSGE = Builder.createBuiltinBinaryFunction( - Loc, "cmp_sge", Start.getType(), ResultTy, {Start, End}); + Loc, "cmp_sge", Start->getType(), ResultTy, {Start, End}); Builder.createCondFail(Loc, CmpSGE); IsOverflowCheckInserted = true; @@ -792,7 +792,7 @@ class InductionAnalysis { // Look for induction variables. IVInfo::IVDesc IV; if (!(IV = IVs.getInductionDesc(Arg))) { - DEBUG(llvm::dbgs() << " not a induction variable: " << *Arg); + DEBUG(llvm::dbgs() << " not an induction variable: " << *Arg); continue; } @@ -860,8 +860,8 @@ class InductionAnalysis { return nullptr; DEBUG(llvm::dbgs() << " found an induction variable (ICMP_EQ): " - << *HeaderVal << " start: " << *Start.getDef() - << " end: " << *End.getDef()); + << *HeaderVal << " start: " << *Start + << " end: " << *End); // Check whether the addition is overflow checked by a cond_fail or whether // code in the preheader's predecessor ensures that we won't overflow. @@ -903,7 +903,7 @@ class AccessFunction { return nullptr; auto AsArg = - dyn_cast(ArrayIndexStruct->getElements()[0].getDef()); + dyn_cast(ArrayIndexStruct->getElements()[0]); if (!AsArg) return nullptr; @@ -919,7 +919,7 @@ class AccessFunction { } /// Hoists the necessary check for beginning and end of the induction - /// encapsulated by this acess function to the header. + /// encapsulated by this access function to the header. void hoistCheckToPreheader(ArraySemanticsCall CheckToHoist, SILBasicBlock *Preheader, DominanceInfo *DT) { @@ -935,7 +935,7 @@ class AccessFunction { // Set the new start index to the first value of the induction. Start->setOperand(0, FirstVal); - // Clone and fixup the load, retain sequenence to the header. + // Clone and fixup the load, retain sequence to the header. auto NewCheck = CheckToHoist.copyTo(Preheader->getTerminator(), DT); NewCheck->setOperand(1, Start); @@ -953,7 +953,7 @@ class AccessFunction { }; static bool hasArrayType(SILValue Value, SILModule &M) { - return Value.getType().getNominalOrBoundGenericNominal() == + return Value->getType().getNominalOrBoundGenericNominal() == M.getASTContext().getArrayDecl(); } @@ -984,8 +984,8 @@ static bool hoistChecksInLoop(DominanceInfo *DT, DominanceInfoNode *DTNode, SILValue Array = getArrayStructPointer(Kind, ArrayVal); // The array must strictly dominate the header. - if (!dominates(DT, Array.getDef(), Preheader)) { - DEBUG(llvm::dbgs() << " does not dominated header" << *Array.getDef()); + if (!dominates(DT, Array, Preheader)) { + DEBUG(llvm::dbgs() << " does not dominated header" << *Array); continue; } @@ -993,7 +993,7 @@ static bool hoistChecksInLoop(DominanceInfo *DT, DominanceInfoNode *DTNode, // This is either a SILValue which is defined outside the loop or it is an // array, which loaded from memory and the memory is not changed in the loop. if (!dominates(DT, ArrayVal, Preheader) && ABC.isUnsafe(Array)) { - DEBUG(llvm::dbgs() << " not a safe array argument " << *Array.getDef()); + DEBUG(llvm::dbgs() << " not a safe array argument " << *Array); continue; } @@ -1153,7 +1153,7 @@ static void reportBoundsChecks(SILFunction *F) { auto Array = ArrayCall.getSelf(); ++NumBCs; llvm::dbgs() << " # CheckBounds: " << Inst - << " with array arg: " << *Array.getDef() + << " with array arg: " << *Array << " and index: " << Inst.getOperand(1); } } @@ -1210,7 +1210,7 @@ class ABCOpt : public SILFunctionTransform { auto rcRoot = RCIA->getRCIdentityRoot(Call.getSelf()); // Check the type of the array. We need to have an array element type // that is not calling a deinit function. - if (DestAnalysis->mayStoreToMemoryOnDestruction(rcRoot.getType())) + if (DestAnalysis->mayStoreToMemoryOnDestruction(rcRoot->getType())) continue; ReleaseSafeArrays.insert(rcRoot); diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp index e2fd1f4e1a0e2..6656afee26337 100644 --- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp @@ -1,8 +1,8 @@ -//===------- COWArrayOpt.cpp - Optimize Copy-On-Write Array Checks --------===// +//===--- COWArrayOpt.cpp - Optimize Copy-On-Write Array Checks ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,9 +17,9 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" -#include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" @@ -51,8 +51,8 @@ COWViewCFGFunction("view-cfg-before-cow-for", llvm::cl::init(""), /// distinguish between indexing and subelement access. The same index could /// either refer to the next element (indexed) or a subelement. static SILValue getAccessPath(SILValue V, SmallVectorImpl& Path) { - V = V.stripCasts(); - ProjectionIndex PI(V.getDef()); + V = stripCasts(V); + ProjectionIndex PI(V); if (!PI.isValid() || V->getKind() == ValueKind::IndexAddrInst) return V; @@ -143,7 +143,7 @@ class StructUseCollector { if (auto *Arg = dyn_cast(V)) return Arg->getType().isObject(); if (auto *Inst = dyn_cast(V)) - return Inst->getNumTypes() == 1 && Inst->getType(0).isObject(); + return Inst->hasValue() && Inst->getType().isObject(); return false; } @@ -215,9 +215,8 @@ class StructUseCollector { continue; } - // An alloc_stack returns its address as the second value. - assert((PI.Aggregate == V || PI.Aggregate == SILValue(V, 1)) && - "Expected unary element addr inst."); + // An alloc_box returns its address as the second value. + assert(PI.Aggregate && "Expected unary element addr inst."); // Recursively check for users after stripping this component from the // access path. @@ -449,7 +448,7 @@ bool COWArrayOpt::checkUniqueArrayContainer(SILValue ArrayContainer) { return false; } -/// Lazilly compute blocks that may reach the loop. +/// Lazily compute blocks that may reach the loop. SmallPtrSetImpl &COWArrayOpt::getReachingBlocks() { if (ReachingBlocks.empty()) { SmallVector Worklist; @@ -536,7 +535,7 @@ bool COWArrayOpt::isRetainReleasedBeforeMutate(SILInstruction *RetainInst, // release %ptr // array_operation(..., @owned %ptr) // - // This is not the case for an potentially aliased array because a release + // This is not the case for a potentially aliased array because a release // can cause a destructor to run. The destructor in turn can cause // arbitrary side effects. if (isa(II) || isa(II)) @@ -636,7 +635,7 @@ static bool isTransitiveSafeUser(SILInstruction *I) { case ValueKind::EnumInst: case ValueKind::UncheckedRefCastInst: case ValueKind::UncheckedBitwiseCastInst: - assert(I->getNumTypes() == 1 && "We assume these are unary"); + assert(I->hasValue() && "We assume these are unary"); return true; default: return false; @@ -787,14 +786,14 @@ bool COWArrayOpt::checkSafeElementValueUses(UserOperList &ElementValueUsers) { return true; } static bool isArrayEltStore(StoreInst *SI) { - SILValue Dest = SI->getDest().stripAddressProjections(); + SILValue Dest = stripAddressProjections(SI->getDest()); if (auto *MD = dyn_cast(Dest)) Dest = MD->getOperand(0); if (auto *PtrToAddr = - dyn_cast(Dest.stripAddressProjections())) + dyn_cast(stripAddressProjections(Dest))) if (auto *SEI = dyn_cast(PtrToAddr->getOperand())) { - ArraySemanticsCall Call(SEI->getOperand().getDef()); + ArraySemanticsCall Call(SEI->getOperand()); if (Call && Call.getKind() == ArrayCallKind::kGetElementAddress) return true; } @@ -837,7 +836,7 @@ bool isReleaseOfArrayValueAt(AllocStackInst *ArrayStruct, SILInstruction *Inst, if (!ArrayLoad) return false; - if (ArrayLoad->getOperand().getDef() == ArrayStruct) + if (ArrayLoad->getOperand() == ArrayStruct) return true; return false; @@ -846,7 +845,7 @@ bool isReleaseOfArrayValueAt(AllocStackInst *ArrayStruct, SILInstruction *Inst, /// Check that the array value is released before a mutating operation happens. bool COWArrayOpt::isArrayValueReleasedBeforeMutate( SILValue V, llvm::SmallSet &Releases) { - auto *ASI = dyn_cast(V.getDef()); + auto *ASI = dyn_cast(V); if (!ASI) return false; @@ -904,8 +903,8 @@ static SILValue stripValueProjections(SILValue V, SmallVectorImpl &ValuePrjs) { while (V->getKind() == ValueKind::StructExtractInst) { - ValuePrjs.push_back(cast(V.getDef())); - V = cast(V.getDef())->getOperand(0); + ValuePrjs.push_back(cast(V)); + V = cast(V)->getOperand(0); } return V; } @@ -936,24 +935,34 @@ findPreceedingCheckSubscriptOrMakeMutable(ApplyInst *GetElementAddr) { /// Matches the self parameter arguments, verifies that \p Self is called and /// stores the instructions in \p DepInsts in order. static bool -matchSelfParameterSetup(ApplyInst *Call, LoadInst *Self, +matchSelfParameterSetup(ArraySemanticsCall Call, LoadInst *Self, SmallVectorImpl &DepInsts) { + bool MayHaveBridgedObjectElementType = Call.mayHaveBridgedObjectElementType(); + // We only need the retain/release for the guaranteed parameter if the call + // could release self. This can only happen if the array is backed by an + // Objective-C array. If this is not the case we can safely hoist the call + // without the retain/releases. auto *RetainArray = dyn_cast_or_null(getInstBefore(Call)); - if (!RetainArray) + if (!RetainArray && MayHaveBridgedObjectElementType) return false; auto *ReleaseArray = dyn_cast_or_null(getInstAfter(Call)); - if (!ReleaseArray) + if (!ReleaseArray && MayHaveBridgedObjectElementType) return false; - if (ReleaseArray->getOperand() != RetainArray->getOperand()) + if (ReleaseArray && RetainArray && + ReleaseArray->getOperand() != RetainArray->getOperand()) return false; - DepInsts.push_back(ReleaseArray); + if (ReleaseArray) + DepInsts.push_back(ReleaseArray); DepInsts.push_back(Call); - DepInsts.push_back(RetainArray); + if (RetainArray) + DepInsts.push_back(RetainArray); - auto ArrayLoad = stripValueProjections(RetainArray->getOperand(), DepInsts); - if (ArrayLoad != Self) - return false; + if (RetainArray) { + auto ArrayLoad = stripValueProjections(RetainArray->getOperand(), DepInsts); + if (ArrayLoad != Self) + return false; + } DepInsts.push_back(Self); return true; @@ -1002,8 +1011,10 @@ struct HoistableMakeMutable { /// Hoist this make_mutable call and depend instructions to the preheader. void hoist() { auto *Term = Loop->getLoopPreheader()->getTerminator(); - for (auto *It : swift::reversed(DepInsts)) - It->moveBefore(Term); + for (auto *It : swift::reversed(DepInsts)) { + if (It->getParent() != Term->getParent()) + It->moveBefore(Term); + } MakeMutable->moveBefore(Term); } @@ -1056,14 +1067,16 @@ struct HoistableMakeMutable { if (!UncheckedRefCast) return false; DepInsts.push_back(UncheckedRefCast); - auto *BaseLoad = dyn_cast(UncheckedRefCast->getOperand()); + + SILValue ArrayBuffer = stripValueProjections(UncheckedRefCast->getOperand(), DepInsts); + auto *BaseLoad = dyn_cast(ArrayBuffer); if (!BaseLoad || Loop->contains(BaseLoad->getOperand()->getParentBB())) return false; DepInsts.push_back(BaseLoad); // Check the get_element_addr call. ArraySemanticsCall GetElementAddrCall( - StructExtractArrayAddr->getOperand().getDef()); + StructExtractArrayAddr->getOperand()); if (!GetElementAddrCall || GetElementAddrCall.getKind() != ArrayCallKind::kGetElementAddress) return false; @@ -1186,7 +1199,7 @@ bool COWArrayOpt::hoistInLoopWithOnlyNonArrayValueMutatingOperations() { // are release before we hit a make_unique instruction. ApplyInst *SemCall = Sem; if (Sem.getKind() == ArrayCallKind::kGetElement && - !SemCall->getArgument(0).getType().isTrivial(Module)) { + !SemCall->getArgument(0)->getType().isTrivial(Module)) { CreatedNonTrivialValues.insert(SemCall->getArgument(0)); } else if (Sem.getKind() == ArrayCallKind::kMakeMutable) { MakeMutableCalls.push_back(Sem); @@ -1216,7 +1229,7 @@ bool COWArrayOpt::hoistInLoopWithOnlyNonArrayValueMutatingOperations() { // is trivial. if (StoreInst *SI = dyn_cast(Inst)) { if (!isArrayEltStore(SI) || - !SI->getSrc().getType().isTrivial(Module)) { + !SI->getSrc()->getType().isTrivial(Module)) { DEBUG(llvm::dbgs() << " (NO) non trivial store could store an array value " << *Inst); @@ -1303,7 +1316,7 @@ bool COWArrayOpt::hasLoopOnlyDestructorSafeArrayOperations() { if (CachedSafeLoop.first) return CachedSafeLoop.second; - assert(CachedSafeLoop.second == false && + assert(!CachedSafeLoop.second && "We only move to a true state below"); // We will compute the state of this loop now. @@ -1333,17 +1346,17 @@ bool COWArrayOpt::hasLoopOnlyDestructorSafeArrayOperations() { // All array types must be the same. This is a stronger guaranteed than // we actually need. The requirement is that we can't create another // reference to the array by performing an array operation: for example, - // storing or appending one array into an two-dimensional array. + // storing or appending one array into a two-dimensional array. // Checking - // that all types are the same make guarantees that this can not happen. + // that all types are the same make guarantees that this cannot happen. if (SameTy.isNull()) { SameTy = - Sem.getSelf().getType().getSwiftRValueType()->getCanonicalType(); + Sem.getSelf()->getType().getSwiftRValueType()->getCanonicalType(); continue; } if (Sem.getSelf() - .getType() + ->getType() .getSwiftRValueType() ->getCanonicalType() != SameTy) { DEBUG(llvm::dbgs() << " (NO) mismatching array types\n"); @@ -1382,7 +1395,7 @@ bool COWArrayOpt::hasLoopOnlyDestructorSafeArrayOperations() { if (MatchedReleases.count(&RVI->getOperandRef())) continue; - // Ignore fix_lifetime. It can not increment ref counts. + // Ignore fix_lifetime. It cannot increment ref counts. if (isa(Inst)) continue; @@ -1402,7 +1415,7 @@ void COWArrayOpt::hoistMakeMutableAndSelfProjection( ArraySemanticsCall MakeMutable, bool HoistProjection) { // Hoist projections. if (HoistProjection) - MakeMutable.getSelfOperand().hoistAddressProjections( + hoistAddressProjections(MakeMutable.getSelfOperand(), Preheader->getTerminator(), DomTree); assert(MakeMutable.canHoist(Preheader->getTerminator(), DomTree) && @@ -1420,8 +1433,8 @@ bool COWArrayOpt::hoistMakeMutable(ArraySemanticsCall MakeMutable) { // We can hoist address projections (even if they are only conditionally // executed). - auto ArrayAddrBase = CurrentArrayAddr.stripAddressProjections(); - SILBasicBlock *ArrayAddrBaseBB = ArrayAddrBase.getDef()->getParentBB(); + auto ArrayAddrBase = stripUnaryAddressProjections(CurrentArrayAddr); + SILBasicBlock *ArrayAddrBaseBB = ArrayAddrBase->getParentBB(); if (ArrayAddrBaseBB && !DomTree->dominates(ArrayAddrBaseBB, Preheader)) { DEBUG(llvm::dbgs() << " Skipping Array: does not dominate loop!\n"); @@ -1450,7 +1463,7 @@ bool COWArrayOpt::hoistMakeMutable(ArraySemanticsCall MakeMutable) { // Check that the Array is not retained with this loop and it's address does // not escape within this function. StructUseCollector StructUses; - StructUses.collectUses(ArrayContainer.getDef(), AccessPath); + StructUses.collectUses(ArrayContainer, AccessPath); for (auto *Oper : StructUses.Visited) ArrayUserSet.insert(Oper->getUser()); @@ -1673,7 +1686,7 @@ class ArrayPropertiesAnalysis { /// Strip the struct load and the address projection to the location /// holding the array struct. SILValue stripArrayStructLoad(SILValue V) { - if (auto LI = dyn_cast(V.getDef())) { + if (auto LI = dyn_cast(V)) { auto Val = LI->getOperand(); // We could have two arrays in a surrounding container so we can only // strip off the 'array struct' project. @@ -1682,7 +1695,7 @@ class ArrayPropertiesAnalysis { // var a2 : [ClassA] // } // 'a1' and 'a2' are different arrays. - if (auto SEAI = dyn_cast(Val.getDef())) + if (auto SEAI = dyn_cast(Val)) Val = SEAI->getOperand(); return Val; } @@ -1757,7 +1770,7 @@ class ArrayPropertiesAnalysis { return false; } - // Otherwise, all of our users are sane. The array does not scape. + // Otherwise, all of our users are sane. The array does not escape. return true; } @@ -1776,7 +1789,7 @@ class ArrayPropertiesAnalysis { // will check in checkSafeArrayAddressUses that all initialization stores to // this variable are safe (i.e the store dominates the loop etc). bool isSafeArrayContainer(SILValue V) { - if (auto *Arg = dyn_cast(V.getDef())) { + if (auto *Arg = dyn_cast(V)) { // Check that the argument is passed as an inout or by value type. This // means there are no aliases accessible within this function scope. auto Params = Fun->getLoweredFunctionType()->getParameters(); @@ -1793,7 +1806,7 @@ class ArrayPropertiesAnalysis { } } return true; - } else if (isa(V.getDef())) + } else if (isa(V)) return true; DEBUG(llvm::dbgs() @@ -1820,11 +1833,11 @@ class ArrayPropertiesAnalysis { } bool isClassElementTypeArray(SILValue Arr) { - auto Ty = Arr.getType().getSwiftRValueType(); - auto Cannonical = Ty.getCanonicalTypeOrNull(); - if (Cannonical.isNull()) + auto Ty = Arr->getType().getSwiftRValueType(); + auto Canonical = Ty.getCanonicalTypeOrNull(); + if (Canonical.isNull()) return false; - auto *Struct = Cannonical->getStructOrBoundGenericStruct(); + auto *Struct = Canonical->getStructOrBoundGenericStruct(); assert(Struct && "Array must be a struct !?"); if (Struct) { // No point in hoisting generic code. @@ -1878,7 +1891,7 @@ class ArrayPropertiesAnalysis { return false; StructUseCollector StructUses; - StructUses.collectUses(ArrayContainer.getDef(), AccessPath); + StructUses.collectUses(ArrayContainer, AccessPath); if (!checkSafeArrayAddressUses(StructUses.AggregateAddressUsers) || !checkSafeArrayAddressUses(StructUses.StructAddressUsers) || @@ -2004,7 +2017,7 @@ class RegionCloner : public SILCloner { } SILValue remapValue(SILValue V) { - if (auto *BB = V.getDef()->getParentBB()) { + if (auto *BB = V->getParentBB()) { if (!DomTree.dominates(StartBB, BB)) { // Must be a value that dominates the start basic block. assert(DomTree.dominates(BB, StartBB) && @@ -2024,7 +2037,7 @@ class RegionCloner : public SILCloner { SILSSAUpdater &SSAUp) { // Collect outside uses. SmallVector UseList; - for (auto Use : V.getUses()) + for (auto Use : V->getUses()) if (OutsideBBs.count(Use->getUser()->getParent()) || !BBMap.count(Use->getUser()->getParent())) { UseList.push_back(UseWrapper(Use)); @@ -2033,7 +2046,7 @@ class RegionCloner : public SILCloner { return; // Update SSA form. - SSAUp.Initialize(V.getType()); + SSAUp.Initialize(V->getType()); SSAUp.AddAvailableValue(OrigBB, V); SILValue NewVal = remapValue(V); SSAUp.AddAvailableValue(BBMap[OrigBB], NewVal); @@ -2057,10 +2070,7 @@ class RegionCloner : public SILCloner { // Update outside used instruction values. for (auto &Inst : *OrigBB) { - for (unsigned i = 0, e = Inst.getNumTypes(); i != e; ++i) { - SILValue V(&Inst, i); - updateSSAForValue(OrigBB, V, SSAUp); - } + updateSSAForValue(OrigBB, &Inst, SSAUp); } } } @@ -2096,7 +2106,7 @@ class ArrayPropertiesSpecializer { static SILValue createStructExtract(SILBuilder &B, SILLocation Loc, SILValue Opd, unsigned FieldNo) { - SILType Ty = Opd.getType(); + SILType Ty = Opd->getType(); auto SD = Ty.getStructOrBoundGenericStruct(); auto Properties = SD->getStoredProperties(); unsigned Counter = 0; @@ -2120,9 +2130,9 @@ static Identifier getBinaryFunction(StringRef Name, SILType IntSILTy, /// Create a binary and function. static SILValue createAnd(SILBuilder &B, SILLocation Loc, SILValue Opd1, SILValue Opd2) { - auto AndFn = getBinaryFunction("and", Opd1.getType(), B.getASTContext()); + auto AndFn = getBinaryFunction("and", Opd1->getType(), B.getASTContext()); SILValue Args[] = {Opd1, Opd2}; - return B.createBuiltin(Loc, AndFn, Opd1.getType(), {}, Args); + return B.createBuiltin(Loc, AndFn, Opd1->getType(), {}, Args); } /// Create a check over all array.props calls that they have the 'fast native @@ -2140,7 +2150,7 @@ createFastNativeArraysCheck(SmallVectorImpl &ArrayProps, auto Loc = (*Call).getLoc(); auto CallKind = Call.getKind(); if (CallKind == ArrayCallKind::kArrayPropsIsNativeTypeChecked) { - auto Val = createStructExtract(B, Loc, SILValue(Call, 0), 0); + auto Val = createStructExtract(B, Loc, SILValue(Call), 0); Result = createAnd(B, Loc, Result, Val); } } @@ -2274,7 +2284,7 @@ class SwiftArrayOptPass : public SILFunctionTransform { // Check whether we can hoist 'array.props' calls out of loops, collecting // the preheader we can hoist to. We only hoist out of loops if 'all' - // arrray.props call can be hoisted for a given loop nest. + // array.props call can be hoisted for a given loop nest. // We process the loop tree preorder (top-down) to hoist over the biggest // possible loop-nest. SmallVector HoistableLoopNests; diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index 19b28d3207ca8..933b9beb56625 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -1,8 +1,8 @@ -//===--------- LICM.cpp - Loop invariant code motion ------*- C++ -*-------===// +//===--- LICM.cpp - Loop invariant code motion ----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,6 +27,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/InstructionUtils.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallPtrSet.h" @@ -111,7 +112,7 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L) { return std::all_of(Opds.begin(), Opds.end(), [=](Operand &Op) { - auto *Def = Op.get().getDef(); + ValueBase *Def = Op.get(); // Operand is defined outside the loop. if (auto *Inst = dyn_cast(Def)) @@ -125,7 +126,7 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L) { /// Check if an address does not depend on other values in a basic block. static SILInstruction *addressIndependent(SILValue Addr) { - Addr = Addr.stripCasts(); + Addr = stripCasts(Addr); if (GlobalAddrInst *SGAI = dyn_cast(Addr)) return SGAI; if (StructElementAddrInst *SEAI = dyn_cast(Addr)) @@ -309,8 +310,8 @@ static bool hoistInstructions(SILLoop *Loop, DominanceInfo *DT, return Changed; } -static bool sinkFixLiftime(SILLoop *Loop, DominanceInfo *DomTree, - SILLoopInfo *LI) { +static bool sinkFixLifetime(SILLoop *Loop, DominanceInfo *DomTree, + SILLoopInfo *LI) { DEBUG(llvm::errs() << " Sink fix_lifetime attempt\n"); auto Preheader = Loop->getLoopPreheader(); if (!Preheader) @@ -347,7 +348,7 @@ static bool sinkFixLiftime(SILLoop *Loop, DominanceInfo *DomTree, // Sink the fix_lifetime instruction. bool Changed = false; for (auto *FLI : FixLifetimeInsts) - if (DomTree->dominates(FLI->getOperand().getDef()->getParentBB(), + if (DomTree->dominates(FLI->getOperand()->getParentBB(), Preheader)) { auto Succs = ExitingBB->getSuccessors(); for (unsigned EdgeIdx = 0; EdgeIdx < Succs.size(); ++EdgeIdx) { @@ -371,7 +372,7 @@ static bool sinkFixLiftime(SILLoop *Loop, DominanceInfo *DomTree, } namespace { -/// \brief Summmary of may writes occuring in the loop tree rooted at \p +/// \brief Summary of may writes occurring in the loop tree rooted at \p /// Loop. This includes all writes of the sub loops and the loop itself. struct LoopNestSummary { SILLoop *Loop; @@ -520,7 +521,7 @@ void LoopTreeOptimization::optimizeLoop(SILLoop *CurrentLoop, Changed |= sinkCondFail(CurrentLoop); Changed |= hoistInstructions(CurrentLoop, DomTree, SafeReads, RunsOnHighLevelSil); - Changed |= sinkFixLiftime(CurrentLoop, DomTree, LoopInfo); + Changed |= sinkFixLifetime(CurrentLoop, DomTree, LoopInfo); } namespace { diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index 464563b14c30a..691512d364f7e 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -1,8 +1,8 @@ -//===--------- LoopSimplify.cpp - Loop structure simplify -*- C++ -*-------===// +//===--- LoopRotate.cpp - Loop structure simplify -------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,7 +40,7 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, return std::all_of(Opds.begin(), Opds.end(), [=](Operand &Op) { - auto *Def = Op.get().getDef(); + ValueBase *Def = Op.get(); // Operand is outside the loop or marked invariant. if (auto *Inst = dyn_cast(Def)) return !L->contains(Inst->getParent()) || Inv.count(Inst); @@ -51,7 +51,7 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, }); } -/// We can not duplicate blocks with AllocStack instructions (they need to be +/// We cannot duplicate blocks with AllocStack instructions (they need to be /// FIFO). Other instructions can be moved to the preheader. static bool canDuplicateOrMoveToPreheader(SILLoop *L, SILBasicBlock *Preheader, @@ -92,17 +92,11 @@ static void mapOperands(SILInstruction *I, const llvm::DenseMap &ValueMap) { for (auto &Opd : I->getAllOperands()) { SILValue OrigVal = Opd.get(); - ValueBase *OrigDef = OrigVal.getDef(); + ValueBase *OrigDef = OrigVal; auto Found = ValueMap.find(OrigDef); if (Found != ValueMap.end()) { SILValue MappedVal = Found->second; - unsigned ResultIdx = OrigVal.getResultNumber(); - // All mapped instructions have their result number set to zero. Except - // for arguments that we followed along one edge to their incoming value - // on that edge. - if (isa(OrigDef)) - ResultIdx = MappedVal.getResultNumber(); - Opd.set(SILValue(MappedVal.getDef(), ResultIdx)); + Opd.set(MappedVal); } } } @@ -119,24 +113,17 @@ updateSSAForUseOfInst(SILSSAUpdater &Updater, // Find the mapped instruction. assert(ValueMap.count(Inst) && "Expected to find value in map!"); SILValue MappedValue = ValueMap.find(Inst)->second; - auto *MappedInst = MappedValue.getDef(); assert(MappedValue); - assert(MappedInst); // For each use of a specific result value of the instruction. - for (unsigned i = 0, e = Inst->getNumTypes(); i != e; ++i) { - SILValue Res(Inst, i); - // For block arguments, MappedValue is already indexed to indicate the - // single result value that feeds the argument. In this case, i==0 because - // SILArgument only produces one value. - SILValue MappedRes = - isa(Inst) ? MappedValue : SILValue(MappedInst, i); - assert(Res.getType() == MappedRes.getType() && "The types must match"); + if (Inst->hasValue()) { + SILValue Res(Inst); + assert(Res->getType() == MappedValue->getType() && "The types must match"); InsertedPHIs.clear(); - Updater.Initialize(Res.getType()); + Updater.Initialize(Res->getType()); Updater.AddAvailableValue(Header, Res); - Updater.AddAvailableValue(EntryCheckBlock, MappedRes); + Updater.AddAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all @@ -146,7 +133,7 @@ updateSSAForUseOfInst(SILSSAUpdater &Updater, // Instead we collect uses wrapping uses in branches specially so that we // can reconstruct the use even after the branch has been modified. SmallVector StoredUses; - for (auto *U : Res.getUses()) + for (auto *U : Res->getUses()) StoredUses.push_back(UseWrapper(U)); for (auto U : StoredUses) { Operand *Use = U; @@ -298,7 +285,7 @@ bool swift::rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, // The header needs to exit the loop. if (!L->isLoopExiting(Header)) { - DEBUG(llvm::dbgs() << *L << " not a exiting header\n"); + DEBUG(llvm::dbgs() << *L << " not an exiting header\n"); DEBUG(L->getHeader()->getParent()->dump()); return false; } @@ -363,7 +350,7 @@ bool swift::rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, mapOperands(I, ValueMap); // The actual operand will sort out which result idx to use. - ValueMap[&Inst] = SILValue(I, 0); + ValueMap[&Inst] = I; } } diff --git a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp index bd78fc1a23fd2..eda87fc6d0822 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp @@ -1,8 +1,8 @@ -//===--------- LoopUnroll.cpp - Loop unrolling ------------*- C++ -*-------===// +//===--- LoopUnroll.cpp - Loop unrolling ----------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -56,7 +56,7 @@ class LoopCloner : public SILCloner { protected: SILValue remapValue(SILValue V) { - if (auto *BB = V.getDef()->getParentBB()) { + if (auto *BB = V->getParentBB()) { if (!Loop->contains(BB)) return V; } @@ -140,7 +140,7 @@ static Optional getMaxLoopTripCount(SILLoop *Loop, return None; auto *Start = dyn_cast_or_null( - RecArg->getIncomingValue(Preheader).getDef()); + RecArg->getIncomingValue(Preheader)); if (!Start) return None; @@ -197,12 +197,12 @@ static void redirectTerminator(SILBasicBlock *Latch, unsigned CurLoopIter, // We can either have a split backedge as our latch terminator. // HeaderBlock: // ... - // cond_br %cond, ExitBlock, BackegdeBlock + // cond_br %cond, ExitBlock, BackedgeBlock // - // BackegdeBlock: + // BackedgeBlock: // br HeaderBlock: // - // Or a a conditional branch back to the header. + // Or a conditional branch back to the header. // HeaderBlock: // ... // cond_br %cond, ExitBlock, HeaderBlock @@ -290,12 +290,11 @@ static void collectLoopLiveOutValues( // Is this use outside the loop. if (!Loop->contains(Op->getUser())) { auto UsedValue = Op->get(); - assert(UsedValue.getDef() == &Inst && "Instructions must match"); + assert(UsedValue == &Inst && "Instructions must match"); assert(ClonedInstructions.count(&Inst) && "Unmapped instruction!"); if (!LoopLiveOutValues.count(UsedValue)) - LoopLiveOutValues[UsedValue].push_back(SILValue( - ClonedInstructions[&Inst], UsedValue.getResultNumber())); + LoopLiveOutValues[UsedValue].push_back(ClonedInstructions[&Inst]); } } } @@ -310,11 +309,11 @@ updateSSA(SILLoop *Loop, // Collect out of loop uses of this value. auto OrigValue = MapEntry.first; SmallVector UseList; - for (auto Use : OrigValue.getUses()) + for (auto Use : OrigValue->getUses()) if (!Loop->contains(Use->getUser()->getParent())) UseList.push_back(UseWrapper(Use)); // Update SSA of use with the available values. - SSAUp.Initialize(OrigValue.getType()); + SSAUp.Initialize(OrigValue->getType()); SSAUp.AddAvailableValue(OrigValue->getParentBB(), OrigValue); for (auto NewValue : MapEntry.second) SSAUp.AddAvailableValue(NewValue->getParentBB(), NewValue); @@ -390,10 +389,8 @@ static bool tryToUnrollLoop(SILLoop *Loop) { MappedValue = Cloner.getValueMap()[MapEntry.first]; // Otherwise, consult the instruction map. else - MappedValue = SILValue( - Cloner - .getInstMap()[cast(MapEntry.first.getDef())], - MapEntry.first.getResultNumber()); + MappedValue = Cloner + .getInstMap()[cast(MapEntry.first)]; MapEntry.second.push_back(MappedValue); assert(MapEntry.second.size() == Cnt); } diff --git a/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp b/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp index 084ec8300b331..cc1f5931e0b36 100644 --- a/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp +++ b/lib/SILOptimizer/Mandatory/ConstantPropagation.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -264,7 +264,7 @@ constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID, return nullptr; } - // Add the literal instruction to represnet the result of the division. + // Add the literal instruction to represent the result of the division. SILBuilderWithScope B(BI); return B.createIntegerLiteral(BI->getLoc(), BI->getType(), ResVal); } @@ -366,7 +366,7 @@ static SILInstruction *constantFoldBinary(BuiltinInst *BI, } } -static std::pair getTypeSigndness(const BuiltinInfo &Builtin) { +static std::pair getTypeSignedness(const BuiltinInfo &Builtin) { bool SrcTySigned = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc || Builtin.ID == BuiltinValueKind::SToUCheckedTrunc || @@ -481,7 +481,7 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI, // 2048. Is there a better way to identify conversions from literals? bool Literal = (SrcBitWidth == 2048); - // FIXME: This will prevent hard error in cases the error is comming + // FIXME: This will prevent hard error in cases the error is coming // from ObjC interoperability code. Currently, we treat NSUInteger as // Int. if (Loc.getSourceLoc().isInvalid()) { @@ -503,7 +503,7 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI, // Otherwise report the overflow error. if (Literal) { bool SrcTySigned, DstTySigned; - std::tie(SrcTySigned, DstTySigned) = getTypeSigndness(Builtin); + std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, SrcTySigned); @@ -521,7 +521,7 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI, // Otherwise, print the Builtin Types. } else { bool SrcTySigned, DstTySigned; - std::tie(SrcTySigned, DstTySigned) = getTypeSigndness(Builtin); + std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_builtin_types, DstTySigned, DstTy, SrcAsString); @@ -540,10 +540,10 @@ constantFoldAndCheckIntegerConversions(BuiltinInst *BI, // Otherwise, print the Builtin Types. } else { - // Since builtin types are sign-agnostic, print the signdness + // Since builtin types are sign-agnostic, print the signedness // separately. bool SrcTySigned, DstTySigned; - std::tie(SrcTySigned, DstTySigned) = getTypeSigndness(Builtin); + std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_builtin_types, SrcTySigned, SrcTy, DstTySigned, DstTy); @@ -673,10 +673,10 @@ case BuiltinValueKind::id: return nullptr; APFloat TruncVal = V->getValue(); Type DestTy = Builtin.Types[1]; - bool loosesInfo; + bool losesInfo; APFloat::opStatus ConversionStatus = TruncVal.convert( DestTy->castTo()->getAPFloatSemantics(), - APFloat::rmNearestTiesToEven, &loosesInfo); + APFloat::rmNearestTiesToEven, &losesInfo); SILLocation Loc = BI->getLoc(); // Check if conversion was successful. @@ -746,7 +746,7 @@ static bool isApplyOfBuiltin(SILInstruction &I, BuiltinValueKind kind) { static bool isApplyOfStringConcat(SILInstruction &I) { if (auto *AI = dyn_cast(&I)) if (auto *Fn = AI->getCalleeFunction()) - if (Fn->hasSemanticsString("string.concat")) + if (Fn->hasSemanticsAttr("string.concat")) return true; return false; } @@ -766,7 +766,7 @@ constantFoldStringConcatenation(ApplyInst *AI, return false; // Replace all uses of the old instruction by a new instruction. - SILValue(AI).replaceAllUsesWith(Concatenated); + AI->replaceAllUsesWith(Concatenated); auto RemoveCallback = [&](SILInstruction *DeadI) { WorkList.remove(DeadI); }; // Remove operands that are not used anymore. @@ -777,7 +777,7 @@ constantFoldStringConcatenation(ApplyInst *AI, for (auto &Op : AI->getAllOperands()) { SILValue Val = Op.get(); Op.drop(); - if (Val.use_empty()) { + if (Val->use_empty()) { auto *DeadI = dyn_cast(Val); recursivelyDeleteTriviallyDeadInstructions(DeadI, /*force*/ true, RemoveCallback); @@ -861,7 +861,7 @@ processFunction(SILFunction &F, bool EnableDiagnostics, [&](SILInstruction *I, ValueBase *V) { /* ReplaceInstUsesAction */ InvalidateInstructions = true; - SILValue(I).replaceAllUsesWith(V); + I->replaceAllUsesWith(V); }, [&](SILInstruction *I) { /* EraseAction */ auto *TI = dyn_cast(I); @@ -1001,7 +1001,7 @@ processFunction(SILFunction &F, bool EnableDiagnostics, if (ResultsInError.hasValue() && ResultsInError.getValue()) ErrorSet.insert(User); - // We failed to constant propogate... continue... + // We failed to constant propagate... continue... if (!C) continue; @@ -1022,12 +1022,10 @@ processFunction(SILFunction &F, bool EnableDiagnostics, // If the user is a tuple_extract, just substitute the right value in. if (auto *TEI = dyn_cast(O->getUser())) { SILValue NewVal = TI->getOperand(TEI->getFieldNo()); - assert(TEI->getTypes().size() == 1 && - "Currently, we only support single result instructions."); - SILValue(TEI, 0).replaceAllUsesWith(NewVal); + TEI->replaceAllUsesWith(NewVal); TEI->dropAllReferences(); FoldedUsers.insert(TEI); - if (auto *Inst = dyn_cast(NewVal.getDef())) + if (auto *Inst = dyn_cast(NewVal)) WorkList.insert(Inst); } } @@ -1038,12 +1036,10 @@ processFunction(SILFunction &F, bool EnableDiagnostics, // We were able to fold, so all users should use the new folded value. - assert(User->getTypes().size() == 1 && - "Currently, we only support single result instructions"); - SILValue(User).replaceAllUsesWith(C); + User->replaceAllUsesWith(C); // The new constant could be further folded now, add it to the worklist. - if (auto *Inst = dyn_cast(C.getDef())) + if (auto *Inst = dyn_cast(C)) WorkList.insert(Inst); } diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index 466a8573c60d2..018c3829e5290 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -177,7 +177,7 @@ emitElementAddress(unsigned EltNo, SILLocation Loc, SILBuilder &B) const { if (IsSelf) { if (auto *NTD = cast_or_null(PointeeType->getAnyNominal())) { - if (isa(NTD) && Ptr.getType().isAddress()) + if (isa(NTD) && Ptr->getType().isAddress()) Ptr = B.createLoad(Loc, Ptr); for (auto *VD : NTD->getStoredProperties()) { auto FieldType = VD->getType()->getCanonicalType(); @@ -333,7 +333,7 @@ onlyTouchesTrivialElements(const DIMemoryObjectInfo &MI) const { static void getScalarizedElementAddresses(SILValue Pointer, SILBuilder &B, SILLocation Loc, SmallVectorImpl &ElementAddrs) { - CanType AggType = Pointer.getType().getSwiftRValueType(); + CanType AggType = Pointer->getType().getSwiftRValueType(); TupleType *TT = AggType->castTo(); for (auto &Field : TT->getElements()) { (void)Field; @@ -347,7 +347,7 @@ static void getScalarizedElementAddresses(SILValue Pointer, SILBuilder &B, static void getScalarizedElements(SILValue V, SmallVectorImpl &ElementVals, SILLocation Loc, SILBuilder &B) { - TupleType *TT = V.getType().getSwiftRValueType()->castTo(); + TupleType *TT = V->getType().getSwiftRValueType()->castTo(); for (auto &Field : TT->getElements()) { (void)Field; ElementVals.push_back(B.emitTupleExtract(Loc, V, ElementVals.size())); @@ -432,14 +432,15 @@ namespace { // ref_element_addrs. collectClassSelfUses(); } else { - if (auto container = TheMemory.getContainer()) - collectContainerUses(container, TheMemory.getAddress()); - collectUses(TheMemory.getAddress(), 0); + if (auto *ABI = TheMemory.getContainer()) + collectContainerUses(ABI); + else + collectUses(TheMemory.getAddress(), 0); } if (!isa(TheMemory.MemoryInst)) { // Collect information about the retain count result as well. - for (auto UI : SILValue(TheMemory.MemoryInst, 0).getUses()) { + for (auto UI : TheMemory.MemoryInst->getUses()) { auto *User = UI->getUser(); // If this is a release or dealloc_stack, then remember it as such. @@ -453,7 +454,7 @@ namespace { private: void collectUses(SILValue Pointer, unsigned BaseEltNo); - void collectContainerUses(SILValue Container, SILValue Pointer); + void collectContainerUses(AllocBoxInst *ABI); void recordFailureBB(TermInst *TI, SILBasicBlock *BB); void recordFailableInitCall(SILInstruction *I); void collectClassSelfUses(); @@ -497,7 +498,7 @@ collectTupleElementUses(TupleElementAddrInst *TEAI, unsigned BaseEltNo) { // BaseElt. The uses hanging off the tuple_element_addr are going to be // counted as uses of the struct or enum itself. if (InStructSubElement || InEnumSubElement) - return collectUses(SILValue(TEAI, 0), BaseEltNo); + return collectUses(TEAI, BaseEltNo); assert(!IsSelfOfNonDelegatingInitializer && "self doesn't have tuple type"); @@ -510,7 +511,7 @@ collectTupleElementUses(TupleElementAddrInst *TEAI, unsigned BaseEltNo) { BaseEltNo += getElementCountRec(EltTy, false); } - collectUses(SILValue(TEAI, 0), BaseEltNo); + collectUses(TEAI, BaseEltNo); } void ElementUseCollector::collectStructElementUses(StructElementAddrInst *SEAI, @@ -520,7 +521,7 @@ void ElementUseCollector::collectStructElementUses(StructElementAddrInst *SEAI, // current element. if (!IsSelfOfNonDelegatingInitializer) { llvm::SaveAndRestore X(InStructSubElement, true); - collectUses(SILValue(SEAI, 0), BaseEltNo); + collectUses(SEAI, BaseEltNo); return; } @@ -536,42 +537,35 @@ void ElementUseCollector::collectStructElementUses(StructElementAddrInst *SEAI, BaseEltNo += getElementCountRec(FieldType, false); } - collectUses(SILValue(SEAI, 0), BaseEltNo); + collectUses(SEAI, BaseEltNo); } -void ElementUseCollector::collectContainerUses(SILValue container, - SILValue pointer) { - auto pointeeType = pointer.getType().getObjectType(); - for (auto UI : container.getUses()) { +void ElementUseCollector::collectContainerUses(AllocBoxInst *ABI) { + for (Operand *UI : ABI->getUses()) { auto *User = UI->getUser(); // Deallocations and retain/release don't affect the value directly. if (isa(User)) continue; - if (isa(User)) - continue; if (isa(User)) continue; if (isa(User)) continue; - // TODO: We should consider uses of project_box as equivalent to uses of - // the box element. For now, just consider them escapes. We would need - // to fix this if we phased out alloc_box's #1 result. - //if (isa(User)) { - // do something smart - // continue; - //} + if (isa(User)) { + collectUses(User, 0); + continue; + } // Other uses of the container are considered escapes of the value. - addElementUses(0, pointeeType, User, DIUseKind::Escape); + addElementUses(0, ABI->getElementType(), User, DIUseKind::Escape); } } void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { - assert(Pointer.getType().isAddress() && + assert(Pointer->getType().isAddress() && "Walked through the pointer to the value?"); - SILType PointeeType = Pointer.getType().getObjectType(); + SILType PointeeType = Pointer->getType().getObjectType(); /// This keeps track of instructions in the use list that touch multiple tuple /// elements and should be scalarized. This is done as a second phase to @@ -579,7 +573,7 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { /// SmallVector UsesToScalarize; - for (auto UI : Pointer.getUses()) { + for (auto UI : Pointer->getUses()) { auto *User = UI->getUser(); // struct_element_addr P, #field indexes into the current element. @@ -761,7 +755,7 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { // recursion that tuple stores are not scalarized outside, and that stores // should not be treated as partial stores. llvm::SaveAndRestore X(InEnumSubElement, true); - collectUses(SILValue(User, 0), BaseEltNo); + collectUses(User, BaseEltNo); continue; } @@ -797,6 +791,10 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { continue; } + if (isa(User)) { + continue; + } + // Otherwise, the use is something complicated, it escapes. addElementUses(BaseEltNo, PointeeType, User, DIUseKind::Escape); } @@ -820,7 +818,7 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) { // Scalarize LoadInst if (auto *LI = dyn_cast(User)) { SILValue Result = scalarizeLoad(LI, ElementAddrs); - SILValue(LI, 0).replaceAllUsesWith(Result); + LI->replaceAllUsesWith(Result); LI->eraseFromParent(); continue; } @@ -1171,7 +1169,7 @@ static bool isSelfInitUse(ValueMetatypeInst *Inst) { void ElementUseCollector:: collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType, llvm::SmallDenseMap &EltNumbering) { - for (auto UI : ClassPointer.getUses()) { + for (auto UI : ClassPointer->getUses()) { auto *User = UI->getUser(); // super_method always looks at the metatype for the class, not at any of @@ -1231,6 +1229,11 @@ collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType, // always fine, even if self is uninitialized. continue; } + + // If this is a partial application of self, then this is an escape point + // for it. + if (isa(User)) + Kind = DIUseKind::Escape; Uses.push_back(DIMemoryUse(User, Kind, 0, TheMemory.NumElements)); } @@ -1377,23 +1380,18 @@ void ElementUseCollector::collectDelegatingClassInitSelfUses() { Uses.push_back(DIMemoryUse(User, DIUseKind::Escape, 0, 1)); } - // The MUI must be used on an alloc_box or alloc_stack instruction. Chase + // The MUI must be used on a project_box or alloc_stack instruction. Chase // down the box value to see if there are any releases. - auto *AI = cast(MUI->getOperand()); - for (auto UI : SILValue(AI, 0).getUses()) { - SILInstruction *User = UI->getUser(); - - if (isa(User)) { - Releases.push_back(User); - continue; - } + if (isa(MUI->getOperand())) + return; - // Ignore the deallocation of the stack box. Its contents will be - // uninitialized by the point it executes. - if (isa(User)) - continue; + auto *PBI = cast(MUI->getOperand()); + auto *ABI = cast(PBI->getOperand()); - assert(0 && "Unknown use of box"); + for (auto UI : ABI->getUses()) { + SILInstruction *User = UI->getUser(); + if (isa(User)) + Releases.push_back(User); } } diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h index ef80816ac3dd4..5fd752abeb3f0 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -76,16 +76,16 @@ class DIMemoryObjectInfo { return MemorySILType.getSwiftRValueType(); } - SILValue getAddress() const { - if (isa(MemoryInst)) - return SILValue(MemoryInst, 0); - return SILValue(MemoryInst, 1); + SILInstruction *getAddress() const { + if (isa(MemoryInst) || + isa(MemoryInst)) + return MemoryInst; + assert(false); + return nullptr; } - SILValue getContainer() const { - if (isa(MemoryInst)) - return SILValue(); - return SILValue(MemoryInst, 0); + AllocBoxInst *getContainer() const { + return dyn_cast(MemoryInst); } /// getNumMemoryElements - Return the number of elements, without the extra @@ -110,7 +110,7 @@ class DIMemoryObjectInfo { return false; } - /// True if the memory object is the 'self' argument of a enum initializer. + /// True if the memory object is the 'self' argument of an enum initializer. bool isEnumInitSelf() const { if (auto *MUI = dyn_cast(MemoryInst)) if (MUI->isRootSelf()) diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index c1b59872be310..8665cad60357b 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -1,8 +1,8 @@ -//===-- DataflowDiagnostics.cpp - Emits diagnostics based on SIL analysis -===// +//===--- DataflowDiagnostics.cpp - Emits diagnostics based on SIL analysis ===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index 92c7bb00e5b99..e56cd6bdb752c 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -54,13 +54,13 @@ static void LowerAssignInstruction(SILBuilder &B, AssignInst *Inst, // assignment with a store. If it has non-trivial type and is an // initialization, we can also replace it with a store. if (isInitialization == IsInitialization || - Inst->getDest().getType().isTrivial(Inst->getModule())) { + Inst->getDest()->getType().isTrivial(Inst->getModule())) { B.createStore(Inst->getLoc(), Src, Inst->getDest()); } else { // Otherwise, we need to replace the assignment with the full // load/store/release dance. Note that the new value is already // considered to be retained (by the semantics of the storage type), - // and we're transfering that ownership count into the destination. + // and we're transferring that ownership count into the destination. // This is basically TypeLowering::emitStoreOfCopy, except that if we have // a known incoming value, we can avoid the load. @@ -629,7 +629,7 @@ bool LifetimeChecker::shouldEmitError(SILInstruction *Inst) { /// initializer. void LifetimeChecker::noteUninitializedMembers(const DIMemoryUse &Use) { assert(TheMemory.isAnyInitSelf() && !TheMemory.isDelegatingInit() && - "Not an designated initializer"); + "Not a designated initializer"); // Root protocol initializers (ones that reassign to self, not delegating to // self.init) have no members to initialize and self itself has already been @@ -1087,6 +1087,15 @@ void LifetimeChecker::handleEscapeUse(const DIMemoryUse &Use) { noteUninitializedMembers(Use); return; } + + if (isa(Inst) && TheMemory.isClassInitSelf()) { + if (!shouldEmitError(Inst)) return; + + diagnose(Module, Inst->getLoc(), diag::self_closure_use_uninit); + noteUninitializedMembers(Use); + return; + } + Diag DiagMessage; if (isa(Inst)) { @@ -1115,7 +1124,7 @@ void LifetimeChecker::handleEscapeUse(const DIMemoryUse &Use) { /// %6 = enum $Optional, #Optional.None!enumelt // user: %7 /// br bb2(%6 : $Optional) // id: %7 /// bb2(%8 : $Optional): // Preds: bb0 bb1 -/// dealloc_stack %1#0 : $*@local_storage Enum // id: %9 +/// dealloc_stack %1 : $*Enum // id: %9 /// return %8 : $Optional // id: %10 /// static bool isFailableInitReturnUseOfEnum(EnumInst *EI) { @@ -1183,7 +1192,7 @@ bool LifetimeChecker::diagnoseMethodCall(const DIMemoryUse &Use, ClassMethodInst *CMI = nullptr; ApplyInst *AI = nullptr; SILInstruction *Release = nullptr; - for (auto UI : SILValue(UCI, 0).getUses()) { + for (auto UI : UCI->getUses()) { auto *User = UI->getUser(); if (auto *TAI = dyn_cast(User)) { if (!AI) { @@ -1215,18 +1224,17 @@ bool LifetimeChecker::diagnoseMethodCall(const DIMemoryUse &Use, // the generic error that we would emit before. // // That is the only case where we support pattern matching a release. - if (Release && + if (Release && AI && !AI->getSubstCalleeType()->getExtInfo().hasGuaranteedSelfParam()) CMI = nullptr; if (AI && CMI) { // TODO: Could handle many other members more specifically. - auto *Decl = CMI->getMember().getDecl(); - Method = dyn_cast(Decl); + Method = dyn_cast(CMI->getMember().getDecl()); } } - // If this is an apply instruction and we're in an class initializer, we're + // If this is an apply instruction and we're in a class initializer, we're // calling a method on self. if (isa(Inst) && TheMemory.isClassInitSelf()) { // If this is a method application, produce a nice, specific, error. @@ -1235,12 +1243,40 @@ bool LifetimeChecker::diagnoseMethodCall(const DIMemoryUse &Use, // If this is a direct/devirt method application, check the location info. if (auto *Fn = cast(Inst)->getCalleeFunction()) { - if (Fn->hasLocation()) { - auto SILLoc = Fn->getLocation(); - Method = SILLoc.getAsASTNode(); + if (Fn->hasLocation()) + Method = Fn->getLocation().getAsASTNode(); + } + } + + // If this is part of a call to a witness method for a non-class-bound + // protocol in a root class, then we could have a store to a temporary whose + // address is passed into an apply. Look through this pattern. + if (auto *SI = dyn_cast(Inst)) { + if (SI->getSrc() == TheMemory.MemoryInst && + isa(SI->getDest()) && + TheMemory.isClassInitSelf()) { + ApplyInst *TheApply = nullptr; + // Check to see if the address of the alloc_stack is only passed to one + // apply_inst. + for (auto UI : SI->getDest()->getUses()) { + if (auto *ApplyUser = dyn_cast(UI->getUser())) { + if (!TheApply && UI->getOperandNumber() == 1) { + TheApply = ApplyUser; + } else { + TheApply = nullptr; + break; + } + } + } + + if (TheApply) { + if (auto *Fn = TheApply->getCalleeFunction()) + if (Fn->hasLocation()) + Method = Fn->getLocation().getAsASTNode(); } } } + // If we were able to find a method call, emit a diagnostic about the method. if (Method) { @@ -1615,11 +1651,12 @@ void LifetimeChecker::processUninitializedRelease(SILInstruction *Release, // for self. Make sure we're using its address result, not its refcount // result, and make sure that the box gets deallocated (not released) // since the pointer it contains will be manually cleaned up. - if (isa(Pointer)) - Pointer = SILValue(Pointer.getDef(), 1); + auto *ABI = dyn_cast(Release->getOperand(0)); + if (ABI) + Pointer = getOrCreateProjectBox(ABI); if (!consumed) { - if (Pointer.getType().isAddress()) + if (Pointer->getType().isAddress()) Pointer = B.createLoad(Loc, Pointer); auto MetatypeTy = CanMetatypeType::get( @@ -1642,7 +1679,7 @@ void LifetimeChecker::processUninitializedRelease(SILInstruction *Release, } // dealloc_box the self box if necessary. - if (auto *ABI = dyn_cast(Release->getOperand(0))) { + if (ABI) { auto DB = B.createDeallocBox(Loc, ABI->getElementType(), ABI); @@ -1664,7 +1701,7 @@ void LifetimeChecker::deleteDeadRelease(unsigned ReleaseID) { /// processNonTrivialRelease - We handle two kinds of release instructions here: /// destroy_addr for alloc_stack's and strong_release/dealloc_box for -/// alloc_box's. By the time that DI gets here, we've validated that all uses +/// alloc_box's. By the time that DI gets here, we've validated that all uses /// of the memory location are valid. Unfortunately, the uses being valid /// doesn't mean that the memory is actually initialized on all paths leading to /// a release. As such, we have to push the releases up the CFG to where the @@ -1750,7 +1787,7 @@ static void updateControlVariable(SILLocation Loc, SILValue ControlVariable, Identifier &OrFn, SILBuilder &B) { - SILType IVType = ControlVariable.getType().getObjectType(); + SILType IVType = ControlVariable->getType().getObjectType(); // Get the integer constant. SILValue MaskVal = B.createIntegerLiteral(Loc, IVType, Bitmask); @@ -1781,7 +1818,7 @@ static SILValue testControlVariable(SILLocation Loc, ControlVariable = B.createLoad(Loc, ControlVariableAddr); SILValue CondVal = ControlVariable; - CanBuiltinIntegerType IVType = CondVal.getType().castTo(); + CanBuiltinIntegerType IVType = CondVal->getType().castTo(); // If this memory object has multiple tuple elements, we need to make sure // to test the right one. @@ -1791,18 +1828,18 @@ static SILValue testControlVariable(SILLocation Loc, // Shift the mask down to this element. if (Elt != 0) { if (!ShiftRightFn.get()) - ShiftRightFn = getBinaryFunction("lshr", CondVal.getType(), + ShiftRightFn = getBinaryFunction("lshr", CondVal->getType(), B.getASTContext()); - SILValue Amt = B.createIntegerLiteral(Loc, CondVal.getType(), Elt); + SILValue Amt = B.createIntegerLiteral(Loc, CondVal->getType(), Elt); SILValue Args[] = { CondVal, Amt }; CondVal = B.createBuiltin(Loc, ShiftRightFn, - CondVal.getType(), {}, + CondVal->getType(), {}, Args); } if (!TruncateFn.get()) - TruncateFn = getTruncateToI1Function(CondVal.getType(), + TruncateFn = getTruncateToI1Function(CondVal->getType(), B.getASTContext()); return B.createBuiltin(Loc, TruncateFn, SILType::getBuiltinIntegerType(1, B.getASTContext()), @@ -1839,13 +1876,13 @@ SILValue LifetimeChecker::handleConditionalInitAssign() { auto *Term = BB.getTerminator(); if (isa(Term) || isa(Term)) { B.setInsertionPoint(Term); - B.createDeallocStack(Loc, ControlVariableBox->getContainerResult()); + B.createDeallocStack(Loc, ControlVariableBox); } } // Before the memory allocation, store zero in the control variable. - B.setInsertionPoint(TheMemory.MemoryInst->getNextNode()); - SILValue ControlVariableAddr = SILValue(ControlVariableBox, 1); + B.setInsertionPoint(&*std::next(TheMemory.MemoryInst->getIterator())); + SILValue ControlVariableAddr = ControlVariableBox; auto Zero = B.createIntegerLiteral(Loc, IVType, 0); B.createStore(Loc, Zero, ControlVariableAddr); @@ -2161,7 +2198,7 @@ computePredsLiveOut(SILBasicBlock *BB) { DEBUG(llvm::dbgs() << " Get liveness for block " << BB->getDebugID() << "\n"); // Collect blocks for which we have to calculate the out-availability. - // These are the pathes from blocks with known out-availability to the BB. + // These are the paths from blocks with known out-availability to the BB. WorkListType WorkList; for (auto Pred : BB->getPreds()) { putIntoWorkList(Pred, WorkList); @@ -2289,7 +2326,7 @@ getLivenessAtInst(SILInstruction *Inst, unsigned FirstElt, unsigned NumElts) { return Result; } - // Check locally to see if any elements are satified within the block, and + // Check locally to see if any elements are satisfied within the block, and // keep track of which ones are still needed in the NeededElements set. llvm::SmallBitVector NeededElements(TheMemory.NumElements); NeededElements.set(FirstElt, FirstElt+NumElts); @@ -2476,7 +2513,7 @@ static bool lowerRawSILOperations(SILFunction &Fn) { // mark_uninitialized just becomes a noop, resolving to its operand. if (auto *MUI = dyn_cast(Inst)) { - SILValue(MUI, 0).replaceAllUsesWith(MUI->getOperand()); + MUI->replaceAllUsesWith(MUI->getOperand()); MUI->eraseFromParent(); Changed = true; continue; diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp index 790cdba68e8ac..3cca342c79125 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,13 +60,13 @@ struct UnreachableInfo { /// removal stage of the path. /// /// To report unreachable user code, we detect the blocks that contain user -/// code and are not reachable (along any of the preceeding paths). Note that we +/// code and are not reachable (along any of the preceding paths). Note that we /// only want to report the first statement on the unreachable path. Keeping /// the info about which branch folding had produced the unreachable block makes /// it possible. class UnreachableUserCodeReportingState { public: - /// \brief The set of top-level blocks that became immediately unreachbale due + /// \brief The set of top-level blocks that became immediately unreachable due /// to conditional branch folding, etc. /// /// This is a SetVector since several blocks may lead to the same error @@ -78,7 +78,7 @@ class UnreachableUserCodeReportingState { /// /// Note, this set is different from the PossiblyUnreachableBlocks as these /// are the blocks that do contain user code and they might not be immediate - /// sucessors of a folded branch. + /// successors of a folded branch. llvm::SmallPtrSet BlocksWithErrors; /// A map from the PossiblyUnreachableBlocks to the folded conditional @@ -146,7 +146,7 @@ static void propagateBasicBlockArgs(SILBasicBlock &BB) { // If we've reached this point, the optimization is valid, so optimize. // We know that the incoming arguments from all predecessors are the same, - // so just use them directly and remove the basic block paramters. + // so just use them directly and remove the basic block parameters. // Drop the arguments from the branch instructions by creating a new branch // instruction and deleting the old one. @@ -171,9 +171,7 @@ static void propagateBasicBlockArgs(SILBasicBlock &BB) { SILArgument *Arg = *AI; // We were able to fold, so all users should use the new folded value. - assert(Arg->getTypes().size() == 1 && - "Currently, we only support single result instructions."); - SILValue(Arg).replaceAllUsesWith(Args[Idx]); + Arg->replaceAllUsesWith(Args[Idx]); NumBasicBlockArgsPropagated++; } @@ -200,7 +198,7 @@ static bool constantFoldTerminator(SILBasicBlock &BB, SILBuilderWithScope B(&BB, CBI); // Determine which of the successors is unreachable and create a new - // terminator that only branches to the reachable sucessor. + // terminator that only branches to the reachable successor. SILBasicBlock *UnreachableBlock = nullptr; bool CondIsTrue = false; if (ConstCond->getValue() == APInt(1, /*value*/ 0, false)) { @@ -267,8 +265,8 @@ static bool constantFoldTerminator(SILBasicBlock &BB, } } - // Not fully covered switches will be diagnosed later. SILGen represnets - // them with a Default basic block with an unrechable instruction. + // Not fully covered switches will be diagnosed later. SILGen represents + // them with a Default basic block with an unreachable instruction. // We are going to produce an error on all unreachable instructions not // eliminated by DCE. if (!TheSuccessorBlock) @@ -404,7 +402,7 @@ static void setOutsideBlockUsesToUndef(SILInstruction *I) { for (auto *Use : Uses) if (auto *User = dyn_cast(Use->getUser())) if (User->getParent() != BB) - Use->set(SILUndef::get(Use->get().getType(), Mod)); + Use->set(SILUndef::get(Use->get()->getType(), Mod)); } static SILInstruction *getAsCallToNoReturn(SILInstruction *I) { @@ -636,7 +634,7 @@ static bool diagnoseUnreachableBlock(const SILBasicBlock &B, return false; // If we have not found user code in this block, inspect it's successors. - // Check if at least one of the sucessors contains user code. + // Check if at least one of the successors contains user code. for (auto I = B.succ_begin(), E = B.succ_end(); I != E; ++I) { SILBasicBlock *SB = *I; bool HasReachablePred = false; @@ -645,7 +643,7 @@ static bool diagnoseUnreachableBlock(const SILBasicBlock &B, HasReachablePred = true; } - // If all of the predecessors of this sucessor are unreachable, check if + // If all of the predecessors of this successor are unreachable, check if // it contains user code. if (!HasReachablePred && diagnoseUnreachableBlock(*SB, M, Reachable, State, TopLevelB, Visited)) diff --git a/lib/SILOptimizer/Mandatory/InOutDeshadowing.cpp b/lib/SILOptimizer/Mandatory/InOutDeshadowing.cpp index 90acd99e19d62..a39dd32ca6fee 100644 --- a/lib/SILOptimizer/Mandatory/InOutDeshadowing.cpp +++ b/lib/SILOptimizer/Mandatory/InOutDeshadowing.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,9 +50,8 @@ static void promoteShadow(AllocStackInst *Alloc, SILArgument *InOutArg) { auto Use = *Alloc->use_begin(); auto *User = Use->getUser(); - // If this is a use of the 0th result, not the address result, just zap the - // instruction. It is a dealloc_stack or something similar. - if (Use->get().getResultNumber() == 0) { + // If this is the dealloc_stack, just zap the instruction. + if (isa(User)) { User->eraseFromParent(); continue; } diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index f4a1afc365479..6c7deabb568e6 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,7 +60,7 @@ static void fixupReferenceCounts(SILBasicBlock::iterator I, SILLocation Loc, // Add a retain of each non-address type capture argument, because it will be // consumed by the closure body. for (auto &CaptureArg : CaptureArgs) - if (!CaptureArg.getType().isAddress()) + if (!CaptureArg->getType().isAddress()) B.emitRetainValueOperation(Loc, CaptureArg); } @@ -72,7 +72,7 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, SmallVector InstsToDelete; for (SILValue V : FullArgs) { if (SILInstruction *I = dyn_cast(V)) - if (I != CalleeValue.getDef() && + if (I != CalleeValue && isInstructionTriviallyDead(I)) InstsToDelete.push_back(I); } @@ -80,9 +80,8 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, // Handle the case where the callee of the apply is a load instruction. if (LoadInst *LI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); - SILInstruction *ABI = dyn_cast(LI->getOperand()); - assert(ABI && LI->getOperand().getResultNumber() == 1); + auto *PBI = cast(LI->getOperand()); + auto *ABI = cast(PBI->getOperand()); // The load instruction must have no more uses left to erase it. if (!LI->use_empty()) @@ -91,15 +90,17 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, // Look through uses of the alloc box the load is loading from to find up to // one store and up to one strong release. - StoreInst *SI = nullptr; StrongReleaseInst *SRI = nullptr; - for (auto UI = ABI->use_begin(), UE = ABI->use_end(); UI != UE; ++UI) { - if (SI == nullptr && isa(UI.getUser())) { - SI = cast(UI.getUser()); - assert(SI->getDest() == SILValue(ABI, 1)); - } else if (SRI == nullptr && isa(UI.getUser())) { - SRI = cast(UI.getUser()); - assert(SRI->getOperand() == SILValue(ABI, 0)); + for (Operand *ABIUse : ABI->getUses()) { + if (SRI == nullptr && isa(ABIUse->getUser())) { + SRI = cast(ABIUse->getUser()); + } else if (ABIUse->getUser() != PBI) + return; + } + StoreInst *SI = nullptr; + for (Operand *PBIUse : PBI->getUses()) { + if (SI == nullptr && isa(PBIUse->getUser())) { + SI = cast(PBIUse->getUser()); } else return; } @@ -115,21 +116,21 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, // If we found a strong release, replace it with a strong release of the // source of the store and erase it. if (SRI) { - if (CalleeValue.isValid()) + if (CalleeValue) SILBuilderWithScope(SRI) .emitStrongReleaseAndFold(SRI->getLoc(), CalleeValue); SRI->eraseFromParent(); } + assert(PBI->use_empty()); + PBI->eraseFromParent(); assert(ABI->use_empty()); ABI->eraseFromParent(); - if (!CalleeValue.isValid()) + if (!CalleeValue) return; } if (auto *PAI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); - SILValue Callee = PAI->getCallee(); if (!tryDeleteDeadClosure(PAI)) return; @@ -137,7 +138,6 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, } if (auto *TTTFI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); SILValue Callee = TTTFI->getCallee(); if (!tryDeleteDeadClosure(TTTFI)) return; @@ -145,7 +145,6 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef CaptureArgs, } if (FunctionRefInst *FRI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); if (!FRI->use_empty()) return; FRI->eraseFromParent(); @@ -176,13 +175,21 @@ getCalleeFunction(FullApplySite AI, bool &IsThick, SILValue CalleeValue = AI.getCallee(); if (LoadInst *LI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); // Conservatively only see through alloc_box; we assume this pass is run // immediately after SILGen - SILInstruction *ABI = dyn_cast(LI->getOperand()); + auto *PBI = dyn_cast(LI->getOperand()); + if (!PBI) + return nullptr; + auto *ABI = dyn_cast(PBI->getOperand()); if (!ABI) return nullptr; - assert(LI->getOperand().getResultNumber() == 1); + // Ensure there are no other uses of alloc_box than the project_box and + // retains, releases. + for (Operand *ABIUse : ABI->getUses()) + if (ABIUse->getUser() != PBI && + !isa(ABIUse->getUser()) && + !isa(ABIUse->getUser())) + return nullptr; // Scan forward from the alloc box to find the first store, which // (conservatively) must be in the same basic block as the alloc box @@ -194,15 +201,11 @@ getCalleeFunction(FullApplySite AI, bool &IsThick, // making any assumptions if (static_cast(I) == LI) return nullptr; - if ((SI = dyn_cast(I)) && SI->getDest().getDef() == ABI) { + if ((SI = dyn_cast(I)) && SI->getDest() == PBI) { // We found a store that we know dominates the load; now ensure there - // are no other uses of the alloc other than loads, retains, releases - // and dealloc stacks - for (auto UI = ABI->use_begin(), UE = ABI->use_end(); UI != UE; - ++UI) - if (UI.getUser() != SI && !isa(UI.getUser()) && - !isa(UI.getUser()) && - !isa(UI.getUser())) + // are no other uses of the project_box except loads. + for (Operand *PBIUse : PBI->getUses()) + if (PBIUse->getUser() != SI && !isa(PBIUse->getUser())) return nullptr; // We can conservatively see through the store break; @@ -218,8 +221,6 @@ getCalleeFunction(FullApplySite AI, bool &IsThick, // generated when using auto closures. if (PartialApplyInst *PAI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); - for (const auto &Arg : PAI->getArguments()) { CaptureArgs.push_back(Arg); FullArgs.push_back(Arg); @@ -230,7 +231,6 @@ getCalleeFunction(FullApplySite AI, bool &IsThick, PartialApply = PAI; } else if (ThinToThickFunctionInst *TTTFI = dyn_cast(CalleeValue)) { - assert(CalleeValue.getResultNumber() == 0); CalleeValue = TTTFI->getOperand(); IsThick = true; } @@ -348,7 +348,7 @@ runOnFunctionRecursively(SILFunction *F, FullApplySite AI, // trace back the failure if we have more information. // FIXME: possibly it could be worth recovering and attempting other // inlines within this same recursive call rather than simply - // propogating the failure. + // propagating the failure. if (AI) { SILLocation L = AI.getLoc(); assert(L && "Must have location for transparent inline apply"); diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 63ef17c779e32..6608537b45b5c 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -86,7 +86,7 @@ static SILValue getAccessPathRoot(SILValue Pointer) { /// /// This will return a subelement number of 2. /// -/// If this pointer is to within a existential projection, it returns ~0U. +/// If this pointer is to within an existential projection, it returns ~0U. /// static unsigned computeSubelement(SILValue Pointer, SILInstruction *RootInst) { unsigned SubEltNumber = 0; @@ -94,12 +94,14 @@ static unsigned computeSubelement(SILValue Pointer, SILInstruction *RootInst) { while (1) { // If we got to the root, we're done. - if (RootInst == Pointer.getDef()) + if (RootInst == Pointer) return SubEltNumber; auto *Inst = cast(Pointer); - if (auto *TEAI = dyn_cast(Inst)) { - SILType TT = TEAI->getOperand().getType(); + if (auto *PBI = dyn_cast(Inst)) { + Pointer = PBI->getOperand(); + } else if (auto *TEAI = dyn_cast(Inst)) { + SILType TT = TEAI->getOperand()->getType(); // Keep track of what subelement is being referenced. for (unsigned i = 0, e = TEAI->getFieldNo(); i != e; ++i) { @@ -107,7 +109,7 @@ static unsigned computeSubelement(SILValue Pointer, SILInstruction *RootInst) { } Pointer = TEAI->getOperand(); } else if (auto *SEAI = dyn_cast(Inst)) { - SILType ST = SEAI->getOperand().getType(); + SILType ST = SEAI->getOperand()->getType(); // Keep track of what subelement is being referenced. StructDecl *SD = SEAI->getStructDecl(); @@ -132,7 +134,7 @@ static unsigned computeSubelement(SILValue Pointer, SILInstruction *RootInst) { /// the path. static SILValue ExtractSubElement(SILValue Val, unsigned SubElementNumber, SILBuilder &B, SILLocation Loc) { - SILType ValTy = Val.getType(); + SILType ValTy = Val->getType(); // Extract tuple elements. if (auto TT = ValTy.getAs()) { @@ -308,7 +310,7 @@ updateAvailableValues(SILInstruction *Inst, llvm::SmallBitVector &RequiredElts, if (isa(Inst) || isa(Inst)) { unsigned StartSubElt = computeSubelement(Inst->getOperand(1), TheMemory); assert(StartSubElt != ~0U && "Store within enum projection not handled"); - SILType ValTy = Inst->getOperand(0).getType(); + SILType ValTy = Inst->getOperand(0)->getType(); for (unsigned i = 0, e = getNumSubElements(ValTy, Module); i != e; ++i) { // If this element is not required, don't fill it in. @@ -336,7 +338,7 @@ updateAvailableValues(SILInstruction *Inst, llvm::SmallBitVector &RequiredElts, if (auto *CAI = dyn_cast(Inst)) { unsigned StartSubElt = computeSubelement(Inst->getOperand(1), TheMemory); assert(StartSubElt != ~0U && "Store within enum projection not handled"); - SILType ValTy = Inst->getOperand(1).getType(); + SILType ValTy = Inst->getOperand(1)->getType(); bool AnyRequired = false; for (unsigned i = 0, e = getNumSubElements(ValTy, Module); i != e; ++i) { @@ -350,9 +352,9 @@ updateAvailableValues(SILInstruction *Inst, llvm::SmallBitVector &RequiredElts, if (!AnyRequired) return; - // If the copyaddr is of an non-loadable type, we can't promote it. Just + // If the copyaddr is of a non-loadable type, we can't promote it. Just // consider it to be a clobber. - if (CAI->getOperand(0).getType().isLoadable(Module)) { + if (CAI->getOperand(0)->getType().isLoadable(Module)) { // Otherwise, some part of the copy_addr's value is demanded by a load, so // we need to explode it to its component pieces. This only expands one // level of the copyaddr. @@ -483,7 +485,7 @@ computeAvailableValuesFrom(SILBasicBlock::iterator StartingFrom, static bool anyMissing(unsigned StartSubElt, unsigned NumSubElts, ArrayRef> &Values) { while (NumSubElts) { - if (!Values[StartSubElt].first.isValid()) return true; + if (!Values[StartSubElt].first) return true; ++StartSubElt; --NumSubElts; } @@ -507,8 +509,8 @@ AggregateAvailableValues(SILInstruction *Inst, SILType LoadTy, // general answer for arbitrary structs and tuples as well. if (FirstElt < AvailableValues.size()) { // #Elements may be zero. SILValue FirstVal = AvailableValues[FirstElt].first; - if (FirstVal.isValid() && AvailableValues[FirstElt].second == 0 && - FirstVal.getType() == LoadTy) { + if (FirstVal && AvailableValues[FirstElt].second == 0 && + FirstVal->getType() == LoadTy) { // If the first element of this value is available, check any extra ones // before declaring success. bool AllMatch = true; @@ -574,12 +576,12 @@ AggregateAvailableValues(SILInstruction *Inst, SILType LoadTy, // Otherwise, we have a simple primitive. If the value is available, use it, // otherwise emit a load of the value. auto Val = AvailableValues[FirstElt]; - if (!Val.first.isValid()) + if (!Val.first) return B.createLoad(Inst->getLoc(), Address); SILValue EltVal = ExtractSubElement(Val.first, Val.second, B, Inst->getLoc()); // It must be the same type as LoadTy if available. - assert(EltVal.getType() == LoadTy && + assert(EltVal->getType() == LoadTy && "Subelement types mismatch"); return EltVal; } @@ -603,7 +605,7 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) { if (auto CAI = dyn_cast(Inst)) { // If this is a CopyAddr, verify that the element type is loadable. If not, // we can't explode to a load. - if (!CAI->getSrc().getType().isLoadable(Module)) + if (!CAI->getSrc()->getType().isLoadable(Module)) return false; } else if (!isa(Inst)) return false; @@ -613,7 +615,7 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) { if (hasEscapedAt(Inst)) return false; - SILType LoadTy = Inst->getOperand(0).getType().getObjectType(); + SILType LoadTy = Inst->getOperand(0)->getType().getObjectType(); // If this is a load/copy_addr from a struct field that we want to promote, // compute the access path down to the field so we can determine precise @@ -643,7 +645,7 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) { // promote this load and there is nothing to do. bool AnyAvailable = false; for (unsigned i = FirstElt, e = i+NumLoadSubElements; i != e; ++i) - if (AvailableValues[i].first.isValid()) { + if (AvailableValues[i].first) { AnyAvailable = true; break; } @@ -674,9 +676,9 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) { // Simply replace the load. assert(isa(Inst)); DEBUG(llvm::dbgs() << " *** Promoting load: " << *Inst << "\n"); - DEBUG(llvm::dbgs() << " To value: " << *NewVal.getDef() << "\n"); + DEBUG(llvm::dbgs() << " To value: " << *NewVal << "\n"); - SILValue(Inst, 0).replaceAllUsesWith(NewVal); + Inst->replaceAllUsesWith(NewVal); SILValue Addr = Inst->getOperand(0); Inst->eraseFromParent(); if (auto *AddrI = dyn_cast(Addr)) @@ -695,7 +697,7 @@ bool AllocOptimize::promoteDestroyAddr(DestroyAddrInst *DAI) { // We cannot promote destroys of address-only types, because we can't expose // the load. - SILType LoadTy = Address.getType().getObjectType(); + SILType LoadTy = Address->getType().getObjectType(); if (LoadTy.isAddressOnly(Module)) return false; @@ -724,7 +726,7 @@ bool AllocOptimize::promoteDestroyAddr(DestroyAddrInst *DAI) { // If some value is not available at this load point, then we fail. for (unsigned i = FirstElt, e = FirstElt+NumLoadSubElements; i != e; ++i) - if (!AvailableValues[i].first.isValid()) + if (!AvailableValues[i].first) return false; } @@ -737,7 +739,7 @@ bool AllocOptimize::promoteDestroyAddr(DestroyAddrInst *DAI) { ++NumDestroyAddrPromoted; DEBUG(llvm::dbgs() << " *** Promoting destroy_addr: " << *DAI << "\n"); - DEBUG(llvm::dbgs() << " To value: " << *NewVal.getDef() << "\n"); + DEBUG(llvm::dbgs() << " To value: " << *NewVal << "\n"); SILBuilderWithScope(DAI).emitReleaseValueOperation(DAI->getLoc(), NewVal); DAI->eraseFromParent(); @@ -751,7 +753,7 @@ bool AllocOptimize::promoteDestroyAddr(DestroyAddrInst *DAI) { void AllocOptimize::explodeCopyAddr(CopyAddrInst *CAI) { DEBUG(llvm::dbgs() << " -- Exploding copy_addr: " << *CAI << "\n"); - SILType ValTy = CAI->getDest().getType().getObjectType(); + SILType ValTy = CAI->getDest()->getType().getObjectType(); auto &TL = Module.getTypeLowering(ValTy); // Keep track of the new instructions emitted. @@ -824,7 +826,7 @@ void AllocOptimize::explodeCopyAddr(CopyAddrInst *CAI) { // for the copy_addr source, or it could be a load corresponding to the // "assign" operation on the destination of the copyaddr. if (LoadUse.isValid() && - getAccessPathRoot(NewInst->getOperand(0)).getDef() == TheMemory) { + getAccessPathRoot(NewInst->getOperand(0)) == TheMemory) { LoadUse.Inst = NewInst; Uses.push_back(LoadUse); } @@ -923,7 +925,7 @@ bool AllocOptimize::tryToRemoveDeadAllocation() { bool AllocOptimize::doIt() { bool Changed = false; - // Don't try to optimize incomplete aggregates. + // Don't try to optimize incomplete aggregates. if (MemoryType.aggregateHasUnreferenceableStorage()) return false; diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index 3e1b2eb6e94fc..f664d8edf8822 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -1,8 +1,8 @@ -//===----- PassManager.cpp - Swift Pass Manager ---------------------------===// +//===--- PassManager.cpp - Swift Pass Manager -----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,6 +22,7 @@ #include "llvm/ADT/StringSwitch.h" #include "swift/SILOptimizer/Analysis/FunctionOrder.h" #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TimeValue.h" @@ -53,7 +54,8 @@ llvm::cl::opt llvm::cl::opt SILPrintOnlyFuns("sil-print-only-functions", llvm::cl::init(""), - llvm::cl::desc("Only print out the sil for the functions whose name contains this substring")); + llvm::cl::desc("Only print out the sil for the functions " + "whose name contains this substring")); llvm::cl::list SILPrintBefore("sil-print-before", @@ -166,95 +168,123 @@ bool SILPassManager::continueTransforming() { NumPassesRun < SILNumOptPassesToRun; } -void SILPassManager::runFunctionPasses(PassList FuncTransforms) { +void SILPassManager::runPassesOnFunction(PassList FuncTransforms, + SILFunction *F) { + const SILOptions &Options = getOptions(); - BasicCalleeAnalysis *BCA = getAnalysis(); - BottomUpFunctionOrder BottomUpOrder(*Mod, BCA); - auto BottomUpFunctions = BottomUpOrder.getFunctions(); + CompletedPasses &completedPasses = CompletedPassesMap[F]; - // Build an initial work list of functions to optimize. - llvm::SmallVector WorkList; - for (auto I = BottomUpFunctions.rbegin(), E = BottomUpFunctions.rend(); - I != E; ++I) { - auto &F = **I; + for (auto SFT : FuncTransforms) { + PrettyStackTraceSILFunctionTransform X(SFT); + SFT->injectPassManager(this); + SFT->injectFunction(F); - // Only include functions that are definitions, and which have not - // been intentionally excluded from optimization. - if (F.isDefinition() && F.shouldOptimize()) - WorkList.push_back(*I); - } + // If nothing changed since the last run of this pass, we can skip this + // pass. + if (completedPasses.test((size_t)SFT->getPassKind())) + continue; - while (!WorkList.empty()) { - auto *F = WorkList.back(); + if (isDisabled(SFT)) + continue; - CompletedPasses &completedPasses = CompletedPassesMap[F]; + CurrentPassHasInvalidated = false; - for (auto SFT : FuncTransforms) { - PrettyStackTraceSILFunctionTransform X(SFT); - SFT->injectPassManager(this); - SFT->injectFunction(F); + if (SILPrintPassName) + llvm::dbgs() << "#" << NumPassesRun << " Stage: " << StageName + << " Pass: " << SFT->getName() + << ", Function: " << F->getName() << "\n"; - // If nothing changed since the last run of this pass, we can skip this - // pass. - if (completedPasses.test((size_t)SFT->getPassKind())) - continue; + if (doPrintBefore(SFT, F)) { + llvm::dbgs() << "*** SIL function before " << StageName << " " + << SFT->getName() << " (" << NumOptimizationIterations + << ") ***\n"; + F->dump(Options.EmitVerboseSIL); + } - if (isDisabled(SFT)) - continue; + llvm::sys::TimeValue StartTime = llvm::sys::TimeValue::now(); + Mod->registerDeleteNotificationHandler(SFT); + SFT->run(); + Mod->removeDeleteNotificationHandler(SFT); - currentPassHasInvalidated = false; + // Did running the transform result in new functions being added + // to the top of our worklist? + bool newFunctionsAdded = (F != FunctionWorklist.back()); - if (SILPrintPassName) - llvm::dbgs() << "#" << NumPassesRun << " Stage: " << StageName - << " Pass: " << SFT->getName() - << ", Function: " << F->getName() << "\n"; + if (SILPrintPassTime) { + auto Delta = + llvm::sys::TimeValue::now().nanoseconds() - StartTime.nanoseconds(); + llvm::dbgs() << Delta << " (" << SFT->getName() << "," << F->getName() + << ")\n"; + } - if (doPrintBefore(SFT, F)) { - llvm::dbgs() << "*** SIL function before " << StageName << " " - << SFT->getName() << " (" << NumOptimizationIterations - << ") ***\n"; - F->dump(Options.EmitVerboseSIL); - } + // If this pass invalidated anything, print and verify. + if (doPrintAfter(SFT, F, CurrentPassHasInvalidated && SILPrintAll)) { + llvm::dbgs() << "*** SIL function after " << StageName << " " + << SFT->getName() << " (" << NumOptimizationIterations + << ") ***\n"; + F->dump(Options.EmitVerboseSIL); + } - llvm::sys::TimeValue StartTime = llvm::sys::TimeValue::now(); - Mod->registerDeleteNotificationHandler(SFT); - SFT->run(); - Mod->removeDeleteNotificationHandler(SFT); + // Remember if this pass didn't change anything. + if (!CurrentPassHasInvalidated) + completedPasses.set((size_t)SFT->getPassKind()); - if (SILPrintPassTime) { - auto Delta = llvm::sys::TimeValue::now().nanoseconds() - - StartTime.nanoseconds(); - llvm::dbgs() << Delta << " (" << SFT->getName() << "," << F->getName() - << ")\n"; - } + if (Options.VerifyAll && + (CurrentPassHasInvalidated || SILVerifyWithoutInvalidation)) { + F->verify(); + verifyAnalyses(F); + } - // If this pass invalidated anything, print and verify. - if (doPrintAfter(SFT, F, - currentPassHasInvalidated && SILPrintAll)) { - llvm::dbgs() << "*** SIL function after " << StageName << " " - << SFT->getName() << " (" << NumOptimizationIterations - << ") ***\n"; - F->dump(Options.EmitVerboseSIL); - } + ++NumPassesRun; - // Remember if this pass didn't change anything. - if (!currentPassHasInvalidated) - completedPasses.set((size_t)SFT->getPassKind()); + // If running the transform resulted in new functions on the top + // of the worklist, we'll return so that we can begin processing + // those new functions. + if (newFunctionsAdded || !continueTransforming()) + return; + } +} - if (Options.VerifyAll && - (currentPassHasInvalidated || SILVerifyWithoutInvalidation)) { - F->verify(); - verifyAnalyses(F); - } +void SILPassManager::runFunctionPasses(PassList FuncTransforms) { + BasicCalleeAnalysis *BCA = getAnalysis(); + BottomUpFunctionOrder BottomUpOrder(*Mod, BCA); + auto BottomUpFunctions = BottomUpOrder.getFunctions(); - ++NumPassesRun; - if (!continueTransforming()) - return; - } + assert(FunctionWorklist.empty() && "Expected empty function worklist!"); + + FunctionWorklist.reserve(BottomUpFunctions.size()); + for (auto I = BottomUpFunctions.rbegin(), E = BottomUpFunctions.rend(); + I != E; ++I) { + auto &F = **I; + + // Only include functions that are definitions, and which have not + // been intentionally excluded from optimization. + if (F.isDefinition() && F.shouldOptimize()) + FunctionWorklist.push_back(*I); + } + + // Used to track how many times a given function has been + // (partially) optimized by the function pass pipeline in this + // invocation. + llvm::DenseMap CountOptimized; + + // Pop functions off the worklist, and run all function transforms + // on each of them. + while (!FunctionWorklist.empty() && continueTransforming()) { + auto *F = FunctionWorklist.back(); - // Pop the function we just processed off the work list. - WorkList.pop_back(); + runPassesOnFunction(FuncTransforms, F); + + ++CountOptimized[F]; + + // If running the function transforms did not result in new + // functions being added to the top of the worklist, then we're + // done with this function and can pop it off and continue. + // Otherwise, we'll return to this function and reoptimize after + // processing the new functions that were added. + if (F == FunctionWorklist.back()) + FunctionWorklist.pop_back(); } } @@ -269,7 +299,7 @@ void SILPassManager::runModulePass(SILModuleTransform *SMT) { SMT->injectPassManager(this); SMT->injectModule(Mod); - currentPassHasInvalidated = false; + CurrentPassHasInvalidated = false; if (SILPrintPassName) llvm::dbgs() << "#" << NumPassesRun << " Stage: " << StageName @@ -295,7 +325,7 @@ void SILPassManager::runModulePass(SILModuleTransform *SMT) { // If this pass invalidated anything, print and verify. if (doPrintAfter(SMT, nullptr, - currentPassHasInvalidated && SILPrintAll)) { + CurrentPassHasInvalidated && SILPrintAll)) { llvm::dbgs() << "*** SIL module after " << StageName << " " << SMT->getName() << " (" << NumOptimizationIterations << ") ***\n"; @@ -303,7 +333,7 @@ void SILPassManager::runModulePass(SILModuleTransform *SMT) { } if (Options.VerifyAll && - (currentPassHasInvalidated || !SILVerifyWithoutInvalidation)) { + (CurrentPassHasInvalidated || !SILVerifyWithoutInvalidation)) { Mod->verify(); verifyAnalyses(); } @@ -335,7 +365,7 @@ void SILPassManager::runOneIteration() { // module transforms. We'll queue up all the function transforms // that we see in a row and then run the entire group of transforms // on each function in turn. Then we move on to running the next set - // of consequtive module transforms. + // of consecutive module transforms. auto It = Transformations.begin(); auto End = Transformations.end(); @@ -403,7 +433,7 @@ SILPassManager::~SILPassManager() { } /// \brief Reset the state of the pass manager and remove all transformation -/// owned by the pass manager. Anaysis passes will be kept. +/// owned by the pass manager. Analysis passes will be kept. void SILPassManager::resetAndRemoveTransformations() { for (auto T : Transformations) delete T; @@ -422,21 +452,21 @@ const SILOptions &SILPassManager::getOptions() const { // Define the add-functions for all passes. -#define PASS(ID, NAME, DESCRIPTION) \ -void SILPassManager::add##ID() { \ - SILTransform *T = swift::create##ID(); \ - T->setPassKind(PassKind::ID); \ - Transformations.push_back(T); \ -} +#define PASS(ID, NAME, DESCRIPTION) \ + void SILPassManager::add##ID() { \ + SILTransform *T = swift::create##ID(); \ + T->setPassKind(PassKind::ID); \ + Transformations.push_back(T); \ + } #include "swift/SILOptimizer/PassManager/Passes.def" void SILPassManager::addPass(PassKind Kind) { assert(unsigned(PassKind::AllPasses_Last) >= unsigned(Kind) && "Invalid pass kind"); switch (Kind) { -#define PASS(ID, NAME, DESCRIPTION) \ - case PassKind::ID: \ - add##ID(); \ +#define PASS(ID, NAME, DESCRIPTION) \ + case PassKind::ID: \ + add##ID(); \ break; #include "swift/SILOptimizer/PassManager/Passes.def" case PassKind::invalidPassKind: @@ -479,8 +509,9 @@ namespace { SmallVector Children; }; - struct child_iterator : public std::iterator { + struct child_iterator + : public std::iterator { SmallVectorImpl::iterator baseIter; child_iterator(SmallVectorImpl::iterator baseIter) : @@ -488,7 +519,11 @@ namespace { { } child_iterator &operator++() { baseIter++; return *this; } - child_iterator operator++(int) { auto tmp = *this; baseIter++; return tmp; } + child_iterator operator++(int) { + auto tmp = *this; + baseIter++; + return tmp; + } Node *operator*() const { return baseIter->Child; } bool operator==(const child_iterator &RHS) const { return baseIter == RHS.baseIter; diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp index 9ccd4972fa006..68da7c6511d1e 100644 --- a/lib/SILOptimizer/PassManager/Passes.cpp +++ b/lib/SILOptimizer/PassManager/Passes.cpp @@ -1,8 +1,8 @@ -//===-------- Passes.cpp - Swift Compiler SIL Pass Entrypoints ------------===// +//===--- Passes.cpp - Swift Compiler SIL Pass Entrypoints -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,13 +40,13 @@ llvm::cl::opt SILViewCFG("sil-view-cfg", llvm::cl::init(false), llvm::cl::desc("Enable the sil cfg viewer pass")); -llvm::cl::opt - SILViewGuaranteedCFG("sil-view-guaranteed-cfg", llvm::cl::init(false), - llvm::cl::desc("Enable the sil cfg viewer pass after diagnostics")); +llvm::cl::opt SILViewGuaranteedCFG( + "sil-view-guaranteed-cfg", llvm::cl::init(false), + llvm::cl::desc("Enable the sil cfg viewer pass after diagnostics")); -llvm::cl::opt - SILViewSILGenCFG("sil-view-silgen-cfg", llvm::cl::init(false), - llvm::cl::desc("Enable the sil cfg viewer pass before diagnostics")); +llvm::cl::opt SILViewSILGenCFG( + "sil-view-silgen-cfg", llvm::cl::init(false), + llvm::cl::desc("Enable the sil cfg viewer pass before diagnostics")); using namespace swift; @@ -251,6 +251,8 @@ void swift::runSILOptimizationPasses(SILModule &Module) { // Run two iterations of the high-level SSA passes. PM.setStageName("HighLevel"); + PM.addDevirtualizer(); + PM.addGenericSpecializer(); AddSSAPasses(PM, OptimizationLevelKind::HighLevel); PM.runOneIteration(); PM.runOneIteration(); @@ -450,7 +452,8 @@ descriptorsForFile(StringRef Filename, auto *RootList = cast(N); - for (auto &PMDescriptorIter : make_range(RootList->begin(), RootList->end())) { + for (auto &PMDescriptorIter : + make_range(RootList->begin(), RootList->end())) { PMDescriptor PM(cast(&PMDescriptorIter)); Descriptors.push_back(std::move(PM)); } diff --git a/lib/SILOptimizer/PassManager/PrettyStackTrace.cpp b/lib/SILOptimizer/PassManager/PrettyStackTrace.cpp index 06f94ebb3aa42..5e94a442dad1f 100644 --- a/lib/SILOptimizer/PassManager/PrettyStackTrace.cpp +++ b/lib/SILOptimizer/PassManager/PrettyStackTrace.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index b87973a8ddc36..e99b2dfb2fc2e 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -1,8 +1,8 @@ -//===-------------------------- SILCombine --------------------------------===// +//===--- SILCombine -------------------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -147,13 +147,13 @@ bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) { ++NumSimplified; DEBUG(llvm::dbgs() << "SC: Simplify Old = " << *I << '\n' - << " New = " << *Result.getDef() << '\n'); + << " New = " << *Result << '\n'); // Everything uses the new instruction now. - replaceInstUsesWith(*I, Result.getDef(), 0, Result.getResultNumber()); + replaceInstUsesWith(*I, Result); // Push the new instruction and any users onto the worklist. - Worklist.addUsersToWorklist(Result.getDef()); + Worklist.addUsersToWorklist(Result); eraseInstFromFunction(*I); MadeChange = true; @@ -211,11 +211,11 @@ bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) { // the next iteration. auto &TrackingList = *Builder.getTrackingList(); for (SILInstruction *I : TrackingList) { - if (!DeletedInstSet.count(I)) - Worklist.add(I); + DEBUG(llvm::dbgs() << "SC: add " << *I << + " from tracking list to worklist\n"); + Worklist.add(I); } TrackingList.clear(); - DeletedInstSet.clear(); } Worklist.zap(); @@ -263,7 +263,7 @@ SILInstruction *SILCombiner::insertNewInstBefore(SILInstruction *New, } // This method is to be used when an instruction is found to be dead, -// replacable with another preexisting expression. Here we add all uses of I +// replaceable with another preexisting expression. Here we add all uses of I // to the worklist, replace all uses of I with the new value, then return I, // so that the combiner will know that I was modified. SILInstruction *SILCombiner::replaceInstUsesWith(SILInstruction &I, @@ -278,30 +278,8 @@ SILInstruction *SILCombiner::replaceInstUsesWith(SILInstruction &I, return &I; } -/// This is meant to be used when one is attempting to replace only one of the -/// results of I with a result of V. -SILInstruction * -SILCombiner:: -replaceInstUsesWith(SILInstruction &I, ValueBase *V, unsigned IIndex, - unsigned VIndex) { - assert(IIndex < I.getNumTypes() && "Can not have more results than " - "types."); - assert(VIndex < V->getNumTypes() && "Can not have more results than " - "types."); - - // Add all modified instrs to worklist. - Worklist.addUsersToWorklist(&I, IIndex); - - DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n" - " with " << *V << '\n'); - - SILValue(&I, IIndex).replaceAllUsesWith(SILValue(V, VIndex)); - - return &I; -} - // Some instructions can never be "trivially dead" due to side effects or -// producing a void value. In those cases, since we can not rely on +// producing a void value. In those cases, since we cannot rely on // SILCombines trivially dead instruction DCE in order to delete the // instruction, visit methods should use this method to delete the given // instruction and upon completion of their peephole return the value returned @@ -314,17 +292,21 @@ SILInstruction *SILCombiner::eraseInstFromFunction(SILInstruction &I, assert(hasNoUsesExceptDebug(&I) && "Cannot erase instruction that is used!"); // Make sure that we reprocess all operands now that we reduced their // use counts. - if (I.getNumOperands() < 8 && AddOperandsToWorklist) - for (auto &OpI : I.getAllOperands()) - if (SILInstruction *Op = llvm::dyn_cast(&*OpI.get())) + if (I.getNumOperands() < 8 && AddOperandsToWorklist) { + for (auto &OpI : I.getAllOperands()) { + if (SILInstruction *Op = llvm::dyn_cast(&*OpI.get())) { + DEBUG(llvm::dbgs() << "SC: add op " << *Op << + " from erased inst to worklist\n"); Worklist.add(Op); + } + } + } - for (Operand *DU : getDebugUses(I)) + for (Operand *DU : getDebugUses(&I)) Worklist.remove(DU->getUser()); Worklist.remove(&I); eraseFromParentWithDebugInsts(&I, InstIter); - DeletedInstSet.insert(&I); MadeChange = true; return nullptr; // Don't do anything with I } @@ -337,23 +319,35 @@ namespace { class SILCombine : public SILFunctionTransform { + llvm::SmallVector TrackingList; + /// The entry point to the transformation. void run() override { auto *AA = PM->getAnalysis(); // Create a SILBuilder with a tracking list for newly added // instructions, which we will periodically move to our worklist. - llvm::SmallVector TrackingList; - SILBuilder B(*getFunction(), &TrackingList); SILCombiner Combiner(B, AA, getOptions().RemoveRuntimeAsserts); bool Changed = Combiner.runOnFunction(*getFunction()); + assert(TrackingList.empty() && + "TrackingList should be fully processed by SILCombiner"); if (Changed) { // Invalidate everything. invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody); } } + + virtual void handleDeleteNotification(ValueBase *I) override { + // Linear searching the tracking list doesn't hurt because usually it only + // contains a few elements. + auto Iter = std::find(TrackingList.begin(), TrackingList.end(), I); + if (Iter != TrackingList.end()) + TrackingList.erase(Iter); + } + + virtual bool needsNotifications() override { return true; } StringRef getName() override { return "SIL Combine"; } }; diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h index 83c0fa4687af8..97386344c5cbb 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombiner.h +++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h @@ -1,8 +1,8 @@ -//===-------------------------- SILCombiner.h -----------------*- C++ -*---===// +//===--- SILCombiner.h ------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -89,14 +89,6 @@ class SILCombineWorklist { add(UI->getUser()); } - /// If only one result of an instruction has been simplified, add all of the - /// users of that result to the worklist since additional simplifications of - /// its users may have been exposed. - void addUsersToWorklist(ValueBase *I, unsigned Index) { - for (auto UI : SILValue(I, Index).getUses()) - add(UI->getUser()); - } - /// Check that the worklist is empty and nuke the backing store for the map if /// it is large. void zap() { @@ -130,17 +122,13 @@ class SILCombiner : /// Builder used to insert instructions. SILBuilder &Builder; - /// A set of instructions which have been deleted during this iteration. It is - /// used to make sure that we do not - llvm::DenseSet DeletedInstSet; - /// Cast optimizer CastOptimizer CastOpt; public: SILCombiner(SILBuilder &B, AliasAnalysis *AA, bool removeCondFails) : AA(AA), Worklist(), MadeChange(false), RemoveCondFails(removeCondFails), - Iteration(0), Builder(B), DeletedInstSet(128), + Iteration(0), Builder(B), CastOpt(/* ReplaceInstUsesAction */ [&](SILInstruction *I, ValueBase * V) { replaceInstUsesWith(*I, V); @@ -161,18 +149,13 @@ class SILCombiner : SILInstruction *insertNewInstBefore(SILInstruction *New, SILInstruction &Old); // This method is to be used when an instruction is found to be dead, - // replacable with another preexisting expression. Here we add all uses of I + // replaceable with another preexisting expression. Here we add all uses of I // to the worklist, replace all uses of I with the new value, then return I, // so that the combiner will know that I was modified. SILInstruction *replaceInstUsesWith(SILInstruction &I, ValueBase *V); - /// This is meant to be used when one is attempting to replace only one of the - /// results of I with a result of V. - SILInstruction *replaceInstUsesWith(SILInstruction &I, ValueBase *V, - unsigned IIndex, unsigned VIndex=0); - // Some instructions can never be "trivially dead" due to side effects or - // producing a void value. In those cases, since we can not rely on + // producing a void value. In those cases, since we cannot rely on // SILCombines trivially dead instruction DCE in order to delete the // instruction, visit methods should use this method to delete the given // instruction and upon completion of their peephole return the value returned @@ -269,12 +252,12 @@ class SILCombiner : SILValue NewSelf, SILValue Self, CanType ConcreteType, - ProtocolConformance *Conformance, - SILType InstanceType); + ProtocolConformanceRef Conformance, + CanType OpenedArchetype); SILInstruction * propagateConcreteTypeOfInitExistential(FullApplySite AI, ProtocolDecl *Protocol, - std::function Propagate); + llvm::function_ref Propagate); SILInstruction *propagateConcreteTypeOfInitExistential(FullApplySite AI, WitnessMethodInst *WMI); @@ -298,7 +281,7 @@ class SILCombiner : /// Inserts release/destroy instructions for all owner and in-parameters. void eraseApply(FullApplySite FAS, const UserListTy &Users); - /// Returns true if the results of an try_apply are not used. + /// Returns true if the results of a try_apply are not used. static bool isTryApplyResultNotUsed(UserListTy &AcceptedUses, TryApplyInst *TAI); }; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index 37957d70b7850..da22b30e88a6c 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -35,7 +35,7 @@ using namespace swift::PatternMatch; static SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI, bool requireSingleUse) { if (requireSingleUse) { - SILValue PAIVal(PAI, 0); + SILValue PAIVal(PAI); if (!hasOneNonDebugUse(PAIVal)) return SILValue(); } @@ -53,8 +53,8 @@ isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI, bool requireSingleUse) // The argument should be a closure. auto Arg = PAI->getArgument(0); - if (!Arg.getType().is() || - !Arg.getType().isReferenceCounted(PAI->getFunction()->getModule())) + if (!Arg->getType().is() || + !Arg->getType().isReferenceCounted(PAI->getFunction()->getModule())) return SILValue(); return PAI->getArgument(0); @@ -80,13 +80,13 @@ static bool foldInverseReabstractionThunks(PartialApplyInst *PAI, return false; // The types must match. - if (PAI->getType() != PAI2->getArgument(0).getType()) + if (PAI->getType() != PAI2->getArgument(0)->getType()) return false; // Replace the partial_apply(partial_apply(X)) by X and remove the // partial_applies. - Combiner->replaceInstUsesWith(*PAI, PAI2->getArgument(0).getDef()); + Combiner->replaceInstUsesWith(*PAI, PAI2->getArgument(0)); Combiner->eraseInstFromFunction(*PAI); assert(hasNoUsesExceptDebug(PAI2) && "Should not have any uses"); Combiner->eraseInstFromFunction(*PAI2); @@ -192,7 +192,7 @@ void PartialApplyCombiner::allocateTemporaries() { // by apply instructions. bool needsReleases = false; CanSILFunctionType PAITy = - dyn_cast(PAI->getCallee().getType().getSwiftType()); + dyn_cast(PAI->getCallee()->getType().getSwiftType()); // Emit a destroy value for each captured closure argument. ArrayRef Params = PAITy->getParameters(); @@ -212,19 +212,19 @@ void PartialApplyCombiner::allocateTemporaries() { (Param.isConsumed() && Param.isIndirect())) { Builder.setInsertionPoint(PAI->getFunction()->begin()->begin()); // Create a new temporary at the beginning of a function. - auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg.getType(), + auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg->getType(), {/*Constant*/ true, AI}); Builder.setInsertionPoint(PAI); // Copy argument into this temporary. - Builder.createCopyAddr(PAI->getLoc(), Arg, SILValue(Tmp, 1), + Builder.createCopyAddr(PAI->getLoc(), Arg, Tmp, IsTake_t::IsNotTake, IsInitialization_t::IsInitialization); - Tmps.push_back(SILValue(Tmp, 0)); + Tmps.push_back(Tmp); // If the temporary is non-trivial, we need to release it later. - if (!Arg.getType().isTrivial(PAI->getModule())) + if (!Arg->getType().isTrivial(PAI->getModule())) needsReleases = true; - ArgToTmp.insert(std::make_pair(Arg, SILValue(Tmp, 0))); + ArgToTmp.insert(std::make_pair(Arg, Tmp)); } } @@ -257,17 +257,16 @@ void PartialApplyCombiner::releaseTemporaries() { // because we don't want to keep objects alive longer than // its really needed. for (auto Op : Tmps) { - auto TmpType = Op.getType().getObjectType(); + auto TmpType = Op->getType().getObjectType(); if (TmpType.isTrivial(PAI->getModule())) continue; for (auto *EndPoint : Lifetime.LastUsers) { Builder.setInsertionPoint(next(SILBasicBlock::iterator(EndPoint))); - auto TmpAddr = SILValue(Op.getDef(), 1); if (!TmpType.isAddressOnly(PAI->getModule())) { - auto *Load = Builder.createLoad(PAI->getLoc(), TmpAddr); + auto *Load = Builder.createLoad(PAI->getLoc(), Op); Builder.createReleaseValue(PAI->getLoc(), Load); } else { - Builder.createDestroyAddr(PAI->getLoc(), TmpAddr); + Builder.createDestroyAddr(PAI->getLoc(), Op); } } } @@ -300,8 +299,7 @@ void PartialApplyCombiner::processSingleApply(FullApplySite AI) { // If there is new temporary for this argument, use it instead. if (isa(Arg)) { if (ArgToTmp.count(Arg)) { - auto Tmp = ArgToTmp.lookup(Arg); - Op = SILValue(Tmp.getDef(), 1); + Op = ArgToTmp.lookup(Arg); } } Args.push_back(Op); @@ -322,7 +320,7 @@ void PartialApplyCombiner::processSingleApply(FullApplySite AI) { SmallVector ToBeReleasedArgs; for (unsigned i = 0, e = PartialApplyArgs.size(); i < e; ++i) { SILValue Arg = PartialApplyArgs[i]; - if (!Arg.getType().isAddress()) { + if (!Arg->getType().isAddress()) { // Retain the argument as the callee may consume it. Builder.emitRetainValueOperation(PAI->getLoc(), Arg); // For non consumed parameters (e.g. guaranteed), we also need to @@ -447,7 +445,7 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI, // Grab our relevant callee types... CanSILFunctionType SubstCalleeTy = AI.getSubstCalleeType(); auto ConvertCalleeTy = - CFI->getOperand().getType().castTo(); + CFI->getOperand()->getType().castTo(); // ... and make sure they have no unsubstituted generics. If they do, bail. if (SubstCalleeTy->hasArchetype() || ConvertCalleeTy->hasArchetype()) @@ -580,7 +578,7 @@ static SILValue getInitOrOpenExistential(AllocStackInst *ASI, SILValue &Src) { continue; if (auto *CAI = dyn_cast(User)) { if (!FoundCAI && !FoundIEAI) { - if (CAI->getDest().getDef() == ASI) + if (CAI->getDest() == ASI) FoundCAI = CAI; } continue; @@ -626,10 +624,10 @@ static SILValue getInitOrOpenExistential(AllocStackInst *ASI, SILValue &Src) { return SrcValue; } -/// find the init_existential, which could be used to determine a concrete +/// find the init_existential, which could be used to determine a concrete /// type of the \p Self. static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, - SILType &InstanceType) { + CanType &OpenedArchetype) { SILInstruction *InitExistential = nullptr; if (auto *Instance = dyn_cast(Self)) { @@ -639,8 +637,8 @@ static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, Self = Existential; } - if (auto *Instance = dyn_cast(Self)) { - auto Op = Instance->getOperand(); + if (auto *Open = dyn_cast(Self)) { + auto Op = Open->getOperand(); if (auto *ASI = dyn_cast(Op)) { SILValue Src; if (getInitOrOpenExistential(ASI, Src)) { @@ -649,7 +647,7 @@ static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, } } - for (auto Use : Op.getUses()) { + for (auto Use : Op->getUses()) { SILValue User = Use->getUser(); if (auto *IE = dyn_cast(User)) { @@ -660,21 +658,37 @@ static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self, if (IE->getParent() != AI.getParent()) continue; - InstanceType = Instance->getType(); + OpenedArchetype = Open->getType().getSwiftRValueType(); InitExistential = IE; } } } - if (auto *Instance = dyn_cast(Self)) { - if (auto *IE = dyn_cast(Instance->getOperand())) { + if (auto *Open = dyn_cast(Self)) { + if (auto *IE = dyn_cast(Open->getOperand())) { // IE should dominate Instance. // Without a DomTree we want to be very defensive // and only allow this optimization when it is used // inside the same BB. if (IE->getParent() != AI.getParent()) return nullptr; - InstanceType = Instance->getType(); + OpenedArchetype = Open->getType().getSwiftRValueType(); + InitExistential = IE; + } + } + + if (auto *Open = dyn_cast(Self)) { + if (auto *IE = + dyn_cast(Open->getOperand())) { + // IE should dominate Instance. + // Without a DomTree we want to be very defensive + // and only allow this optimization when it is used + // inside the same BB. + if (IE->getParent() != AI.getParent()) + return nullptr; + OpenedArchetype = Open->getType().getSwiftRValueType(); + while (auto Metatype = dyn_cast(OpenedArchetype)) + OpenedArchetype = Metatype.getInstanceType(); InitExistential = IE; } } @@ -689,8 +703,8 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, SILValue NewSelf, SILValue Self, CanType ConcreteType, - ProtocolConformance *Conformance, - SILType InstanceType) { + ProtocolConformanceRef Conformance, + CanType OpenedArchetype) { // Create a set of arguments. SmallVector Args; for (auto Arg : AI.getArgumentsWithoutSelf()) { @@ -703,13 +717,11 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, SmallVector Substitutions; for (auto Subst : AI.getSubstitutions()) { if (Subst.getReplacement().getCanonicalTypeOrNull() == - Self.getType().getSwiftRValueType()) { + Self->getType().getSwiftRValueType()) { auto Conformances = AI.getModule().getASTContext() - .Allocate(1); + .AllocateUninitialized(1); Conformances[0] = Conformance; - Substitution NewSubst(Subst.getArchetype(), - ConcreteType, - Conformances); + Substitution NewSubst(ConcreteType, Conformances); Substitutions.push_back(NewSubst); } else Substitutions.push_back(Subst); @@ -719,7 +731,7 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, SILType NewSubstCalleeType; - auto FnTy = AI.getCallee().getType().getAs(); + auto FnTy = AI.getCallee()->getType().getAs(); if (FnTy && FnTy->isPolymorphic()) { // Handle polymorphic functions by properly substituting // their parameter types. @@ -730,7 +742,7 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, NewSubstCalleeType = SILType::getPrimitiveObjectType(SFT); } else { TypeSubstitutionMap TypeSubstitutions; - TypeSubstitutions[InstanceType.getSwiftType().getPointer()] = ConcreteType; + TypeSubstitutions[OpenedArchetype.getPointer()] = ConcreteType; NewSubstCalleeType = SubstCalleeType.subst(AI.getModule(), AI.getModule().getSwiftModule(), TypeSubstitutions); @@ -751,7 +763,7 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, cast(AI)->isNonThrowing()); if (isa(NewAI)) - replaceInstUsesWith(*AI.getInstruction(), NewAI.getInstruction(), 0); + replaceInstUsesWith(*AI.getInstruction(), NewAI.getInstruction()); eraseInstFromFunction(*AI.getInstruction()); return NewAI.getInstruction(); @@ -759,12 +771,12 @@ SILCombiner::createApplyWithConcreteType(FullApplySite AI, /// Derive a concrete type of self and conformance from the init_existential /// instruction. -static std::pair +static Optional> getConformanceAndConcreteType(FullApplySite AI, SILInstruction *InitExistential, ProtocolDecl *Protocol, SILValue &NewSelf, - ArrayRef &Conformances) { + ArrayRef &Conformances) { // Try to derive the concrete type of self from the found init_existential. CanType ConcreteType; if (auto IE = dyn_cast(InitExistential)) { @@ -775,39 +787,29 @@ getConformanceAndConcreteType(FullApplySite AI, Conformances = IER->getConformances(); ConcreteType = IER->getFormalConcreteType(); NewSelf = IER->getOperand(); + } else if (auto IEM = dyn_cast(InitExistential)){ + Conformances = IEM->getConformances(); + NewSelf = IEM->getOperand(); + ConcreteType = NewSelf->getType().getSwiftRValueType(); + + auto ExType = IEM->getType().getSwiftRValueType(); + while (auto ExMetatype = dyn_cast(ExType)) { + ExType = ExMetatype.getInstanceType(); + ConcreteType = cast(ConcreteType).getInstanceType(); + } + } else { + return None; } - if (Conformances.empty()) - return std::make_pair(nullptr, CanType()); - - // If ConcreteType depends on any archetypes, then propagating it does not - // help resolve witness table lookups. Catch these cases before calling - // gatherAllSubstitutions, which only works on nominal types. - if (ConcreteType->hasArchetype()) - return std::make_pair(nullptr, CanType()); - - // Check the substitutions. - auto ConcreteTypeSubsts = ConcreteType->gatherAllSubstitutions( - AI.getModule().getSwiftModule(), nullptr); - if (!ConcreteTypeSubsts.empty()) { - // Bail if any generic types parameters of the concrete type are unbound. - if (hasUnboundGenericTypes(ConcreteTypeSubsts)) - return std::make_pair(nullptr, CanType()); - // At this point we know that all replacements use concrete types - // and therefore the whole Lookup type is concrete. So, we can - // propagate it, because we know how to devirtualize it. - } - - // Find the conformance related to witness_method. - ProtocolConformance *Conformance = nullptr; - for (auto Con : Conformances) { - if (Con->getProtocol() == Protocol) { - Conformance = Con; - break; + // Find the conformance for the protocol we're interested in. + for (auto Conformance : Conformances) { + auto Requirement = Conformance.getRequirement(); + if (Requirement == Protocol || Requirement->inheritsFrom(Protocol)) { + return std::make_pair(Conformance, ConcreteType); } } - return std::make_pair(Conformance, ConcreteType); + llvm_unreachable("couldn't find matching conformance in substitution?"); } /// Propagate information about a concrete type from init_existential_addr @@ -818,7 +820,7 @@ getConformanceAndConcreteType(FullApplySite AI, SILInstruction * SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, ProtocolDecl *Protocol, - std::function Propagate) { + llvm::function_ref Propagate) { // Get the self argument. SILValue Self; @@ -830,57 +832,58 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, Self = Apply->getSelfArgument(); } - assert (Self && "Self argument should be present"); + assert(Self && "Self argument should be present"); // Try to find the init_existential, which could be used to // determine a concrete type of the self. - SILType InstanceType; - SILInstruction *InitExistential = findInitExistential(AI, Self, InstanceType); + CanType OpenedArchetype; + SILInstruction *InitExistential = + findInitExistential(AI, Self, OpenedArchetype); if (!InitExistential) return nullptr; // Try to derive the concrete type of self and a related conformance from // the found init_existential. - ArrayRef Conformances; + ArrayRef Conformances; auto NewSelf = SILValue(); auto ConformanceAndConcreteType = getConformanceAndConcreteType(AI, InitExistential, Protocol, NewSelf, Conformances); - auto ConcreteType = ConformanceAndConcreteType.second; - auto Conformance = ConformanceAndConcreteType.first; - if (!Conformance) + if (!ConformanceAndConcreteType) return nullptr; + auto ConcreteType = ConformanceAndConcreteType->second; + auto Conformance = ConformanceAndConcreteType->first; + // Propagate the concrete type into the callee-operand if required. Propagate(ConcreteType, Conformance); - // Create a new apply instructions that uses the concrete type instead + // Create a new apply instruction that uses the concrete type instead // of the existential type. return createApplyWithConcreteType(AI, NewSelf, Self, - ConcreteType, Conformance, InstanceType); + ConcreteType, Conformance, + OpenedArchetype); } SILInstruction * SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, WitnessMethodInst *WMI) { // Check if it is legal to perform the propagation. - if (WMI->getConformance()) + if (WMI->getConformance().isConcrete()) return nullptr; // Don't specialize Apply instructions that return the Self type. // Notice that it is sufficient to compare the return type to the // substituted type because types that depend on the Self type are // not allowed (for example [Self] is not allowed). - if (AI.getType().getSwiftType().getLValueOrInOutObjectType() == - WMI->getLookupType()) + if (AI.getType().getSwiftRValueType() == WMI->getLookupType()) return nullptr; // We need to handle the Self return type. // In we find arguments that are not the 'self' argument and if // they are of the Self type then we abort the optimization. for (auto Arg : AI.getArgumentsWithoutSelf()) { - if (Arg.getType().getSwiftType().getLValueOrInOutObjectType() == - WMI->getLookupType()) + if (Arg->getType().getSwiftRValueType() == WMI->getLookupType()) return nullptr; } @@ -889,17 +892,21 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI, // Propagate the concrete type into a callee-operand, which is a // witness_method instruction. - auto PropagateIntoOperand = [this, &WMI] (CanType ConcreteType, - ProtocolConformance *Conformance) { - SILValue OptionalExistential = - WMI->hasOperand() ? WMI->getOperand() : SILValue(); + auto PropagateIntoOperand = [this, &WMI](CanType ConcreteType, + ProtocolConformanceRef Conformance) { + // Keep around the dependence on the open instruction unless we've + // actually eliminated the use. + SILValue OptionalExistential; + if (WMI->hasOperand() && ConcreteType->isOpenedExistential()) + OptionalExistential = WMI->getOperand(); + auto *NewWMI = Builder.createWitnessMethod(WMI->getLoc(), ConcreteType, Conformance, WMI->getMember(), WMI->getType(), OptionalExistential, WMI->isVolatile()); - replaceInstUsesWith(*WMI, NewWMI, 0); + replaceInstUsesWith(*WMI, NewWMI); eraseInstFromFunction(*WMI); }; @@ -933,8 +940,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI) { // In we find arguments that are not the 'self' argument and if // they are of the Self type then we abort the optimization. for (auto Arg : AI.getArgumentsWithoutSelf()) { - if (Arg.getType().getSwiftType().getLValueOrInOutObjectType() == - AI.getArguments().back().getType().getSwiftRValueType()) + if (Arg->getType().getSwiftType().getLValueOrInOutObjectType() == + AI.getArguments().back()->getType().getSwiftRValueType()) return nullptr; } @@ -947,7 +954,7 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite AI) { // No need to propagate anything into the callee operand. auto PropagateIntoOperand = [] (CanType ConcreteType, - ProtocolConformance *Conformance) {}; + ProtocolConformanceRef Conformance) {}; // Try to perform the propagation. return propagateConcreteTypeOfInitExistential(AI, PD, PropagateIntoOperand); @@ -1008,7 +1015,7 @@ static ApplyInst *optimizeCastThroughThinFunctionPointer( return nullptr; // The fourth parameter is a metatype of a bound generic type. Use it to - // obtain the type substitutions to apply. + // obtain the type substitutions to apply. auto MetaTy = dyn_cast(CastedParams[3].getType()); if (!MetaTy) return nullptr; @@ -1026,38 +1033,11 @@ static ApplyInst *optimizeCastThroughThinFunctionPointer( if (Subs.size() == 0) return nullptr; - // We expect one type variable to be substituted. The substitution might have - // recursive substitutions. Recognize and allow the case of one substitution - // with recursive substitutions. - // Container - // T = ... - // T.A = ... - // T.A.C = ... - if (Subs.size() != 1) { - SmallPtrSet Archetypes; - bool SawPrimary = false; - // Collect all the archetypes and make sure there is only one primary. - for (unsigned i = 0, e = Subs.size(); i != e; ++i) { - auto *AT = Subs[i].getArchetype(); - Archetypes.insert(AT); - // Two primary arche types. We can't handle this case. - if (SawPrimary && AT->isPrimary()) - return nullptr; - else if (AT->isPrimary()) - SawPrimary = true; - } - - // Make sure all the non primary archetypes have a parent archetype in the - // set. - for (unsigned i = 0, e = Subs.size(); i != e; ++i) { - auto *AT = Subs[i].getArchetype(); - // Ignore the one primary archetype. - if (AT->isPrimary()) - continue; - if (!Archetypes.count(AT)) - return nullptr; - } - } + // If the generic signature of the function doesn't match the generic + // signature of the type, don't try to continue. + if (BoundGenericInstTy->getDecl()->getGenericSignature() + ->getCanonicalSignature() != ConvertCalleeTy->getGenericSignature()) + return nullptr; SmallVector Args; for (auto Arg : AI->getArguments()) @@ -1080,7 +1060,7 @@ static ApplyInst *optimizeCastThroughThinFunctionPointer( static bool hasOnlyRetainReleaseUsers(ApplyInst *AI, SILInstruction *IgnoreUser, SmallVectorImpl &Users) { - for (auto *Use : getNonDebugUses(*AI)) { + for (auto *Use : getNonDebugUses(AI)) { if (Use->getUser() == IgnoreUser) continue; @@ -1169,8 +1149,8 @@ bool SILCombiner::optimizeIdentityCastComposition(ApplyInst *FInverse, if (!knowHowToEmitReferenceCountInsts(FInverse)) return false; - // We need to know that the cast will succeeed. - if (!isCastTypeKnownToSucceed(FInverse->getArgument(0).getType(), + // We need to know that the cast will succeed. + if (!isCastTypeKnownToSucceed(FInverse->getArgument(0)->getType(), FInverse->getModule()) || !isCastTypeKnownToSucceed(FInverse->getType(), FInverse->getModule())) return false; @@ -1185,7 +1165,7 @@ bool SILCombiner::optimizeIdentityCastComposition(ApplyInst *FInverse, return false; // The types must match. - if (F->getArgument(0).getType() != FInverse->getType()) + if (F->getArgument(0)->getType() != FInverse->getType()) return false; // Retains, releases of the result of F. @@ -1219,7 +1199,7 @@ bool SILCombiner::optimizeIdentityCastComposition(ApplyInst *FInverse, emitMatchingRCAdjustmentsForCall(FInverse, X); // Replace users of f_inverse by x. - replaceInstUsesWith(*FInverse, X.getDef()); + replaceInstUsesWith(*FInverse, X); // Remove the calls. eraseInstFromFunction(*FInverse); @@ -1245,7 +1225,7 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) { if (auto *OrigThinFun = dyn_cast(Ptr->getOperand())) if (auto *NewAI = optimizeCastThroughThinFunctionPointer( Builder, AI, OrigThinFun, CastedThinFun)) { - replaceInstUsesWith(*AI, NewAI, 0); + replaceInstUsesWith(*AI, NewAI); eraseInstFromFunction(*AI); return nullptr; } @@ -1268,7 +1248,7 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) { return I; } } - if (SF->hasSemanticsString("array.uninitialized")) { + if (SF->hasSemanticsAttr("array.uninitialized")) { UserListTy Users; // If the uninitialized array is only written into then it can be removed. if (recursivelyCollectARCUsers(Users, AI)) { @@ -1288,9 +1268,9 @@ SILInstruction *SILCombiner::visitApplyInst(ApplyInst *AI) { for (auto &Op : AI->getArgumentOperands()) { Arguments.push_back(Op.get()); } - // The type of the substition is the source type of the thin to thick + // The type of the substitution is the source type of the thin to thick // instruction. - SILType substTy = TTTFI->getOperand().getType(); + SILType substTy = TTTFI->getOperand()->getType(); auto *NewAI = Builder.createApply(AI->getLoc(), TTTFI->getOperand(), substTy, AI->getType(), AI->getSubstitutions(), Arguments, @@ -1421,7 +1401,7 @@ SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) { } // The type of the substitution is the source type of the thin to thick // instruction. - SILType substTy = TTTFI->getOperand().getType(); + SILType substTy = TTTFI->getOperand()->getType(); auto *NewAI = Builder.createTryApply(AI->getLoc(), TTTFI->getOperand(), substTy, AI->getSubstitutions(), Arguments, diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp index 44f0af6ce5f8e..a49a1f51aeb2c 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -33,7 +33,7 @@ using namespace swift::PatternMatch; SILInstruction *SILCombiner::optimizeBuiltinCompareEq(BuiltinInst *BI, bool NegateResult) { // Canonicalize boolean comparisons. - if (auto OpTy = BI->getArguments()[0].getType().getAs()) + if (auto OpTy = BI->getArguments()[0]->getType().getAs()) if (OpTy->isFixedWidth(1)) // cmp_eq %X, -1 -> xor (cmp_eq %X, 0), -1 if (!NegateResult) { @@ -106,7 +106,7 @@ static SILInstruction *optimizeBuiltinWithSameOperands(SILBuilder &Builder, // We cannot just _return_ the operand because it is not necessarily an // instruction. It can be an argument. SILValue Op = I->getOperand(0); - C->replaceInstUsesWith(*I, Op.getDef(), 0, Op.getResultNumber()); + C->replaceInstUsesWith(*I, Op); break; } @@ -268,14 +268,14 @@ SILInstruction *optimizeBuiltinArrayOperation(BuiltinInst *I, TruncOrBitCast, Ptr, Distance); if (IdxRawPtr1) NewOp1 = createIndexAddrFrom(IdxRawPtr1, Metatype, TruncOrBitCast, Ptr, - Distance, NewOp1.getType(), Builder); + Distance, NewOp1->getType(), Builder); // Try to replace the second pointer operand. auto *IdxRawPtr2 = matchSizeOfMultiplication(I->getOperand(2), Metatype, TruncOrBitCast, Ptr, Distance); if (IdxRawPtr2) NewOp2 = createIndexAddrFrom(IdxRawPtr2, Metatype, TruncOrBitCast, Ptr, - Distance, NewOp2.getType(), Builder); + Distance, NewOp2->getType(), Builder); if (NewOp1 != I->getOperand(1) || NewOp2 != I->getOperand(2)) { SmallVector NewOpds; @@ -334,7 +334,7 @@ SILInstruction *optimizeBitOp(BuiltinInst *BI, } if (isNeutral(bits)) // The bit operation has no effect, e.g. x | 0 -> x - return C->replaceInstUsesWith(*BI, op.getDef()); + return C->replaceInstUsesWith(*BI, op); if (isZero(bits)) // The bit operation yields to a constant, e.g. x & 0 -> 0 @@ -384,14 +384,14 @@ SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) { match(I->getArguments()[1], m_ApplyInst(BuiltinValueKind::ZExtOrBitCast, m_SILValue(RCast))) && - LCast->getType(0) == RCast->getType(0)) { + LCast->getType() == RCast->getType()) { auto *NewCmp = Builder.createBuiltinBinaryFunction( I->getLoc(), getBuiltinName(I->getBuiltinInfo().ID), - LCast->getType(0), I->getType(), {LCast, RCast}); + LCast->getType(), I->getType(), {LCast, RCast}); I->replaceAllUsesWith(NewCmp); - replaceInstUsesWith(*I, NewCmp, 0); + replaceInstUsesWith(*I, NewCmp); return eraseInstFromFunction(*I); } break; @@ -450,8 +450,8 @@ SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) { if (match(Bytes2, m_BuiltinInst(BuiltinValueKind::PtrToInt, m_ValueBase()))) { if (Indexraw->getOperand(0) == Bytes2->getOperand(0) && - Indexraw->getOperand(1).getType() == I->getType()) { - replaceInstUsesWith(*I, Indexraw->getOperand(1).getDef()); + Indexraw->getOperand(1)->getType() == I->getType()) { + replaceInstUsesWith(*I, Indexraw->getOperand(1)); return eraseInstFromFunction(*I); } } diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp index 1fa07447d8b6d..2779c236c1e19 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -36,7 +36,7 @@ SILCombiner::visitRefToRawPointerInst(RefToRawPointerInst *RRPI) { if (auto *URCI = dyn_cast(RRPI->getOperand())) { // (ref_to_raw_pointer (unchecked_ref_cast x)) // -> (ref_to_raw_pointer x) - if (URCI->getOperand().getType().getSwiftType() + if (URCI->getOperand()->getType().getSwiftType() ->isAnyClassReferenceType()) { RRPI->setOperand(URCI->getOperand()); return URCI->use_empty() ? eraseInstFromFunction(*URCI) : nullptr; @@ -86,7 +86,7 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) { PTAI->getType()); } - // Turn this also into a index_addr. We generate this pattern after switching + // Turn this also into an index_addr. We generate this pattern after switching // the Word type to an explicit Int32 or Int64 in the stdlib. // // %101 = builtin "strideof_nonzero"(%84 : $@thick Int.Type) : @@ -178,7 +178,7 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) { if (InstanceType.getAddressType() != PTAI->getType()) return nullptr; - auto IRPI = cast(PTAI->getOperand().getDef()); + auto IRPI = cast(PTAI->getOperand()); SILValue Ptr = IRPI->getOperand(0); SILValue Distance = Bytes->getArguments()[0]; auto *NewPTAI = @@ -204,8 +204,8 @@ SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) { UADCI->getType()); // (unchecked-addr-cast cls->superclass) -> (upcast cls->superclass) - if (UADCI->getType() != UADCI->getOperand().getType() && - UADCI->getType().isSuperclassOf(UADCI->getOperand().getType())) + if (UADCI->getType() != UADCI->getOperand()->getType() && + UADCI->getType().isSuperclassOf(UADCI->getOperand()->getType())) return Builder.createUpcast(UADCI->getLoc(), UADCI->getOperand(), UADCI->getType()); @@ -216,7 +216,7 @@ SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) { if (UADCI->use_empty()) return nullptr; - SILType InputTy = UADCI->getOperand().getType(); + SILType InputTy = UADCI->getOperand()->getType(); SILType OutputTy = UADCI->getType(); // If either type is address only, do not do anything here. @@ -241,7 +241,7 @@ SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) { return nullptr; // For each user U of the unchecked_addr_cast... - for (auto U : getNonDebugUses(*UADCI)) + for (auto U : getNonDebugUses(UADCI)) // Check if it is load. If it is not a load, bail... if (!isa(U->getUser())) return nullptr; @@ -251,7 +251,7 @@ SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) { // Ok, we have all loads. Lets simplify this. Go back through the loads a // second time, rewriting them into a load + bitcast from our source. - auto UsesRange = getNonDebugUses(*UADCI); + auto UsesRange = getNonDebugUses(UADCI); for (auto UI = UsesRange.begin(), E = UsesRange.end(); UI != E;) { // Grab the original load. LoadInst *L = cast(UI->getUser()); @@ -263,7 +263,7 @@ SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) { OutputTy.getObjectType()); // Replace all uses of the old load with the new bitcasted result and erase // the old load. - replaceInstUsesWith(*L, BitCast, 0); + replaceInstUsesWith(*L, BitCast); eraseInstFromFunction(*L); } @@ -287,8 +287,8 @@ SILCombiner::visitUncheckedRefCastInst(UncheckedRefCastInst *URCI) { UI->getOperand(), URCI->getType()); - if (URCI->getType() != URCI->getOperand().getType() && - URCI->getType().isSuperclassOf(URCI->getOperand().getType())) + if (URCI->getType() != URCI->getOperand()->getType() && + URCI->getType().isSuperclassOf(URCI->getOperand()->getType())) return Builder.createUpcast(URCI->getLoc(), URCI->getOperand(), URCI->getType()); @@ -304,11 +304,11 @@ SILCombiner::visitUncheckedRefCastInst(UncheckedRefCastInst *URCI) { SILInstruction * SILCombiner::visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI) { - SILType SrcTy = URCI->getSrc().getType(); + SILType SrcTy = URCI->getSrc()->getType(); if (!SrcTy.isLoadable(URCI->getModule())) return nullptr; - SILType DestTy = URCI->getDest().getType(); + SILType DestTy = URCI->getDest()->getType(); if (!DestTy.isLoadable(URCI->getModule())) return nullptr; @@ -353,8 +353,8 @@ visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) { // unconditional_checked_cast -> unchecked_addr_cast return Builder.createUncheckedAddrCast(Loc, Op, LoweredTargetType); } else if (LoweredTargetType.isHeapObjectReferenceType()) { - if (!(Op.getType().isHeapObjectReferenceType() || - Op.getType().isClassExistentialType())) { + if (!(Op->getType().isHeapObjectReferenceType() || + Op->getType().isClassExistentialType())) { return nullptr; } // unconditional_checked_cast -> unchecked_ref_cast @@ -441,7 +441,7 @@ visitMetatypeConversionInst(SILBuilder &Builder, ConversionInst *MCI, SILValue Op = MCI->getOperand(0); // Instruction has a proper target type already. SILType Ty = MCI->getType(); - auto MetatypeTy = Op.getType().getAs(); + auto MetatypeTy = Op->getType().getAs(); if (MetatypeTy->getRepresentation() != Representation) return nullptr; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index 826cd618d6b7f..cd5b5e91b7d5e 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -1,8 +1,8 @@ -//===---- SILCombinerMiscVisitors.cpp -------------------------------------===// +//===--- SILCombinerMiscVisitors.cpp --------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,14 +45,25 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) { StoreInst *SingleStore = nullptr; StrongReleaseInst *SingleRelease = nullptr; + ProjectExistentialBoxInst *SingleProjection = nullptr; // For each user U of the alloc_existential_box... - for (auto U : getNonDebugUses(*AEBI)) { - // Record stores into the box. - if (auto *SI = dyn_cast(U->getUser())) { - // If this is not the only store into the box then bail out. - if (SingleStore) return nullptr; - SingleStore = SI; + for (auto U : getNonDebugUses(AEBI)) { + + if (auto *PEBI = dyn_cast(U->getUser())) { + if (SingleProjection) return nullptr; + SingleProjection = PEBI; + for (auto AddrUse : getNonDebugUses(PEBI)) { + // Record stores into the box. + if (auto *SI = dyn_cast(AddrUse->getUser())) { + // If this is not the only store into the box then bail out. + if (SingleStore) return nullptr; + SingleStore = SI; + continue; + } + // If there are other users to the box value address then bail out. + return nullptr; + } continue; } @@ -69,6 +80,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) { } if (SingleStore && SingleRelease) { + assert(SingleProjection && "store without a projection"); // Release the value that was stored into the existential box. The box // is going away so we need to release the stored value now. Builder.setInsertionPoint(SingleStore); @@ -78,6 +90,7 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) { // releases the box, and finally, release the box. eraseInstFromFunction(*SingleRelease); eraseInstFromFunction(*SingleStore); + eraseInstFromFunction(*SingleProjection); return eraseInstFromFunction(*AEBI); } @@ -90,7 +103,7 @@ SILInstruction *SILCombiner::visitSwitchEnumAddrInst(SwitchEnumAddrInst *SEAI) { // -> // %value = load %ptr // switch_enum %value - SILType Ty = SEAI->getOperand().getType(); + SILType Ty = SEAI->getOperand()->getType(); if (!Ty.isLoadable(SEAI->getModule())) return nullptr; @@ -133,7 +146,7 @@ SILInstruction *SILCombiner::visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) { // -> // %value = load %ptr // = select_enum %value - SILType Ty = SEAI->getEnumOperand().getType(); + SILType Ty = SEAI->getEnumOperand()->getType(); if (!Ty.isLoadable(SEAI->getModule())) return nullptr; @@ -168,20 +181,20 @@ namespace { /// /// We detect this pattern /// %0 = alloc_stack $LogicValue -/// %1 = init_existential_addr %0#1 : $*LogicValue, $*Bool +/// %1 = init_existential_addr %0 : $*LogicValue, $*Bool /// ... /// use of %1 /// ... -/// destroy_addr %0#1 : $*LogicValue -/// dealloc_stack %0#0 : $*@local_storage LogicValue +/// destroy_addr %0 : $*LogicValue +/// dealloc_stack %0 : $*LogicValue /// /// At the same we time also look for dead alloc_stack live ranges that are only /// copied into. /// /// %0 = alloc_stack /// copy_addr %src, %0 -/// destroy_addr %0#1 : $*LogicValue -/// dealloc_stack %0#0 : $*@local_storage LogicValue +/// destroy_addr %0 : $*LogicValue +/// dealloc_stack %0 : $*LogicValue struct AllocStackAnalyzer : SILInstructionVisitor { /// The alloc_stack that we are analyzing. AllocStackInst *ASI; @@ -213,7 +226,7 @@ struct AllocStackAnalyzer : SILInstructionVisitor { // anything other than the init_existential_addr/open_existential_addr // container. - for (auto *Op : getNonDebugUses(*ASI)) { + for (auto *Op : getNonDebugUses(ASI)) { visit(Op->getUser()); // If we found a non-legal user, bail early. @@ -232,7 +245,7 @@ struct AllocStackAnalyzer : SILInstructionVisitor { void visitDeallocStackInst(DeallocStackInst *I) {} void visitInitExistentialAddrInst(InitExistentialAddrInst *I) { - // If we have already seen an init_existential_addr, we can not + // If we have already seen an init_existential_addr, we cannot // optimize. This is because we only handle the single init_existential_addr // case. if (IEI || HaveSeenCopyInto) { @@ -243,7 +256,7 @@ struct AllocStackAnalyzer : SILInstructionVisitor { } void visitOpenExistentialAddrInst(OpenExistentialAddrInst *I) { - // If we have already seen an open_existential_addr, we can not + // If we have already seen an open_existential_addr, we cannot // optimize. This is because we only handle the single open_existential_addr // case. if (OEI) { @@ -251,9 +264,9 @@ struct AllocStackAnalyzer : SILInstructionVisitor { return; } - // Make sure tht the open_existential does not have any uses except + // Make sure that the open_existential does not have any uses except // destroy_addr. - for (auto *Use : getNonDebugUses(*I)) { + for (auto *Use : getNonDebugUses(I)) { if (!isa(Use->getUser())) { LegalUsers = false; return; @@ -270,7 +283,7 @@ struct AllocStackAnalyzer : SILInstructionVisitor { } // Copies into the alloc_stack live range are safe. - if (I->getDest().getDef() == ASI) { + if (I->getDest() == ASI) { HaveSeenCopyInto = true; return; } @@ -299,7 +312,7 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { if (IEI && !OEI) { auto *ConcAlloc = Builder.createAllocStack( AS->getLoc(), IEI->getLoweredConcreteType(), AS->getVarInfo()); - SILValue(IEI, 0).replaceAllUsesWith(ConcAlloc->getAddressResult()); + IEI->replaceAllUsesWith(ConcAlloc); eraseInstFromFunction(*IEI); for (auto UI = AS->use_begin(), UE = AS->use_end(); UI != UE;) { @@ -307,7 +320,7 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { ++UI; if (auto *DA = dyn_cast(Op->getUser())) { Builder.setInsertionPoint(DA); - Builder.createDestroyAddr(DA->getLoc(), SILValue(ConcAlloc, 1)); + Builder.createDestroyAddr(DA->getLoc(), ConcAlloc); eraseInstFromFunction(*DA); continue; } @@ -317,7 +330,7 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { auto *DS = cast(Op->getUser()); Builder.setInsertionPoint(DS); - Builder.createDeallocStack(DS->getLoc(), SILValue(ConcAlloc, 0)); + Builder.createDeallocStack(DS->getLoc(), ConcAlloc); eraseInstFromFunction(*DS); } @@ -339,7 +352,7 @@ SILInstruction *SILCombiner::visitAllocStackInst(AllocStackInst *AS) { // no the alloc_stack. // Otherwise, just delete the copy_addr. if (auto *CopyAddr = dyn_cast(Op->getUser())) { - if (CopyAddr->isTakeOfSrc() && CopyAddr->getSrc().getDef() != AS) { + if (CopyAddr->isTakeOfSrc() && CopyAddr->getSrc() != AS) { Builder.setInsertionPoint(CopyAddr); Builder.createDestroyAddr(CopyAddr->getLoc(), CopyAddr->getSrc()); } @@ -386,7 +399,7 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) { // Go through the loads uses and add any users that are projections to the // projection list. llvm::SmallVector Projections; - for (auto *UI : getNonDebugUses(*LI)) { + for (auto *UI : getNonDebugUses(LI)) { auto *User = UI->getUser(); // If we have any non SEI, TEI instruction, don't do anything here. @@ -413,7 +426,7 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) { // If this projection is the same as the last projection we processed, just // replace all uses of the projection with the load we created previously. if (LastProj && Proj == *LastProj) { - replaceInstUsesWith(*Inst, LastNewLoad, 0); + replaceInstUsesWith(*Inst, LastNewLoad); eraseInstFromFunction(*Inst); continue; } @@ -423,7 +436,7 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) { auto I = Proj.createAddrProjection(Builder, LI->getLoc(), LI->getOperand()); LastProj = &Proj; LastNewLoad = Builder.createLoad(LI->getLoc(), I.get()); - replaceInstUsesWith(*Inst, LastNewLoad, 0); + replaceInstUsesWith(*Inst, LastNewLoad); eraseInstFromFunction(*Inst); } @@ -433,12 +446,12 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) { SILInstruction *SILCombiner::visitReleaseValueInst(ReleaseValueInst *RVI) { SILValue Operand = RVI->getOperand(); - SILType OperandTy = Operand.getType(); + SILType OperandTy = Operand->getType(); // Destroy value of an enum with a trivial payload or no-payload is a no-op. if (auto *EI = dyn_cast(Operand)) { if (!EI->hasOperand() || - EI->getOperand().getType().isTrivial(EI->getModule())) + EI->getOperand()->getType().isTrivial(EI->getModule())) return eraseInstFromFunction(*RVI); // retain_value of an enum_inst where we know that it has a payload can be @@ -466,13 +479,13 @@ SILInstruction *SILCombiner::visitReleaseValueInst(ReleaseValueInst *RVI) { SILInstruction *SILCombiner::visitRetainValueInst(RetainValueInst *RVI) { SILValue Operand = RVI->getOperand(); - SILType OperandTy = Operand.getType(); + SILType OperandTy = Operand->getType(); // retain_value of an enum with a trivial payload or no-payload is a no-op + // RAUW. if (auto *EI = dyn_cast(Operand)) { if (!EI->hasOperand() || - EI->getOperand().getType().isTrivial(RVI->getModule())) { + EI->getOperand()->getType().isTrivial(RVI->getModule())) { return eraseInstFromFunction(*RVI); } @@ -492,7 +505,7 @@ SILInstruction *SILCombiner::visitRetainValueInst(RetainValueInst *RVI) { return Builder.createStrongRetain(RVI->getLoc(), Operand); } - // RetainValueInst of a trivial type is a no-op + use propogation. + // RetainValueInst of a trivial type is a no-op + use propagation. if (OperandTy.isTrivial(RVI->getModule())) { return eraseInstFromFunction(*RVI); } @@ -508,7 +521,7 @@ SILInstruction *SILCombiner::visitRetainValueInst(RetainValueInst *RVI) { // // Due to the matching pairs being in different basic blocks, the ARC // Optimizer (which is currently local to one basic block does not handle - // it). But that does not mean that we can not eliminate this pair with a + // it). But that does not mean that we cannot eliminate this pair with a // peephole. // If we are not the first instruction in this basic block... @@ -586,7 +599,7 @@ SILInstruction *SILCombiner::visitStrongRetainInst(StrongRetainInst *SRI) { // // Due to the matching pairs being in different basic blocks, the ARC // Optimizer (which is currently local to one basic block does not handle - // it). But that does not mean that we can not eliminate this pair with a + // it). But that does not mean that we cannot eliminate this pair with a // peephole. // If we are not the first instruction in this basic block... @@ -630,10 +643,10 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { // can't handle the payload case here due to the flow problems caused by the // dependency in between the enum and its data. - assert(IEAI->getOperand().getType().isAddress() && "Must be an address"); + assert(IEAI->getOperand()->getType().isAddress() && "Must be an address"); Builder.setCurrentDebugScope(IEAI->getDebugScope()); - if (IEAI->getOperand().getType().isAddressOnly(IEAI->getModule())) { + if (IEAI->getOperand()->getType().isAddressOnly(IEAI->getModule())) { // Check for the following pattern inside the current basic block: // inject_enum_addr %payload_allocation, $EnumType.case1 // ... no insns storing anything into %payload_allocation @@ -666,7 +679,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { if (SI->getDest() == IEAI->getOperand()) return nullptr; } - // Allow all instructions inbetween, which don't have any dependency to + // Allow all instructions in between, which don't have any dependency to // the store. if (AA->mayWriteToMemory(&*II, IEAI->getOperand())) return nullptr; @@ -676,7 +689,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { auto Result = SEAI->getCaseResult(InjectedEnumElement); // Replace select_enum_addr by the result - replaceInstUsesWith(*SEAI, Result.getDef()); + replaceInstUsesWith(*SEAI, Result); return nullptr; } @@ -705,7 +718,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { if (SI->getDest() == IEAI->getOperand()) return nullptr; } - // Allow all instructions inbetween, which don't have any dependency to + // Allow all instructions in between, which don't have any dependency to // the store. if (AA->mayWriteToMemory(&*II, IEAI->getOperand())) return nullptr; @@ -750,7 +763,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { if (!IEAI->getElement()->hasArgumentType()) { EnumInst *E = Builder.createEnum(IEAI->getLoc(), SILValue(), IEAI->getElement(), - IEAI->getOperand().getType().getObjectType()); + IEAI->getOperand()->getType().getObjectType()); Builder.createStore(IEAI->getLoc(), E, IEAI->getOperand()); return eraseInstFromFunction(*IEAI); } @@ -770,7 +783,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { if (SI) { // Find a Store whose destination is taken from an init_enum_data_addr // whose address is same allocation as our inject_enum_addr. - DataAddrInst = dyn_cast(SI->getDest().getDef()); + DataAddrInst = dyn_cast(SI->getDest()); if (DataAddrInst && DataAddrInst->getOperand() == IEAI->getOperand()) break; SI = nullptr; @@ -784,8 +797,8 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { // Allowing us to perform the same optimization as for the store. // // %alloca = alloc_stack - // apply(%alloca#1,...) - // %load = load %alloca#1 + // apply(%alloca,...) + // %load = load %alloca // %1 = enum $EnumType, $EnumType.case, %load // store %1 to %nopayload_addr // @@ -795,7 +808,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { for (auto &Opd : AI->getArgumentOperands()) { // Found an apply that initializes the enum. We can optimize this by // localizing the initialization to an alloc_stack and loading from it. - DataAddrInst = dyn_cast(Opd.get().getDef()); + DataAddrInst = dyn_cast(Opd.get()); if (DataAddrInst && DataAddrInst->getOperand() == IEAI->getOperand() && Params[ArgIdx].getConvention() == ParameterConvention::Indirect_Out) { @@ -819,7 +832,7 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { EnumInst *E = Builder.createEnum(DataAddrInst->getLoc(), SI->getSrc(), DataAddrInst->getElement(), - DataAddrInst->getOperand().getType().getObjectType()); + DataAddrInst->getOperand()->getType().getObjectType()); Builder.createStore(DataAddrInst->getLoc(), E, DataAddrInst->getOperand()); // Cleanup. eraseInstFromFunction(*SI); @@ -831,18 +844,15 @@ SILCombiner::visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) { // Localize the address access. Builder.setInsertionPoint(AI); auto *AllocStack = Builder.createAllocStack(DataAddrInst->getLoc(), - EnumInitOperand->get().getType()); - EnumInitOperand->set(AllocStack->getAddressResult()); + EnumInitOperand->get()->getType()); + EnumInitOperand->set(AllocStack); Builder.setInsertionPoint(std::next(SILBasicBlock::iterator(AI))); - SILValue Load(Builder.createLoad(DataAddrInst->getLoc(), - AllocStack->getAddressResult()), - 0); + SILValue Load(Builder.createLoad(DataAddrInst->getLoc(), AllocStack)); EnumInst *E = Builder.createEnum( DataAddrInst->getLoc(), Load, DataAddrInst->getElement(), - DataAddrInst->getOperand().getType().getObjectType()); + DataAddrInst->getOperand()->getType().getObjectType()); Builder.createStore(DataAddrInst->getLoc(), E, DataAddrInst->getOperand()); - Builder.createDeallocStack(DataAddrInst->getLoc(), - AllocStack->getContainerResult()); + Builder.createDeallocStack(DataAddrInst->getLoc(), AllocStack); eraseInstFromFunction(*DataAddrInst); return eraseInstFromFunction(*IEAI); } @@ -883,15 +893,15 @@ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI) { if (TEDAI->use_empty()) return nullptr; - // If our enum type is address only, we can not do anything here. The key + // If our enum type is address only, we cannot do anything here. The key // thing to remember is that an enum is address only if any of its cases are // address only. So we *could* have a loadable payload resulting from the // TEDAI without the TEDAI being loadable itself. - if (TEDAI->getOperand().getType().isAddressOnly(TEDAI->getModule())) + if (TEDAI->getOperand()->getType().isAddressOnly(TEDAI->getModule())) return nullptr; // For each user U of the take_enum_data_addr... - for (auto U : getNonDebugUses(*TEDAI)) + for (auto U : getNonDebugUses(TEDAI)) // Check if it is load. If it is not a load, bail... if (!isa(U->getUser())) return nullptr; @@ -906,7 +916,7 @@ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI) { // Go back through a second time now that we know all of our users are // loads. Perform the transformation on each load. SmallVector ToRemove; - for (auto U : getNonDebugUses(*TEDAI)) { + for (auto U : getNonDebugUses(TEDAI)) { // Grab the load. LoadInst *L = cast(U->getUser()); @@ -915,7 +925,7 @@ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *TEDAI) { auto *D = Builder.createUncheckedEnumData(Loc, Ld, EnumElt, PayloadType); // Replace all uses of the old load with the data and erase the old load. - replaceInstUsesWith(*L, D, 0); + replaceInstUsesWith(*L, D); ToRemove.push_back(L); } @@ -959,13 +969,13 @@ SILInstruction *SILCombiner::visitCondBranchInst(CondBranchInst *CBI) { // No bb args should be passed if (!CBI->getTrueArgs().empty() || !CBI->getFalseArgs().empty()) return nullptr; - auto EnumOperandTy = SEI->getEnumOperand().getType(); + auto EnumOperandTy = SEI->getEnumOperand()->getType(); // Type should be loadable if (!EnumOperandTy.isLoadable(SEI->getModule())) return nullptr; - // Result of the selec_enum should be a boolean. - if (SEI->getType() != CBI->getCondition().getType()) + // Result of the select_enum should be a boolean. + if (SEI->getType() != CBI->getCondition()->getType()) return nullptr; // If any of cond_br edges are critical edges, do not perform @@ -1076,9 +1086,9 @@ SILInstruction *SILCombiner::visitFixLifetimeInst(FixLifetimeInst *FLI) { // fix_lifetime(alloc_stack) -> fix_lifetime(load(alloc_stack)) Builder.setCurrentDebugScope(FLI->getDebugScope()); if (auto *AI = dyn_cast(FLI->getOperand())) { - if (FLI->getOperand().getType().isLoadable(FLI->getModule())) { - auto Load = Builder.createLoad(FLI->getLoc(), SILValue(AI, 1)); - return Builder.createFixLifetime(FLI->getLoc(), SILValue(Load, 0)); + if (FLI->getOperand()->getType().isLoadable(FLI->getModule())) { + auto Load = Builder.createLoad(FLI->getLoc(), AI); + return Builder.createFixLifetime(FLI->getLoc(), Load); } } return nullptr; diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index ad033e8b2cfaf..9a9a65eced054 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -110,15 +110,16 @@ static bool getFinalReleases(AllocBoxInst *ABI, auto seenRelease = false; SILInstruction *OneRelease = nullptr; - auto Box = ABI->getContainerResult(); - // We'll treat this like a liveness problem where the alloc_box is // the def. Each block that has a use of the owning pointer has the // value live-in unless it is the block with the alloc_box. - for (auto UI : Box.getUses()) { + for (auto UI : ABI->getUses()) { auto *User = UI->getUser(); auto *BB = User->getParent(); + if (isa(User)) + continue; + if (BB != DefBB) LiveIn.insert(BB); @@ -149,7 +150,7 @@ static bool getFinalReleases(AllocBoxInst *ABI, // release/dealloc. for (auto *BB : UseBlocks) if (!successorHasLiveIn(BB, LiveIn)) - if (!addLastRelease(Box, BB, Releases)) + if (!addLastRelease(ABI, BB, Releases)) return false; return true; @@ -178,7 +179,7 @@ static bool useCaptured(Operand *UI) { } static bool partialApplyEscapes(SILValue V, bool examineApply) { - for (auto UI : V.getUses()) { + for (auto UI : V->getUses()) { auto *User = UI->getUser(); // These instructions do not cause the address to escape. @@ -332,9 +333,9 @@ static SILInstruction* findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, bool inAppliedFunction, llvm::SmallVectorImpl &PromotedOperands) { - assert((Box.getType().is() - || Box.getType() - == SILType::getNativeObjectType(Box.getType().getASTContext())) + assert((Box->getType().is() + || Box->getType() + == SILType::getNativeObjectType(Box->getType().getASTContext())) && "Expected an object pointer!"); llvm::SmallVector LocalPromotedOperands; @@ -342,7 +343,7 @@ static SILInstruction* findUnexpectedBoxUse(SILValue Box, // Scan all of the uses of the retain count value, collecting all // the releases and validating that we don't have an unexpected // user. - for (auto UI : Box.getUses()) { + for (auto UI : Box->getUses()) { auto *User = UI->getUser(); // Retains and releases are fine. Deallocs are fine if we're not @@ -376,7 +377,7 @@ static bool canPromoteAllocBox(AllocBoxInst *ABI, llvm::SmallVectorImpl &PromotedOperands){ // Scan all of the uses of the address of the box to see if any // disqualifies the box from being promoted to the stack. - if (auto *User = findUnexpectedBoxUse(ABI->getContainerResult(), + if (auto *User = findUnexpectedBoxUse(ABI, /* examinePartialApply = */ true, /* inAppliedFunction = */ false, PromotedOperands)) { @@ -413,15 +414,19 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI, // Replace all uses of the address of the box's contained value with // the address of the stack location. - ABI->getAddressResult().replaceAllUsesWith(ASI->getAddressResult()); + for (Operand *Use : ABI->getUses()) { + if (auto *PBI = dyn_cast(Use->getUser())) { + PBI->replaceAllUsesWith(ASI); + } + } // Check to see if the alloc_box was used by a mark_uninitialized instruction. // If so, any uses of the pointer result need to keep using the MUI, not the // alloc_stack directly. If we don't do this, DI will miss the uses. - SILValue PointerResult = ASI->getAddressResult(); - for (auto UI : ASI->getAddressResult().getUses()) + SILValue PointerResult = ASI; + for (auto UI : ASI->getUses()) if (auto *MUI = dyn_cast(UI->getUser())) { - assert(ASI->getAddressResult().hasOneUse() && + assert(ASI->hasOneUse() && "alloc_stack used by mark_uninitialized, but not exclusively!"); PointerResult = MUI; break; @@ -444,7 +449,7 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI, for (auto Return : Returns) { SILBuilderWithScope BuildDealloc(Return); - BuildDealloc.createDeallocStack(Loc, ASI->getContainerResult()); + BuildDealloc.createDeallocStack(Loc, ASI); } // Remove any retain and release instructions. Since all uses of result #1 @@ -453,7 +458,7 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI, while (!ABI->use_empty()) { auto *User = (*ABI->use_begin())->getUser(); assert(isa(User) || isa(User) || - isa(User)); + isa(User) || isa(User)); User->eraseFromParent(); } @@ -505,16 +510,15 @@ PromotedParamCloner::PromotedParamCloner(SILFunction *Orig, assert(Orig->getDebugScope()->SILFn != getCloned()->getDebugScope()->SILFn); } -static void getClonedName(SILFunction *F, - ParamIndexList &PromotedParamIndices, - llvm::SmallString<64> &Name) { - llvm::raw_svector_ostream buffer(Name); - Mangle::Mangler M(buffer); - auto P = Mangle::SpecializationPass::AllocBoxToStack; - Mangle::FunctionSignatureSpecializationMangler FSSM(P, M, F); +static std::string getClonedName(SILFunction *F, + ParamIndexList &PromotedParamIndices) { + Mangle::Mangler M; + auto P = SpecializationPass::AllocBoxToStack; + FunctionSignatureSpecializationMangler FSSM(P, M, F); for (unsigned i : PromotedParamIndices) FSSM.setArgumentBoxToStack(i); FSSM.mangle(); + return M.finalize(); } /// \brief Create the function corresponding to the clone of the @@ -566,7 +570,9 @@ PromotedParamCloner::initCloned(SILFunction *Orig, Orig->getLocation(), Orig->isBare(), IsNotTransparent, Orig->isFragile(), Orig->isThunk(), Orig->getClassVisibility(), Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope()); - Fn->setSemanticsAttr(Orig->getSemanticsAttr()); + for (auto &Attr : Orig->getSemanticsAttrs()) { + Fn->addSemanticsAttr(Attr); + } Fn->setDeclCtx(Orig->getDeclContext()); return Fn; } @@ -683,8 +689,7 @@ LifetimeTracker::EndpointRange LifetimeTracker::getEndpoints() { if (TheValue->hasOneUse()) { Lifetime = ValueLifetime(); Lifetime->LastUsers.insert(TheValue->use_begin().getUser()); - } - else { + } else { ValueLifetimeAnalysis VLA(TheValue); Lifetime = VLA.computeFromDirectUses(); } @@ -703,8 +708,7 @@ specializePartialApply(PartialApplyInst *PartialApply, auto *F = FRI->getReferencedFunction(); assert(F && "Expected a referenced function!"); - llvm::SmallString<64> ClonedName; - getClonedName(F, PromotedParamIndices, ClonedName); + std::string ClonedName = getClonedName(F, PromotedParamIndices); auto &M = PartialApply->getModule(); @@ -740,20 +744,29 @@ specializePartialApply(PartialApplyInst *PartialApply, // of this box so we must now release it explicitly when the // partial_apply is released. auto box = cast(O.get()); - assert(box->getContainerResult() == O.get() && - "Expected promoted param to be an alloc_box container!"); // If the box address has a MUI, route accesses through it so DI still // works. - auto promoted = box->getAddressResult(); - for (auto use : promoted->getUses()) { - if (auto MUI = dyn_cast(use->getUser())) { - assert(promoted.hasOneUse() && "box value used by mark_uninitialized" - " but not exclusively!"); - promoted = MUI; - break; + SILInstruction *promoted = nullptr; + int numAddrUses = 0; + for (Operand *BoxUse : box->getUses()) { + if (auto *PBI = dyn_cast(BoxUse->getUser())) { + for (auto PBIUse : PBI->getUses()) { + numAddrUses++; + if (auto MUI = dyn_cast(PBIUse->getUser())) + promoted = MUI; + } } } + assert((!promoted || numAddrUses == 1) && + "box value used by mark_uninitialized but not exclusively!"); + + // We only reuse an existing project_box if it directly follows the + // alloc_box. This makes sure that the project_box dominates the + // partial_apply. + if (!promoted) + promoted = getOrCreateProjectBox(box); + Args.push_back(promoted); // If the partial_apply is dead, insert a release after it. diff --git a/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp b/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp index a37a654a8865c..8efff63b52a1a 100644 --- a/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp +++ b/lib/SILOptimizer/Transforms/ArrayCountPropagation.cpp @@ -1,8 +1,8 @@ -//===------ ArrayCountPropagation.cpp - Propagate the count of arrays -----===// +//===--- ArrayCountPropagation.cpp - Propagate the count of arrays --------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -91,7 +91,7 @@ bool ArrayAllocation::propagate() { return propagateCountToUsers(); } -/// Check that we have a array initialization call with a known count. +/// Check that we have an array initialization call with a known count. /// /// The returned array value is known not to be aliased since it was just /// allocated. @@ -114,7 +114,7 @@ bool ArrayAllocation::isInitializationWithKnownCount() { /// Collect all getCount users and check that there are no escapes or uses that /// could change the array value. bool ArrayAllocation::analyseArrayValueUses() { - return recursivelyCollectUses(ArrayValue.getDef()); + return recursivelyCollectUses(ArrayValue); } static bool doesNotChangeArrayCount(ArraySemanticsCall &C) { @@ -169,7 +169,7 @@ bool ArrayAllocation::propagateCountToUsers() { SmallVector Uses; for (auto *Op : Count->getUses()) { - if (Op->get().getType() == ArrayCount.getType()) { + if (Op->get()->getType() == ArrayCount->getType()) { Uses.push_back(Op); } } diff --git a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp index 7a6699731b7cc..5ba373ab17351 100644 --- a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp +++ b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -105,7 +105,7 @@ bool ArrayAllocation::mapInitializationStores() { if (!UnsafeMutablePointerExtract) return false; auto *PointerToAddress = dyn_cast_or_null( - getSingleNonDebugUser(*UnsafeMutablePointerExtract)); + getSingleNonDebugUser(UnsafeMutablePointerExtract)); if (!PointerToAddress) return false; @@ -116,7 +116,7 @@ bool ArrayAllocation::mapInitializationStores() { // Store to the base. auto *SI = dyn_cast(Inst); - if (SI && SI->getDest() == SILValue(PointerToAddress, 0)) { + if (SI && SI->getDest() == PointerToAddress) { // We have already seen an entry for this index bail. if (ElementValueMap.count(0)) return false; @@ -125,12 +125,12 @@ bool ArrayAllocation::mapInitializationStores() { } else if (SI) return false; - // Store a index_addr projection. + // Store an index_addr projection. auto *IndexAddr = dyn_cast(Inst); if (!IndexAddr) return false; - SI = dyn_cast_or_null(getSingleNonDebugUser(*IndexAddr)); - if (!SI || SI->getDest().getDef() != IndexAddr) + SI = dyn_cast_or_null(getSingleNonDebugUser(IndexAddr)); + if (!SI || SI->getDest() != IndexAddr) return false; auto *Index = dyn_cast(IndexAddr->getIndex()); if (!Index) @@ -148,7 +148,7 @@ bool ArrayAllocation::mapInitializationStores() { return !ElementValueMap.empty(); } -/// Check that we have a array initialization call with known elements. +/// Check that we have an array initialization call with known elements. /// /// The returned array value is known not to be aliased since it was just /// allocated. @@ -165,7 +165,7 @@ bool ArrayAllocation::isInitializationWithKnownElements() { /// Propagate the elements of an array literal to get_element method calls on /// the same array. /// -/// We have to prove that the the array value is not changed in between the +/// We have to prove that the array value is not changed in between the /// creation and the method call to get_element. bool ArrayAllocation::findValueReplacements() { if (!isInitializationWithKnownElements()) @@ -185,7 +185,7 @@ bool ArrayAllocation::findValueReplacements() { /// Collect all get_element users and check that there are no escapes or uses /// that could change the array value. bool ArrayAllocation::analyseArrayValueUses() { - return recursivelyCollectUses(ArrayValue.getDef()); + return recursivelyCollectUses(ArrayValue); } static bool doesNotChangeArray(ArraySemanticsCall &C) { diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index c49ce1fa671ca..52ca9ca998cf1 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -7,6 +7,8 @@ set(TRANSFORMS_SOURCES Transforms/DeadCodeElimination.cpp Transforms/DeadObjectElimination.cpp Transforms/DeadStoreElimination.cpp + Transforms/Devirtualizer.cpp + Transforms/GenericSpecializer.cpp Transforms/MergeCondFail.cpp Transforms/RedundantLoadElimination.cpp Transforms/RedundantOverflowCheckRemoval.cpp diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index c58d070fa55ad..43eaf3d23f505 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -1,8 +1,8 @@ -//===- CSE.cpp - Simple and fast CSE pass ---------------------------------===// +//===--- CSE.cpp - Simple and fast CSE pass -------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -129,6 +129,10 @@ class HashVisitor : public SILInstructionVisitor { return llvm::hash_combine(X->getKind(), X->getOperand(), X->getField()); } + hash_code visitProjectBoxInst(ProjectBoxInst *X) { + return llvm::hash_combine(X->getKind(), X->getOperand()); + } + hash_code visitRefToRawPointerInst(RefToRawPointerInst *X) { return llvm::hash_combine(X->getKind(), X->getOperand()); } @@ -537,7 +541,7 @@ bool CSE::processNode(DominanceInfoNode *Node) { if (SILValue V = simplifyInstruction(Inst)) { DEBUG(llvm::dbgs() << "SILCSE SIMPLIFY: " << *Inst << " to: " << *V << '\n'); - SILValue(Inst, 0).replaceAllUsesWith(V); + Inst->replaceAllUsesWith(V); Inst->eraseFromParent(); Changed = true; ++NumSimplify; @@ -619,7 +623,7 @@ bool CSE::canHandle(SILInstruction *Inst) { return !WMI->isVolatile(); } if (auto *EMI = dyn_cast(Inst)) { - return !EMI->getOperand().getType().isAddress(); + return !EMI->getOperand()->getType().isAddress(); } switch (Inst->getKind()) { case ValueKind::FunctionRefInst: @@ -637,6 +641,7 @@ bool CSE::canHandle(SILInstruction *Inst) { case ValueKind::ValueMetatypeInst: case ValueKind::ObjCProtocolInst: case ValueKind::RefElementAddrInst: + case ValueKind::ProjectBoxInst: case ValueKind::IndexRawPointerInst: case ValueKind::IndexAddrInst: case ValueKind::PointerToAddressInst: diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp index ab55c54f700f0..de46a6893d57c 100644 --- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp +++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -26,9 +26,9 @@ // Useless copies of address-only types look like this: // // %copy = alloc_stack $T -// copy_addr %arg to [initialization] %copy#1 : $*T -// %ret = apply %callee(%copy#1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () -// dealloc_stack %copy#0 : $*@local_storage T +// copy_addr %arg to [initialization] %copy : $*T +// %ret = apply %callee(%copy) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () +// dealloc_stack %copy : $*T // destroy_addr %arg : $*T // // Eliminating the address-only copies eliminates a very expensive call to @@ -84,18 +84,17 @@ static llvm::cl::opt EnableCopyForwarding("enable-copyforwarding", static llvm::cl::opt EnableDestroyHoisting("enable-destroyhoisting", llvm::cl::init(true)); -/// \return true of the given object can only be accessed via the given def -/// (this def uniquely identifies the object). +/// \return true if the given copy source value can only be accessed via the +/// given def (this def uniquely identifies the object). /// /// (1) An "in" argument. /// (inouts are also nonaliased, but won't be destroyed in scope) /// /// (2) A local alloc_stack variable. -static bool isIdentifiedObject(SILValue Def, SILFunction *F) { +static bool isIdentifiedSourceValue(SILValue Def) { if (SILArgument *Arg = dyn_cast(Def)) { // Check that the argument is passed as an in type. This means there are - // no aliases accessible within this function scope. We may be able to just - // assert this. + // no aliases accessible within this function scope. ParameterConvention Conv = Arg->getParameterInfo().getConvention(); switch (Conv) { case ParameterConvention::Indirect_In: @@ -112,6 +111,32 @@ static bool isIdentifiedObject(SILValue Def, SILFunction *F) { return false; } +/// \return true if the given copy dest value can only be accessed via the given +/// def (this def uniquely identifies the object). +/// +/// (1) An "out" or inout argument. +/// +/// (2) A local alloc_stack variable. +static bool isIdentifiedDestValue(SILValue Def) { + if (SILArgument *Arg = dyn_cast(Def)) { + // Check that the argument is passed as an out type. This means there are + // no aliases accessible within this function scope. + ParameterConvention Conv = Arg->getParameterInfo().getConvention(); + switch (Conv) { + case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_Out: + return true; + default: + DEBUG(llvm::dbgs() << " Skipping Def: Not an @in argument!\n"); + return false; + } + } + else if (isa(Def)) + return true; + + return false; +} + /// Return the parameter convention used by Apply to pass an argument /// indirectly via Address. /// @@ -428,7 +453,7 @@ class CopyForwarding { /// The collected use points will be consulted during forward and backward /// copy propagation. bool CopyForwarding::collectUsers() { - for (auto UI : CurrentDef.getUses()) { + for (auto UI : CurrentDef->getUses()) { SILInstruction *UserInst = UI->getUser(); if (auto *Apply = dyn_cast(UserInst)) { /// A call to materializeForSet exposes an address within the parent @@ -466,6 +491,8 @@ bool CopyForwarding::collectUsers() { case ValueKind::DebugValueAddrInst: SrcDebugValueInsts.insert(cast(UserInst)); break; + case ValueKind::DeallocStackInst: + break; default: // Most likely one of: // init_enum_data_addr @@ -504,7 +531,7 @@ bool CopyForwarding::propagateCopy(CopyAddrInst *CopyInst) { // Gather a list of CopyDest users in this block. SmallPtrSet DestUserInsts; - for (auto UI : CopyDest.getUses()) { + for (auto UI : CopyDest->getUses()) { SILInstruction *UserInst = UI->getUser(); if (UserInst != CopyInst && UI->getUser()->getParent() == BB) DestUserInsts.insert(UI->getUser()); @@ -561,10 +588,12 @@ bool CopyForwarding::areCopyDestUsersDominatedBy( SILValue CopyDest = Copy->getDest(); DominanceInfo *DT = nullptr; - for (auto *Use : CopyDest.getUses()) { + for (auto *Use : CopyDest->getUses()) { auto *UserInst = Use->getUser(); if (UserInst == Copy) continue; + if (isa(UserInst)) + continue; // Initialize the dominator tree info. if (!DT) @@ -591,6 +620,38 @@ bool CopyForwarding::areCopyDestUsersDominatedBy( return true; } +/// Returns the associated dealloc_stack if \p ASI has a single dealloc_stack. +/// Usually this is the case, but the optimizations may generate something like: +/// %1 = alloc_stack +/// if (...) { +/// dealloc_stack %1 +/// } else { +/// dealloc_stack %1 +/// } +static DeallocStackInst *getSingleDealloc(AllocStackInst *ASI) { + DeallocStackInst *SingleDSI = nullptr; + for (Operand *Use : ASI->getUses()) { + if (auto *DSI = dyn_cast(Use->getUser())) { + if (SingleDSI) + return nullptr; + SingleDSI = DSI; + } + } + return SingleDSI; +} + +/// Replace all uses of \p ASI by \p RHS, except the dealloc_stack. +static void replaceAllUsesExceptDealloc(AllocStackInst *ASI, ValueBase *RHS) { + llvm::SmallVector Uses; + for (Operand *Use : ASI->getUses()) { + if (!isa(Use->getUser())) + Uses.push_back(Use); + } + for (Operand *Use : Uses) { + Use->set(RHS); + } +} + /// Perform forward copy-propagation. Find a set of uses that the given copy can /// forward to and replace them with the copy's source. /// @@ -602,9 +663,9 @@ bool CopyForwarding::areCopyDestUsersDominatedBy( /// %copy = alloc_stack $T /// ... /// CurrentBlock: -/// copy_addr %arg to [initialization] %copy#1 : $*T +/// copy_addr %arg to [initialization] %copy : $*T /// ... -/// %ret = apply %callee(%copy#1) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () +/// %ret = apply %callee(%copy) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () /// \endcode /// /// If the last use (deinit) is a copy, replace it with a destroy+copy[init]. @@ -616,20 +677,25 @@ bool CopyForwarding::forwardPropagateCopy( CopyAddrInst *CopyInst, SmallPtrSetImpl &DestUserInsts) { + SILValue CopyDest = CopyInst->getDest(); + // Require the copy dest to be a simple alloc_stack. This ensures that all + // instructions that may read from the destination address depend on CopyDest. + if (!isa(CopyDest)) + return false; + // Looking at // // copy_addr %Src, [init] %Dst // - // We can reuse %Src if it is destroyed at %Src and not initialized again. To + // We can reuse %Src if it is dead after the copy and not reinitialized. To // know that we can safely replace all uses of %Dst with source we must know // that it is uniquely named and cannot be accessed outside of the function // (an alloc_stack instruction qualifies for this, an inout parameter does // not). Additionally, we must know that all accesses to %Dst further on must // have had this copy on their path (there might be reinitialization of %Dst - // later, but there must no be a path around this copy that reads from %Dst). + // later, but there must not be a path around this copy that reads from %Dst). SmallVector DestUses; - if (isa(CopyInst->getDest()) && /* Uniquely identified name */ - isSourceDeadAtCopy(CopyInst) && + if (isSourceDeadAtCopy(CopyInst) && areCopyDestUsersDominatedBy(CopyInst, DestUses)) { // Replace all uses of Dest with a use of Src. @@ -648,16 +714,14 @@ bool CopyForwarding::forwardPropagateCopy( return true; } - SILValue CopyDest = CopyInst->getDest(); SILInstruction *DefDealloc = nullptr; - if (isa(CurrentDef)) { - SILValue StackAddr(CurrentDef.getDef(), 0); - if (!StackAddr.hasOneUse()) { + if (auto *ASI = dyn_cast(CurrentDef)) { + DefDealloc = getSingleDealloc(ASI); + if (!DefDealloc) { DEBUG(llvm::dbgs() << " Skipping copy" << *CopyInst << " stack address has multiple uses.\n"); return false; } - DefDealloc = StackAddr.use_begin()->getUser(); } // Scan forward recording all operands that use CopyDest until we see the @@ -722,6 +786,30 @@ bool CopyForwarding::forwardPropagateCopy( return true; } +/// Given an address defined by 'Def', find the object root and all direct uses, +/// not including: +/// - 'Def' itself +/// - Transitive uses of 'Def' (listed elsewhere in DestUserInsts) +/// +/// If the returned root is not 'Def' itself, then 'Def' must be an address +/// projection that can be trivially rematerialized with the root as its +/// operand. +static ValueBase * +findAddressRootAndUsers(ValueBase *Def, + SmallPtrSetImpl &RootUserInsts) { + if (isa(Def) || isa(Def)) { + SILValue InitRoot = cast(Def)->getOperand(0); + for (auto *Use : InitRoot->getUses()) { + auto *UserInst = Use->getUser(); + if (UserInst == Def) + continue; + RootUserInsts.insert(UserInst); + } + return InitRoot; + } + return Def; +} + /// Perform backward copy-propagation. Find the initialization point of the /// copy's source and replace the initializer's address with the copy's dest. bool CopyForwarding::backwardPropagateCopy( @@ -729,21 +817,34 @@ bool CopyForwarding::backwardPropagateCopy( SmallPtrSetImpl &DestUserInsts) { SILValue CopySrc = CopyInst->getSrc(); - ValueBase *CopyDestDef = CopyInst->getDest().getDef(); + ValueBase *CopyDestDef = CopyInst->getDest(); + SmallPtrSet RootUserInsts; + ValueBase *CopyDestRoot = findAddressRootAndUsers(CopyDestDef, RootUserInsts); + + // Require the copy dest value to be identified by this address. This ensures + // that all instructions that may write to destination address depend on + // CopyDestRoot. + if (!isIdentifiedDestValue(CopyDestRoot)) + return false; // Scan backward recording all operands that use CopySrc until we see the // most recent init of CopySrc. bool seenInit = false; + bool seenCopyDestDef = false; + // ValueUses records the uses of CopySrc in reverse order. SmallVector ValueUses; SmallVector DebugValueInstsToDelete; auto SI = CopyInst->getIterator(), SE = CopyInst->getParent()->begin(); while (SI != SE) { --SI; SILInstruction *UserInst = &*SI; + if (UserInst == CopyDestDef) + seenCopyDestDef = true; // If we see another use of Dest, then Dest is live after the Src location // is initialized, so we really need the copy. - if (DestUserInsts.count(UserInst) || UserInst == CopyDestDef) { + if (UserInst == CopyDestRoot || DestUserInsts.count(UserInst) + || RootUserInsts.count(UserInst)) { if (auto *DVAI = dyn_cast(UserInst)) { DebugValueInstsToDelete.push_back(DVAI); continue; @@ -763,7 +864,7 @@ bool CopyForwarding::backwardPropagateCopy( // If this use cannot be analyzed, then abort. if (!AnalyzeUse.Oper) return false; - // Otherwise record the operand. + // Otherwise record the operand with the earliest use last in the list. ValueUses.push_back(AnalyzeUse.Oper); // If this is an init, we're done searching. if (seenInit) @@ -785,6 +886,10 @@ bool CopyForwarding::backwardPropagateCopy( Copy->setIsInitializationOfDest(IsInitialization); } } + // Rematerialize the projection if needed by simply moving it. + if (seenCopyDestDef) { + cast(CopyDestDef)->moveBefore(&*SI); + } // Now that an init was found, it is safe to substitute all recorded uses // with the copy's dest. for (auto *Oper : ValueUses) { @@ -985,7 +1090,7 @@ void CopyForwarding::forwardCopiesOf(SILValue Def, SILFunction *F) { /// %2 = alloc_stack $T /// ... // arbitrary control flow, but no other uses of %0 /// bbN: -/// copy_addr [take] %2#1 to [initialization] %0 : $*T +/// copy_addr [take] %2 to [initialization] %0 : $*T /// ... // no writes /// return static bool canNRVO(CopyAddrInst *CopyInst) { @@ -997,7 +1102,11 @@ static bool canNRVO(CopyAddrInst *CopyInst) { // optimization will early-initialize the copy dest, so we can't allow aliases // to be accessed between the initialization and the return. auto OutArg = dyn_cast(CopyInst->getDest()); - if (!OutArg || !OutArg->getParameterInfo().isIndirect()) + if (!OutArg) + return false; + + auto ArgConv = OutArg->getParameterInfo().getConvention(); + if (ArgConv != ParameterConvention::Indirect_Out) return false; SILBasicBlock *BB = CopyInst->getParent(); @@ -1020,7 +1129,8 @@ static bool canNRVO(CopyAddrInst *CopyInst) { static void performNRVO(CopyAddrInst *CopyInst) { DEBUG(llvm::dbgs() << "NRVO eliminates copy" << *CopyInst); ++NumCopyNRVO; - CopyInst->getSrc().replaceAllUsesWith(CopyInst->getDest()); + replaceAllUsesExceptDealloc(cast(CopyInst->getSrc()), + CopyInst->getDest()); assert(CopyInst->getSrc() == CopyInst->getDest() && "bad NRVO"); CopyInst->eraseFromParent(); } @@ -1059,7 +1169,7 @@ class CopyForwardingPass : public SILFunctionTransform continue; } SILValue Def = CopyInst->getSrc(); - if (isIdentifiedObject(Def, getFunction())) + if (isIdentifiedSourceValue(Def)) CopiedDefs.insert(Def); else { DEBUG(llvm::dbgs() << " Skipping Def: " << Def diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp index 3d43445233ada..13d318d7bdcc8 100644 --- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -91,7 +91,7 @@ class DCE : public SILFunctionTransform { /// Tracks if the pass changed branches. bool BranchesChanged; - /// Trackes if the pass changed ApplyInsts. + /// Tracks if the pass changed ApplyInsts. bool CallsChanged; /// The entry point to the transformation. @@ -197,7 +197,7 @@ void DCE::markValueLive(ValueBase *V) { } /// Gets the producing instruction of a cond_fail condition. Currently these -/// are overflow builtints but may be extended to other instructions in the +/// are overflow builtins but may be extended to other instructions in the /// future. static SILInstruction *getProducer(CondFailInst *CFI) { // Check for the pattern: @@ -235,7 +235,7 @@ void DCE::markLive(SILFunction &F) { // definition is alive. SILValue Op = FLI->getOperand(); auto *OpInst = dyn_cast(Op); - if (OpInst && !Op.getType().isAddress()) { + if (OpInst && !Op->getType().isAddress()) { addReverseDependency(OpInst, FLI); } else { markValueLive(FLI); @@ -280,18 +280,20 @@ void DCE::markTerminatorArgsLive(SILBasicBlock *Pred, // delivers those arguments. markValueLive(Term); - switch (Term->getKind()) { - default: - llvm_unreachable("Unexpected terminator kind!"); + switch (Term->getTermKind()) { + case TermKind::ReturnInst: + case TermKind::ThrowInst: - case ValueKind::UnreachableInst: - case ValueKind::SwitchValueInst: + case TermKind::UnreachableInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::CheckedCastAddrBranchInst: llvm_unreachable("Unexpected argument for terminator kind!"); break; - case ValueKind::DynamicMethodBranchInst: - case ValueKind::SwitchEnumInst: - case ValueKind::CheckedCastBranchInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::SwitchEnumInst: + case TermKind::CheckedCastBranchInst: assert(ArgIndex == 0 && "Expected a single argument!"); // We do not need to do anything with these. If the resulting @@ -300,26 +302,26 @@ void DCE::markTerminatorArgsLive(SILBasicBlock *Pred, // single operand of these instructions as live. break; - case ValueKind::BranchInst: - markValueLive(cast(Term)->getArg(ArgIndex).getDef()); + case TermKind::BranchInst: + markValueLive(cast(Term)->getArg(ArgIndex)); break; - case ValueKind::CondBranchInst: { + case TermKind::CondBranchInst: { auto *CondBr = cast(Term); if (CondBr->getTrueBB() == Succ) { auto TrueArgs = CondBr->getTrueArgs(); - markValueLive(TrueArgs[ArgIndex].getDef()); + markValueLive(TrueArgs[ArgIndex]); } if (CondBr->getFalseBB() == Succ) { auto FalseArgs = CondBr->getFalseArgs(); - markValueLive(FalseArgs[ArgIndex].getDef()); + markValueLive(FalseArgs[ArgIndex]); } break; } - case ValueKind::TryApplyInst: { + case TermKind::TryApplyInst: { assert(ArgIndex == 0 && "Expect a single argument!"); break; } @@ -332,7 +334,7 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) { // Conceptually, the dependency from a debug instruction to its definition // is in reverse direction: Only if its definition (the Arg) is alive, also // the debug_value instruction is alive. - for (Operand *DU : getDebugUses(*Arg)) + for (Operand *DU : getDebugUses(Arg)) markValueLive(DU->getUser()); if (Arg->isFunctionArg()) @@ -350,12 +352,12 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) { void DCE::propagateLiveness(SILInstruction *I) { if (!isa(I)) { for (auto &O : I->getAllOperands()) - markValueLive(O.get().getDef()); + markValueLive(O.get()); // Conceptually, the dependency from a debug instruction to its definition // is in reverse direction: Only if its definition is alive, also the // debug_value instruction is alive. - for (Operand *DU : getDebugUses(*I)) + for (Operand *DU : getDebugUses(I)) markValueLive(DU->getUser()); // Handle all other reverse-dependency instructions, like cond_fail and @@ -366,35 +368,30 @@ void DCE::propagateLiveness(SILInstruction *I) { return; } - switch (I->getKind()) { -#define TERMINATOR(ID, PARENT, MEM, RELEASE) -#define VALUE(ID, PARENT) case ValueKind::ID: -#include "swift/SIL/SILNodes.def" - llvm_unreachable("Unexpected terminator instruction!"); - - case ValueKind::BranchInst: - case ValueKind::UnreachableInst: + switch (ValueKindAsTermKind(I->getKind())) { + case TermKind::BranchInst: + case TermKind::UnreachableInst: return; - case ValueKind::ReturnInst: - case ValueKind::ThrowInst: - case ValueKind::CondBranchInst: - case ValueKind::SwitchEnumInst: - case ValueKind::SwitchEnumAddrInst: - case ValueKind::DynamicMethodBranchInst: - case ValueKind::CheckedCastBranchInst: - markValueLive(I->getOperand(0).getDef()); + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::CondBranchInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + markValueLive(I->getOperand(0)); return; - case ValueKind::TryApplyInst: - case ValueKind::SwitchValueInst: + case TermKind::TryApplyInst: + case TermKind::SwitchValueInst: for (auto &O : I->getAllOperands()) - markValueLive(O.get().getDef()); + markValueLive(O.get()); return; - case ValueKind::CheckedCastAddrBranchInst: - markValueLive(I->getOperand(0).getDef()); - markValueLive(I->getOperand(1).getDef()); + case TermKind::CheckedCastAddrBranchInst: + markValueLive(I->getOperand(0)); + markValueLive(I->getOperand(1)); return; } llvm_unreachable("corrupt instruction!"); @@ -455,9 +452,9 @@ bool DCE::removeDead(SILFunction &F) { DEBUG(llvm::dbgs() << "Removing dead argument:\n"); DEBUG(Inst->dump()); - for (unsigned i = 0, e = Inst->getNumTypes(); i != e; ++i) { - auto *Undef = SILUndef::get(Inst->getType(i), Inst->getModule()); - SILValue(Inst, i).replaceAllUsesWith(Undef); + if (Inst->hasValue()) { + auto *Undef = SILUndef::get(Inst->getType(), Inst->getModule()); + Inst->replaceAllUsesWith(Undef); } Changed = true; @@ -485,9 +482,9 @@ bool DCE::removeDead(SILFunction &F) { DEBUG(llvm::dbgs() << "Removing dead instruction:\n"); DEBUG(Inst->dump()); - for (unsigned i = 0, e = Inst->getNumTypes(); i != e; ++i) { - auto *Undef = SILUndef::get(Inst->getType(i), Inst->getModule()); - SILValue(Inst, i).replaceAllUsesWith(Undef); + if (Inst->hasValue()) { + auto *Undef = SILUndef::get(Inst->getType(), Inst->getModule()); + Inst->replaceAllUsesWith(Undef); } diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp index d8eec61966ce8..5e882a014a109 100644 --- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp @@ -1,8 +1,8 @@ -//===-- DeadObjectElimination.h - Remove unused objects ------------------===// +//===--- DeadObjectElimination.cpp - Remove unused objects ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,6 +34,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" @@ -79,7 +80,7 @@ static SILFunction *getDestructor(AllocRefInst *ARI) { DEBUG(llvm::dbgs() << " Found destructor!\n"); - // If the destructor has an objc_method calling convention, we can not + // If the destructor has an objc_method calling convention, we cannot // analyze it since it could be swapped out from under us at runtime. if (Fn->getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { DEBUG(llvm::dbgs() << " Found objective-c destructor. Can't " @@ -123,7 +124,7 @@ static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) { // destructor. RefCountingOperations on other instructions could have side // effects though. if (auto *RefInst = dyn_cast(&I)) { - if (RefInst->getOperand(0).stripCasts().getDef() == Self) { + if (stripCasts(RefInst->getOperand(0)) == Self) { // For now all ref counting insts have 1 operand. Put in an assert // just in case. assert(RefInst->getNumOperands() == 1 && @@ -146,9 +147,9 @@ static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) { } // dealloc_ref on self can be ignored, but dealloc_ref on anything else - // can not be eliminated. + // cannot be eliminated. if (auto *DeallocRef = dyn_cast(&I)) { - if (DeallocRef->getOperand().stripCasts().getDef() == Self) { + if (stripCasts(DeallocRef->getOperand()) == Self) { DEBUG(llvm::dbgs() << " SAFE! dealloc_ref on self.\n"); continue; } else { @@ -160,7 +161,7 @@ static bool doesDestructorHaveSideEffects(AllocRefInst *ARI) { // Storing into the object can be ignored. if (auto *SI = dyn_cast(&I)) - if (SI->getDest().stripAddressProjections().getDef() == Self) { + if (stripAddressProjections(SI->getDest()) == Self) { DEBUG(llvm::dbgs() << " SAFE! Instruction is a store into " "self.\n"); continue; @@ -179,9 +180,7 @@ void static removeInstructions(ArrayRef UsersToRemove) { for (auto *I : UsersToRemove) { if (!I->use_empty()) - for (unsigned i = 0, e = I->getNumTypes(); i != e; ++i) - SILValue(I, i).replaceAllUsesWith(SILUndef::get(I->getType(i), - I->getModule())); + I->replaceAllUsesWith(SILUndef::get(I->getType(), I->getModule())); // Now we know that I should not have any uses... erase it from its parent. I->eraseFromParent(); } @@ -227,7 +226,7 @@ static bool canZapInstruction(SILInstruction *Inst) { /// Analyze the use graph of AllocRef for any uses that would prevent us from /// zapping it completely. static bool -hasUnremoveableUsers(SILInstruction *AllocRef, UserList &Users) { +hasUnremovableUsers(SILInstruction *AllocRef, UserList &Users) { SmallVector Worklist; Worklist.push_back(AllocRef); @@ -331,7 +330,7 @@ namespace { /// dead arrays. We just need a slightly better destructor analysis to prove /// that it only releases elements. class DeadObjectAnalysis { - // Map a each address projection of this object to a list of stores. + // Map each address projection of this object to a list of stores. // Do not iterate over this map's entries. using AddressToStoreMap = llvm::DenseMap >; @@ -372,7 +371,7 @@ class DeadObjectAnalysis { private: void addStore(StoreInst *Store, IndexTrieNode *AddressNode); - bool recursivelyCollectInteriorUses(ValueBase *defInst, + bool recursivelyCollectInteriorUses(ValueBase *DefInst, IndexTrieNode *AddressNode, bool IsInteriorAddress); @@ -384,7 +383,7 @@ class DeadObjectAnalysis { // Record a store into this object. void DeadObjectAnalysis:: addStore(StoreInst *Store, IndexTrieNode *AddressNode) { - if (Store->getSrc().getType().isTrivial(Store->getModule())) + if (Store->getSrc()->getType().isTrivial(Store->getModule())) return; // SSAUpdater cannot handle multiple defs in the same blocks. Therefore, we @@ -438,7 +437,7 @@ recursivelyCollectInteriorUses(ValueBase *DefInst, // Initialization points. if (auto *Store = dyn_cast(User)) { // Bail if this address is stored to another object. - if (Store->getDest().getDef() != DefInst) { + if (Store->getDest() != DefInst) { DEBUG(llvm::dbgs() << " Found an escaping store: " << *User); return false; } @@ -506,7 +505,7 @@ bool DeadObjectAnalysis::analyze() { // Populate AllValues, AddressProjectionTrie, and StoredLocations. AddressProjectionTrie = new IndexTrieNode(); - if (!recursivelyCollectInteriorUses(NewAddrValue.getDef(), + if (!recursivelyCollectInteriorUses(NewAddrValue, AddressProjectionTrie, false)) { return false; } @@ -545,7 +544,7 @@ static void insertReleases(ArrayRef Stores, assert(!Stores.empty()); SILValue StVal = Stores.front()->getSrc(); - SSAUp.Initialize(StVal.getType()); + SSAUp.Initialize(StVal->getType()); for (auto *Store : Stores) SSAUp.AddAvailableValue(Store->getParent(), Store->getSrc()); @@ -557,7 +556,7 @@ static void insertReleases(ArrayRef Stores, // per block, and all release points occur after all stores. Therefore we // can simply ask SSAUpdater for the reaching store. SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent()); - if (StVal.getType().isReferenceCounted(RelPoint->getModule())) + if (StVal->getType().isReferenceCounted(RelPoint->getModule())) B.createStrongRelease(RelPoint->getLoc(), RelVal)->getOperandRef(); else B.createReleaseValue(RelPoint->getLoc(), RelVal)->getOperandRef(); @@ -740,8 +739,8 @@ bool DeadObjectElimination::processAllocRef(AllocRefInst *ARI) { // Our destructor has no side effects, so if we can prove that no loads // escape, then we can completely remove the use graph of this alloc_ref. UserList UsersToRemove; - if (hasUnremoveableUsers(ARI, UsersToRemove)) { - DEBUG(llvm::dbgs() << " Found a use that can not be zapped...\n"); + if (hasUnremovableUsers(ARI, UsersToRemove)) { + DEBUG(llvm::dbgs() << " Found a use that cannot be zapped...\n"); return false; } @@ -760,8 +759,8 @@ bool DeadObjectElimination::processAllocStack(AllocStackInst *ASI) { return false; UserList UsersToRemove; - if (hasUnremoveableUsers(ASI, UsersToRemove)) { - DEBUG(llvm::dbgs() << " Found a use that can not be zapped...\n"); + if (hasUnremovableUsers(ASI, UsersToRemove)) { + DEBUG(llvm::dbgs() << " Found a use that cannot be zapped...\n"); return false; } @@ -781,7 +780,7 @@ bool DeadObjectElimination::processAllocApply(ApplyInst *AI) { ApplyInst *AllocBufferAI = nullptr; SILValue Arg0 = AI->getArgument(0); - if (Arg0.getType().isExistentialType()) { + if (Arg0->getType().isExistentialType()) { // This is a version of the initializer which receives a pre-allocated // buffer as first argument. If we want to delete the initializer we also // have to delete the allocation. diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index cf0d8ae723237..4f5b57a243f1b 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -1,8 +1,8 @@ -//===---- DeadStoreElimination.cpp - SIL Dead Store Elimination -----===// +//===--- DeadStoreElimination.cpp - SIL Dead Store Elimination ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,12 +27,12 @@ /// /// 2. Performing a post-order walk over the control flow graph, tracking any /// LSLocations that are read from or stored into in each basic block. After -/// eliminating any dead stores in single blocks, it computes a kill set for -/// each block. The kill set tracks what LSLocations are stored into by this -/// basic block and its successors. +/// eliminating any dead stores in single blocks, it computes a genset and +/// killset for each block. The genset keeps a list of upward visible stores +/// and the killset keeps a list of LSLocation this basic block reads (kills). /// -/// 3. An optimistic iterative dataflow is performed on the gen sets and kill -/// sets until convergence. +/// 3. An optimistic iterative dataflow is performed on the genset and killset +/// until convergence. /// /// At the core of DSE, there is the LSLocation class. a LSLocation is an /// abstraction of an object field in program. It consists of a base and a @@ -54,13 +54,6 @@ /// treated as killing the entire store. However, using ProjectionPath does /// lead to more memory uses. /// -/// TODO: Handle same value store in DSE, currently handled in RLE. -/// -/// e.g. -/// %0 = load %A -/// ... nothing happens in middle and the %A contains the value of %0. -/// store %0 to %A <---- no need to do this store. -/// //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-dead-store-elim" @@ -69,38 +62,67 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILValueProjection.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/Local.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include using namespace swift; -using swift::LSLocation; - -static llvm::cl::opt DisableLocalStoreDSE("disable-local-store-dse", - llvm::cl::init(true)); STATISTIC(NumDeadStores, "Number of dead stores removed"); STATISTIC(NumPartialDeadStores, "Number of partial dead stores removed"); -/// Are we building the gen/kill sets or actually performing the DSE. -enum class DSEComputeKind { BuildGenKillSet, PerformDSE }; +/// ComputeMaxStoreSet - If we ignore all reads, what is the max store set that +/// can reach a particular point in a basic block. This helps in generating +/// the genset and killset. i.e. if there is no upward visible store that can +/// reach the beginning of a basic block, then we know that the genset and +/// killset for the stored location need not be set for the basic block. +/// +/// BuildGenKillSet - Build the genset and killset of the basic block. +/// +/// PerformDSE - Perform the actual dead store elimination. +enum class DSEKind : unsigned { + ComputeMaxStoreSet = 0, + BuildGenKillSet = 1, + PerformDSE = 2, +}; + +/// Return the deallocate stack instructions corresponding to the given +/// AllocStackInst. +static llvm::SmallVector findDeallocStackInst( + AllocStackInst *ASI) { + llvm::SmallVector DSIs; + for (auto UI = ASI->use_begin(), E = ASI->use_end(); UI != E; ++UI) { + if (DeallocStackInst *D = dyn_cast(UI->getUser())) { + DSIs.push_back(D); + } + } + return DSIs; +} //===----------------------------------------------------------------------===// // Utility Functions //===----------------------------------------------------------------------===// -static inline bool isBuildingGenKillSet(DSEComputeKind Kind) { - return Kind == DSEComputeKind::BuildGenKillSet; +static inline bool isComputeMaxStoreSet(DSEKind Kind) { + return Kind == DSEKind::ComputeMaxStoreSet; +} + +static inline bool isBuildingGenKillSet(DSEKind Kind) { + return Kind == DSEKind::BuildGenKillSet; +} + +static inline bool isPerformingDSE(DSEKind Kind) { + return Kind == DSEKind::PerformDSE; } /// Returns true if this is an instruction that may have side effects in a @@ -115,6 +137,7 @@ static bool isDeadStoreInertInstruction(SILInstruction *Inst) { case ValueKind::CondFailInst: case ValueKind::IsUniqueInst: case ValueKind::IsUniqueOrPinnedInst: + case ValueKind::FixLifetimeInst: return true; default: return false; @@ -127,30 +150,50 @@ static bool isDeadStoreInertInstruction(SILInstruction *Inst) { namespace { +/// If this function has too many basic blocks or too many locations, it may +/// take a long time to compute the genset and killset. The number of memory +/// behavior or alias query we need to do in worst case is roughly linear to +/// # of BBs x(times) # of locations. +/// +/// we could run DSE on functions with 256 basic blocks and 256 locations, +/// which is a large function. +constexpr unsigned MaxLSLocationBBMultiplicationNone = 256*256; + +/// we could run optimistic DSE on functions with less than 64 basic blocks +/// and 64 locations which is a sizeable function. +constexpr unsigned MaxLSLocationBBMultiplicationPessimistic = 64*64; + /// If a large store is broken down to too many smaller stores, bail out. /// Currently, we only do partial dead store if we can form a single contiguous /// non-dead store. constexpr unsigned MaxPartialDeadStoreCountLimit = 1; +/// forward declaration. +class DSEContext; /// BlockState summarizes how LSLocations are used in a basic block. /// -/// Initially the WriteSetOut is empty. Before a basic block is processed, it is -/// initialized to the intersection of WriteSetIns of all successors of the +/// Initially the BBWriteSetOut is empty. Before a basic block is processed, it +/// is initialized to the intersection of BBWriteSetIns of all successors of the /// basic block. /// -/// Initially WriteSetIn is set to true. After the basic block is processed, if -/// its WriteSetOut is different from WriteSetIn, WriteSetIn is initialized to -/// the value of WriteSetOut and the data flow is rerun. +/// BBWriteSetMid is initialized to BBWriteSetOut of the current basic block +/// before instructions in the basic block is processed. +/// +/// Initially BBWriteSetIn is set to true. After the basic block is processed, +/// if its BBWriteSetMid is different from BBWriteSetIn, BBWriteSetIn is +/// assigned the value of BBWriteSetMid and the data flow is rerun on the +/// current basic block's predecessors. /// /// Instructions in each basic block are processed in post-order as follows: /// /// 1. When a store instruction is encountered, the stored location is tracked. /// /// 2. When a load instruction is encountered, remove the loaded location and -/// any location it may alias with from the WriteSetOut. +/// any location it may alias with from the BBWriteSetMid. /// -/// 3. When an instruction reads from memory in an unknown way, the WriteSetOut -/// bit is cleared if the instruction can read the corresponding LSLocation. +/// 3. When an instruction reads from memory in an unknown way, the +/// BBWriteSetMid bit is cleared if the instruction can read the +/// corresponding LSLocation. /// class BlockState { public: @@ -158,114 +201,94 @@ class BlockState { SILBasicBlock *BB; /// Keep the number of LSLocations in the LocationVault. - unsigned LSLocationNum; + unsigned LocationNum; /// A bit vector for which the ith bit represents the ith LSLocation in - /// LSLocationVault. If the bit is set, then the location currently has an - /// upward visible store. - llvm::BitVector WriteSetOut; + /// LocationVault. If the bit is set, then the location currently has an + /// upward visible store at the end of the basic block. + llvm::SmallBitVector BBWriteSetOut; - /// If WriteSetIn changes while processing a basicblock, then all its - /// predecessors needs to be rerun. - llvm::BitVector WriteSetIn; + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If the bit is set, then the location currently has an + /// upward visible store in middle of the basic block. + llvm::SmallBitVector BBWriteSetMid; + + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If a bit in the vector is set, then the location has an + /// upward visible store at the beginning of the basic block. + llvm::SmallBitVector BBWriteSetIn; /// A bit vector for which the ith bit represents the ith LSLocation in - /// LSLocationVault. If the bit is set, then the current basic block + /// LocationVault. If the bit is set, then the current basic block /// generates an upward visible store. - llvm::BitVector BBGenSet; + llvm::SmallBitVector BBGenSet; /// A bit vector for which the ith bit represents the ith LSLocation in - /// LSLocationVault. If the bit is set, then the current basic block + /// LocationVault. If the bit is set, then the current basic block /// kills an upward visible store. - llvm::BitVector BBKillSet; + llvm::SmallBitVector BBKillSet; + + /// A bit vector to keep the maximum number of stores that can reach a + /// certain point of the basic block. If a bit is set, that means there is + /// potentially an upward visible store to the location at the particular + /// point of the basic block. + llvm::SmallBitVector BBMaxStoreSet; + + /// If a bit in the vector is set, then the location is dead at the end of + /// this basic block. + llvm::SmallBitVector BBDeallocateLocation; /// The dead stores in the current basic block. llvm::DenseSet DeadStores; /// Keeps track of what stores to generate after the data flow stabilizes. /// these stores come from partial dead stores. + /// + /// The first SILValue keeps the address of the live store and the second + /// SILValue keeps the value of the store. llvm::DenseMap LiveStores; /// Constructors. - BlockState() : BB(nullptr) {} BlockState(SILBasicBlock *B) : BB(B) {} /// Return the current basic block. SILBasicBlock *getBB() const { return BB; } - void init(unsigned lcnt) { - LSLocationNum = lcnt; - // The initial state of WriteSetIn should be all 1's. Otherwise the - // dataflow solution could be too conservative. - // - // consider this case, the dead store by var a = 10 before the loop will not - // be eliminated if the WriteSetIn is set to 0 initially. - // - // var a = 10 - // for _ in 0...1024 {} - // a = 10 - // - // However, by doing so, we can only eliminate the dead stores after the - // data flow stablizes. - // - WriteSetIn.resize(LSLocationNum, true); - WriteSetOut.resize(LSLocationNum, false); - - // GenSet and KillSet initially empty. - BBGenSet.resize(LSLocationNum, false); - BBKillSet.resize(LSLocationNum, false); - } + /// Initialize the bitvectors for the current basic block. + void init(DSEContext &Ctx, bool PessimisticDF); - /// Check whether the WriteSetIn has changed. If it does, we need to rerun - /// the data flow to reach fixed point. - bool updateWriteSetIn(); + /// Check whether the BBWriteSetIn has changed. If it does, we need to rerun + /// the data flow on this block's predecessors to reach fixed point. + bool updateBBWriteSetIn(llvm::SmallBitVector &X); /// Functions to manipulate the write set. - void clearLSLocations(); - void startTrackingLSLocation(unsigned bit); - void stopTrackingLSLocation(unsigned bit); - bool isTrackingLSLocation(unsigned bit); - void initialize(const BlockState &L); - void intersect(const BlockState &L); + void startTrackingLocation(llvm::SmallBitVector &BV, unsigned bit); + void stopTrackingLocation(llvm::SmallBitVector &BV, unsigned bit); + bool isTrackingLocation(llvm::SmallBitVector &BV, unsigned bit); + + /// Set the store bit for stack slot deallocated in this basic block. + void initStoreSetAtEndOfBlock(DSEContext &Ctx); }; } // end anonymous namespace -bool BlockState::updateWriteSetIn() { - bool Changed = (WriteSetIn != WriteSetOut); - WriteSetIn = WriteSetOut; - return Changed; -} - -void BlockState::clearLSLocations() { WriteSetOut.reset(); } - -void BlockState::startTrackingLSLocation(unsigned bit) { WriteSetOut.set(bit); } - -void BlockState::stopTrackingLSLocation(unsigned bit) { - WriteSetOut.reset(bit); +bool BlockState::updateBBWriteSetIn(llvm::SmallBitVector &X) { + if (BBWriteSetIn == X) + return false; + BBWriteSetIn = X; + return true; } -bool BlockState::isTrackingLSLocation(unsigned bit) { - return WriteSetOut.test(bit); +void BlockState::startTrackingLocation(llvm::SmallBitVector &BV, unsigned i) { + BV.set(i); } -void BlockState::initialize(const BlockState &Succ) { - WriteSetOut = Succ.WriteSetIn; +void BlockState::stopTrackingLocation(llvm::SmallBitVector &BV, unsigned i) { + BV.reset(i); } -/// Intersect is very frequently performed, so it is important to make it as -/// cheap as possible. -/// -/// To do so, we canonicalize LSLocations, i.e. traced back to the underlying -/// object. Therefore, no need to do a O(N^2) comparison to figure out what is -/// dead along all successors. -/// -/// NOTE: Canonicalizing does not solve the problem entirely. i.e. it is still -/// possible that 2 LSLocations with different bases that happen to be the -/// same object and field. In such case, we would miss a dead store -/// opportunity. But this happens less often with canonicalization. -void BlockState::intersect(const BlockState &Succ) { - WriteSetOut &= Succ.WriteSetIn; +bool BlockState::isTrackingLocation(llvm::SmallBitVector &BV, unsigned i) { + return BV.test(i); } //===----------------------------------------------------------------------===// @@ -275,6 +298,12 @@ void BlockState::intersect(const BlockState &Succ) { namespace { class DSEContext { + enum class ProcessKind { + ProcessOptimistic = 0, + ProcessPessimistic = 1, + ProcessNone = 2, + }; +private: /// The module we are currently processing. SILModule *Mod; @@ -287,6 +316,9 @@ class DSEContext { /// Alias Analysis. AliasAnalysis *AA; + /// Escape Analysis. + EscapeAnalysis *EA; + /// Type Expansion Analysis. TypeExpansionAnalysis *TE; @@ -302,11 +334,25 @@ class DSEContext { /// Keeps all the locations for the current function. The BitVector in each /// BlockState is then laid on top of it to keep track of which LSLocation /// has an upward visible store. - std::vector LSLocationVault; + std::vector LocationVault; - /// Contains a map between location to their index in the LSLocationVault. + /// Keeps a list of basic blocks that have StoreInsts. If a basic block does + /// not have StoreInst, we do not actually perform the last iteration where + /// DSE is actually performed on the basic block. + /// + /// NOTE: This is never populated for functions which will only require 1 + /// data flow iteration. For function that requires more than 1 iteration of + /// the data flow this is populated when the first time the functions is + /// walked, i.e. when the we generate the genset and killset. + llvm::DenseSet BBWithStores; + + /// Contains a map between location to their index in the LocationVault. + /// used to facilitate fast location to index lookup. LSLocationIndexMap LocToBitIndex; + /// Keeps a map between the accessed SILValue and the location. + LSLocationBaseMap BaseToLocIndex; + /// Return the BlockState for the basic block this basic block belongs to. BlockState *getBlockState(SILBasicBlock *B) { return BBToLocState[B]; } @@ -315,50 +361,44 @@ class DSEContext { return getBlockState(I->getParent()); } - /// LSLocation read has been extracted, expanded and mapped to the bit - /// position in the bitvector. update the gen kill set using the bit - /// position. - void updateGenKillSetForRead(BlockState *S, unsigned bit); - /// LSLocation written has been extracted, expanded and mapped to the bit - /// position in the bitvector. update the gen kill set using the bit + /// position in the bitvector. update the max store set using the bit /// position. - void updateGenKillSetForWrite(BlockState *S, unsigned bit); - - /// LSLocation read has been extracted, expanded and mapped to the bit - /// position in the bitvector. process it using the bit position. - void updateWriteSetForRead(BlockState *S, unsigned Bit); - - /// LSLocation written has been extracted, expanded and mapped to the bit - /// position in the bitvector. process it using the bit position. - bool updateWriteSetForWrite(BlockState *S, unsigned Bit); + void processWriteForMaxStoreSet(BlockState *S, unsigned bit); /// There is a read to a location, expand the location into individual fields /// before processing them. - void processRead(SILInstruction *Inst, BlockState *State, SILValue Mem, - DSEComputeKind Kind); + void processRead(SILInstruction *Inst, BlockState *S, SILValue M, DSEKind K); + void processReadForGenKillSet(BlockState *S, unsigned bit); + void processReadForDSE(BlockState *S, unsigned Bit); /// There is a write to a location, expand the location into individual fields /// before processing them. - void processWrite(SILInstruction *Inst, BlockState *State, SILValue Val, - SILValue Mem, DSEComputeKind Kind); - - /// Process Instructions. Extract LSLocations from SIL LoadInst. - void processLoadInst(SILInstruction *Inst, DSEComputeKind Kind); - - /// Process Instructions. Extract LSLocations from SIL StoreInst. - void processStoreInst(SILInstruction *Inst, DSEComputeKind Kind); - - /// Process Instructions. Extract LSLocations from SIL DebugValueAddrInst. - /// DebugValueAddrInst operand maybe promoted to DebugValue, when this is - /// done, DebugValueAddrInst is effectively a read on the LSLocation. - void processDebugValueAddrInst(SILInstruction *I); - - /// Process Instructions. Extract LSLocations from SIL Unknown Memory Inst. - void processUnknownReadMemInst(SILInstruction *Inst, DSEComputeKind Kind); - - /// Check whether the instruction invalidate any LSLocations due to change in - /// its LSLocation Base. + void processWrite(SILInstruction *Inst, BlockState *S, SILValue V, SILValue M, + DSEKind K); + void processWriteForGenKillSet(BlockState *S, unsigned bit); + bool processWriteForDSE(BlockState *S, unsigned bit); + + /// Process instructions. Extract locations from SIL LoadInst. + void processLoadInst(SILInstruction *Inst, DSEKind Kind); + + /// Process instructions. Extract locations from SIL StoreInst. + void processStoreInst(SILInstruction *Inst, DSEKind Kind); + + /// Process instructions. Extract locations from SIL DebugValueAddrInst. + /// DebugValueAddrInst maybe promoted to DebugValue, when this is done, + /// DebugValueAddrInst is effectively a read on the location. + void processDebugValueAddrInst(SILInstruction *I, DSEKind Kind); + void processDebugValueAddrInstForGenKillSet(SILInstruction *I); + void processDebugValueAddrInstForDSE(SILInstruction *I); + + /// Process instructions. Extract locations from unknown memory inst. + void processUnknownReadInst(SILInstruction *Inst, DSEKind Kind); + void processUnknownReadInstForGenKillSet(SILInstruction *Inst); + void processUnknownReadInstForDSE(SILInstruction *Inst); + + /// Check whether the instruction invalidate any locations due to change in + /// its location Base. /// /// This is to handle a case like this. /// @@ -369,218 +409,356 @@ class DSEContext { /// } /// x.a = 12 /// - /// In this case, DSE can not remove the x.a = 13 inside the loop. + /// In this case, DSE cannot remove the x.a = 13 inside the loop. /// /// To do this, when the algorithm reaches the beginning of the basic block in - /// the loop it will need to invalidate the LSLocation in the WriteSetOut. - /// i.e. - /// the base of the LSLocation is changed. + /// the loop it will need to invalidate the location in the BBWriteSetMid. + /// i.e. the base of the location is changed. /// /// If not, on the second iteration, the intersection of the successors of /// the loop basic block will have store to x.a and therefore x.a = 13 can now /// be considered dead. - /// - void invalidateLSLocationBase(SILInstruction *Inst, DSEComputeKind Kind); + void invalidateLSLocationBase(SILInstruction *Inst, DSEKind Kind); + void invalidateLSLocationBaseForGenKillSet(SILInstruction *Inst); + void invalidateLSLocationBaseForDSE(SILInstruction *Inst); - /// Get the bit representing the location in the LSLocationVault. - /// - /// NOTE: Adds the location to the location vault if necessary. - unsigned getLSLocationBit(const LSLocation &L); + /// Get the bit representing the location in the LocationVault. + unsigned getLocationBit(const LSLocation &L); public: /// Constructor. DSEContext(SILFunction *F, SILModule *M, SILPassManager *PM, - AliasAnalysis *AA, TypeExpansionAnalysis *TE) - : Mod(M), F(F), PM(PM), AA(AA), TE(TE) {} + AliasAnalysis *AA, EscapeAnalysis *EA, TypeExpansionAnalysis *TE) + : Mod(M), F(F), PM(PM), AA(AA), EA(EA), TE(TE) {} + + /// Entry point for dead store elimination. + bool run(); + + /// Run the iterative DF to converge the BBWriteSetIn. + void runIterativeDSE(); + + /// Returns the escape analysis we use. + EscapeAnalysis *getEA() { return EA; } + + /// Returns the function currently being processing. + SILFunction *getFn() { return F; } + + /// Returns the location vault of the current function. + std::vector &getLocationVault() { return LocationVault; } + + /// Use a set of ad hoc rules to tell whether we should run a pessimistic + /// one iteration data flow on the function. + ProcessKind getProcessFunctionKind(); /// Compute the kill set for the basic block. return true if the store set /// changes. - bool processBasicBlock(SILBasicBlock *BB); + void processBasicBlockForDSE(SILBasicBlock *BB, bool PessimisticDF); /// Compute the genset and killset for the current basic block. void processBasicBlockForGenKillSet(SILBasicBlock *BB); - /// Compute the WriteSetOut and WriteSetIn for the current basic + /// Compute the BBWriteSetOut and BBWriteSetIn for the current basic /// block with the generated gen and kill set. bool processBasicBlockWithGenKillSet(SILBasicBlock *BB); - /// Intersect the successor live-ins. - void mergeSuccessorStates(SILBasicBlock *BB); + /// Intersect the successors' BBWriteSetIns. + void mergeSuccessorLiveIns(SILBasicBlock *BB); /// Update the BlockState based on the given instruction. - void processInstruction(SILInstruction *I, DSEComputeKind Kind); - - /// Entry point for global dead store elimination. - bool run(); + void processInstruction(SILInstruction *I, DSEKind Kind); }; } // end anonymous namespace -unsigned DSEContext::getLSLocationBit(const LSLocation &Loc) { - // Return the bit position of the given Loc in the LSLocationVault. The bit +void BlockState::init(DSEContext &Ctx, bool PessimisticDF) { + std::vector &LV = Ctx.getLocationVault(); + LocationNum = LV.size(); + // For function that requires just 1 iteration of the data flow to converge + // we set the initial state of BBWriteSetIn to 0. + // + // For other functions, the initial state of BBWriteSetIn should be all 1's. + // Otherwise the dataflow solution could be too conservative. + // + // Consider this case, the dead store by var a = 10 before the loop will not + // be eliminated if the BBWriteSetIn is set to 0 initially. + // + // var a = 10 + // for _ in 0...1024 {} + // a = 10 + // + // However, by doing so, we can only eliminate the dead stores after the + // data flow stabilizes. + // + BBWriteSetIn.resize(LocationNum, !PessimisticDF); + BBWriteSetOut.resize(LocationNum, false); + BBWriteSetMid.resize(LocationNum, false); + + // GenSet and KillSet initially empty. + BBGenSet.resize(LocationNum, false); + BBKillSet.resize(LocationNum, false); + + // MaxStoreSet is optimistically set to true initially. + BBMaxStoreSet.resize(LocationNum, true); + + + // DeallocateLocation initially empty. + BBDeallocateLocation.resize(LocationNum, false); +} + +unsigned DSEContext::getLocationBit(const LSLocation &Loc) { + // Return the bit position of the given Loc in the LocationVault. The bit // position is then used to set/reset the bitvector kept by each BlockState. // // We should have the location populated by the enumerateLSLocation at this // point. - // auto Iter = LocToBitIndex.find(Loc); - assert(Iter != LocToBitIndex.end() && - "LSLocation should have been enumerated"); + assert(Iter != LocToBitIndex.end() && "LSLocation should have been enum'ed"); return Iter->second; } +DSEContext::ProcessKind DSEContext::getProcessFunctionKind() { + bool RunOneIteration = true; + unsigned BBCount = 0; + unsigned LocationCount = LocationVault.size(); + + // If all basic blocks will have their successors processed if + // the basic blocks in the functions are iterated in post order. + // Then this function can be processed in one iteration, i.e. no + // need to generate the genset and killset. + auto *PO = PM->getAnalysis()->get(F); + llvm::DenseSet HandledBBs; + for (SILBasicBlock *B : PO->getPostOrder()) { + ++BBCount; + for (auto &X : B->getSuccessors()) { + if (HandledBBs.find(X) == HandledBBs.end()) { + RunOneIteration = false; + break; + } + } + HandledBBs.insert(B); + } + + // Data flow may take too long to run. + if (BBCount * LocationCount > MaxLSLocationBBMultiplicationNone) + return ProcessKind::ProcessNone; + + // This function's data flow would converge in 1 iteration. + if (RunOneIteration) + return ProcessKind::ProcessPessimistic; + + // We run one pessimistic data flow to do dead store elimination on + // the function. + if (BBCount * LocationCount > MaxLSLocationBBMultiplicationPessimistic) + return ProcessKind::ProcessPessimistic; + + return ProcessKind::ProcessOptimistic; +} + void DSEContext::processBasicBlockForGenKillSet(SILBasicBlock *BB) { + // Compute the MaxStoreSet at the end of the basic block. + auto *BBState = getBlockState(BB); + if (BB->succ_empty()) { + BBState->BBMaxStoreSet |= BBState->BBDeallocateLocation; + } else { + auto Iter = BB->succ_begin(); + BBState->BBMaxStoreSet = getBlockState(*Iter)->BBMaxStoreSet; + Iter = std::next(Iter); + for (auto EndIter = BB->succ_end(); Iter != EndIter; ++Iter) { + BBState->BBMaxStoreSet &= getBlockState(*Iter)->BBMaxStoreSet; + } + } + + // Compute the genset and killset. + // + // Also compute the MaxStoreSet at the current position of the basic block. + // + // This helps generating the genset and killset. If there is no way a + // location can have an upward visible store at a particular point in the + // basic block, we do not need to turn on the genset and killset for the + // location. + // + // Turning on the genset and killset can be costly as it involves querying + // the AA interface. for (auto I = BB->rbegin(), E = BB->rend(); I != E; ++I) { - processInstruction(&(*I), DSEComputeKind::BuildGenKillSet); + // Only process store insts. + if (isa(*I)) { + if (BBWithStores.find(BB) == BBWithStores.end()) + BBWithStores.insert(BB); + processStoreInst(&(*I), DSEKind::ComputeMaxStoreSet); + } + + // Compute the genset and killset for this instruction. + processInstruction(&(*I), DSEKind::BuildGenKillSet); } } bool DSEContext::processBasicBlockWithGenKillSet(SILBasicBlock *BB) { - // Compute the WriteSetOut at the end of the basic block. - mergeSuccessorStates(BB); + // Compute the BBWriteSetOut at the end of the basic block. + mergeSuccessorLiveIns(BB); - // Compute the WriteSetOut at the beginning of the basic block. + // Compute the BBWriteSet at the beginning of the basic block. BlockState *S = getBlockState(BB); - llvm::BitVector T = S->BBKillSet; - S->WriteSetOut &= T.flip(); - S->WriteSetOut |= S->BBGenSet; - - // If WriteSetIn changes, then keep iterating until reached a fixed - // point. - return S->updateWriteSetIn(); + S->BBWriteSetMid = S->BBWriteSetOut; + S->BBWriteSetMid.reset(S->BBKillSet); + S->BBWriteSetMid |= S->BBGenSet; + + // If BBWriteSetIn changes, then keep iterating until reached a fixed point. + return S->updateBBWriteSetIn(S->BBWriteSetMid); } -bool DSEContext::processBasicBlock(SILBasicBlock *BB) { - // Intersect in the successor live-ins. A store is dead if it is not read from - // any path to the end of the program. Thus an intersection. - mergeSuccessorStates(BB); +void DSEContext::processBasicBlockForDSE(SILBasicBlock *BB, + bool PessimisticDF) { + // If we know this is not a one iteration function which means its + // its BBWriteSetIn and BBWriteSetOut have been computed and converged, + // and this basic block does not even have StoreInsts, there is no point + // in processing every instruction in the basic block again as no store + // will be eliminated. + if (!PessimisticDF && BBWithStores.find(BB) == BBWithStores.end()) + return; + + // Intersect in the successor WriteSetIns. A store is dead if it is not read + // from any path to the end of the program. Thus an intersection. + mergeSuccessorLiveIns(BB); + + // Initialize the BBWriteSetMid to BBWriteSetOut to get started. + BlockState *S = getBlockState(BB); + S->BBWriteSetMid = S->BBWriteSetOut; // Process instructions in post-order fashion. for (auto I = BB->rbegin(), E = BB->rend(); I != E; ++I) { - processInstruction(&(*I), DSEComputeKind::PerformDSE); + processInstruction(&(*I), DSEKind::PerformDSE); } - // If WriteSetIn changes, then keep iterating until reached a fixed - // point. - return getBlockState(BB)->updateWriteSetIn(); + S->BBWriteSetIn = S->BBWriteSetMid; } -void DSEContext::mergeSuccessorStates(SILBasicBlock *BB) { - // First, clear the WriteSetOut for the current basicblock. - BlockState *C = getBlockState(BB); - C->clearLSLocations(); +void BlockState::initStoreSetAtEndOfBlock(DSEContext &Ctx) { + std::vector &LocationVault = Ctx.getLocationVault(); + // We set the store bit at the end of the basic block in which a stack + // allocated location is deallocated. + for (unsigned i = 0; i < LocationVault.size(); ++i) { + // Turn on the store bit at the block which the stack slot is deallocated. + if (auto *ASI = dyn_cast(LocationVault[i].getBase())) { + for (auto X : findDeallocStackInst(ASI)) { + SILBasicBlock *DSIBB = X->getParent(); + if (DSIBB != BB) + continue; + startTrackingLocation(BBDeallocateLocation, i); + } + } + } +} +void DSEContext::mergeSuccessorLiveIns(SILBasicBlock *BB) { // If basic block has no successor, then all local writes can be considered // dead for block with no successor. + BlockState *C = getBlockState(BB); if (BB->succ_empty()) { - if (DisableLocalStoreDSE) - return; - for (unsigned i = 0; i < LSLocationVault.size(); ++i) { - if (!LSLocationVault[i].isNonEscapingLocalLSLocation()) - continue; - C->startTrackingLSLocation(i); - } + C->BBWriteSetOut |= C->BBDeallocateLocation; return; } // Use the first successor as the base condition. auto Iter = BB->succ_begin(); - C->initialize(*getBlockState(*Iter)); + C->BBWriteSetOut = getBlockState(*Iter)->BBWriteSetIn; + + /// Merge/intersection is very frequently performed, so it is important to make + /// it as cheap as possible. + /// + /// To do so, we canonicalize LSLocations, i.e. traced back to the underlying + /// object. Therefore, no need to do a O(N^2) comparison to figure out what is + /// dead along all successors. + /// + /// NOTE: Canonicalization does not solve the problem entirely. i.e. it is + /// still possible that 2 LSLocations with different bases that happen to be + /// the same object and field. In such case, we would miss a dead store + /// opportunity. But this happens less often with canonicalization. Iter = std::next(Iter); for (auto EndIter = BB->succ_end(); Iter != EndIter; ++Iter) { - C->intersect(*getBlockState(*Iter)); + C->BBWriteSetOut &= getBlockState(*Iter)->BBWriteSetIn; + } + + // We set the store bit at the end of the basic block in which a stack + // allocated location is deallocated. + C->BBWriteSetOut |= C->BBDeallocateLocation; +} + +void DSEContext::invalidateLSLocationBaseForGenKillSet(SILInstruction *I) { + BlockState *S = getBlockState(I); + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (LocationVault[i].getBase() != I) + continue; + S->startTrackingLocation(S->BBKillSet, i); + S->stopTrackingLocation(S->BBGenSet, i); } } -void DSEContext::invalidateLSLocationBase(SILInstruction *I, - DSEComputeKind Kind) { +void DSEContext::invalidateLSLocationBaseForDSE(SILInstruction *I) { + BlockState *S = getBlockState(I); + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->BBWriteSetMid.test(i)) + continue; + if (LocationVault[i].getBase() != I) + continue; + S->stopTrackingLocation(S->BBWriteSetMid, i); + } +} + +void DSEContext::invalidateLSLocationBase(SILInstruction *I, DSEKind Kind) { // If this instruction defines the base of a location, then we need to // invalidate any locations with the same base. - BlockState *S = getBlockState(I); + // + // Are we building genset and killset. if (isBuildingGenKillSet(Kind)) { - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (LSLocationVault[i].getBase().getDef() != I) - continue; - S->BBGenSet.reset(i); - S->BBKillSet.set(i); - } + invalidateLSLocationBaseForGenKillSet(I); return; } - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (!S->WriteSetOut.test(i)) - continue; - if (LSLocationVault[i].getBase().getDef() != I) - continue; - S->stopTrackingLSLocation(i); + // Are we performing dead store elimination. + if (isPerformingDSE(Kind)) { + invalidateLSLocationBaseForDSE(I); + return; } + + llvm_unreachable("Unknown DSE compute kind"); } -void DSEContext::updateWriteSetForRead(BlockState *S, unsigned bit) { +void DSEContext::processReadForDSE(BlockState *S, unsigned bit) { // Remove any may/must-aliasing stores to the LSLocation, as they cant be // used to kill any upward visible stores due to the interfering load. - LSLocation &R = LSLocationVault[bit]; - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (!S->isTrackingLSLocation(i)) + LSLocation &R = LocationVault[bit]; + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->isTrackingLocation(S->BBWriteSetMid, i)) continue; - LSLocation &L = LSLocationVault[i]; + LSLocation &L = LocationVault[i]; if (!L.isMayAliasLSLocation(R, AA)) continue; - DEBUG(llvm::dbgs() << "Loc Removal: " << LSLocationVault[i].getBase() - << "\n"); - S->stopTrackingLSLocation(i); + S->stopTrackingLocation(S->BBWriteSetMid, i); } } -void DSEContext::updateGenKillSetForRead(BlockState *S, unsigned bit) { +void DSEContext::processReadForGenKillSet(BlockState *S, unsigned bit) { // Start tracking the read to this LSLocation in the killset and update // the genset accordingly. // // Even though, LSLocations are canonicalized, we still need to consult // alias analysis to determine whether 2 LSLocations are disjointed. - LSLocation &R = LSLocationVault[bit]; - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - LSLocation &L = LSLocationVault[i]; - if (!L.isMayAliasLSLocation(R, AA)) + LSLocation &R = LocationVault[bit]; + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->BBMaxStoreSet.test(i)) continue; - S->BBGenSet.reset(i); - // Update the kill set, we need to be conservative about kill set. Kill set - // kills any LSLocation that this currently LSLocation mayalias. - S->BBKillSet.set(i); - } -} - -bool DSEContext::updateWriteSetForWrite(BlockState *S, unsigned bit) { - // If a tracked store must aliases with this store, then this store is dead. - bool IsDead = false; - LSLocation &R = LSLocationVault[bit]; - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (!S->isTrackingLSLocation(i)) - continue; - // If 2 locations may alias, we can still keep both stores. - LSLocation &L = LSLocationVault[i]; - if (!L.isMustAliasLSLocation(R, AA)) + // Do nothing if the read location NoAlias with the current location. + LSLocation &L = LocationVault[i]; + if (!L.isMayAliasLSLocation(R, AA)) continue; - IsDead = true; - // No need to check the rest of the upward visible stores as this store - // is dead. - break; + // Update the genset and kill set. + S->startTrackingLocation(S->BBKillSet, i); + S->stopTrackingLocation(S->BBGenSet, i); } - - // Track this new store. - DEBUG(llvm::dbgs() << "Loc Insertion: " << LSLocationVault[bit].getBase() - << "\n"); - S->startTrackingLSLocation(bit); - return IsDead; -} - -void DSEContext::updateGenKillSetForWrite(BlockState *S, unsigned bit) { - // Start tracking the store to this MemLoation. - S->BBGenSet.set(bit); } void DSEContext::processRead(SILInstruction *I, BlockState *S, SILValue Mem, - DSEComputeKind Kind) { + DSEKind Kind) { // Construct a LSLocation to represent the memory read by this instruction. // NOTE: The base will point to the actual object this inst is accessing, // not this particular field. @@ -594,44 +772,78 @@ void DSEContext::processRead(SILInstruction *I, BlockState *S, SILValue Mem, // // This will make comparison between locations easier. This eases the // implementation of intersection operator in the data flow. - LSLocation L(Mem); + LSLocation L; + if (BaseToLocIndex.find(Mem) != BaseToLocIndex.end()) { + L = BaseToLocIndex[Mem]; + } else { + SILValue UO = getUnderlyingObject(Mem); + L = LSLocation(UO, NewProjectionPath::getProjectionPath(UO, Mem)); + } // If we cant figure out the Base or Projection Path for the read instruction, // process it as an unknown memory instruction for now. if (!L.isValid()) { - processUnknownReadMemInst(I, Kind); + processUnknownReadInst(I, Kind); return; } -#ifndef NDEBUG - // Make sure that the LSLocation getType() returns the same type as the - // loaded type. - if (auto *LI = dyn_cast(I)) { - assert(LI->getOperand().getType().getObjectType() == L.getType() && - "LSLocation returns different type"); - } -#endif - - // Expand the given Mem into individual fields and process them as - // separate reads. + // Expand the given Mem into individual fields and process them as separate + // reads. LSLocationList Locs; LSLocation::expand(L, &I->getModule(), Locs, TE); + + // Are we building the genset and killset. if (isBuildingGenKillSet(Kind)) { for (auto &E : Locs) { // Only building the gen and kill sets for now. - updateGenKillSetForRead(S, getLSLocationBit(E)); + processReadForGenKillSet(S, getLocationBit(E)); } - } else { + return; + } + + // Are we performing the actual DSE. + if (isPerformingDSE(Kind)) { for (auto &E : Locs) { - // This is the last iteration, compute WriteSetOut and perform the dead - // store elimination. - updateWriteSetForRead(S, getLSLocationBit(E)); + // This is the last iteration, compute BBWriteSetOut and perform DSE. + processReadForDSE(S, getLocationBit(E)); } + return; + } + + llvm_unreachable("Unknown DSE compute kind"); +} + +bool DSEContext::processWriteForDSE(BlockState *S, unsigned bit) { + // If a tracked store must aliases with this store, then this store is dead. + bool StoreDead = false; + LSLocation &R = LocationVault[bit]; + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->isTrackingLocation(S->BBWriteSetMid, i)) + continue; + // If 2 locations may alias, we can still keep both stores. + LSLocation &L = LocationVault[i]; + if (!L.isMustAliasLSLocation(R, AA)) + continue; + // There is a must alias store. No need to check further. + StoreDead = true; + break; } + + // Track this new store. + S->startTrackingLocation(S->BBWriteSetMid, bit); + return StoreDead; +} + +void DSEContext::processWriteForGenKillSet(BlockState *S, unsigned bit) { + S->startTrackingLocation(S->BBGenSet, bit); +} + +void DSEContext::processWriteForMaxStoreSet(BlockState *S, unsigned bit) { + S->startTrackingLocation(S->BBMaxStoreSet, bit); } void DSEContext::processWrite(SILInstruction *I, BlockState *S, SILValue Val, - SILValue Mem, DSEComputeKind Kind) { + SILValue Mem, DSEKind Kind) { // Construct a LSLocation to represent the memory read by this instruction. // NOTE: The base will point to the actual object this inst is accessing, // not this particular field. @@ -645,49 +857,56 @@ void DSEContext::processWrite(SILInstruction *I, BlockState *S, SILValue Val, // // This will make comparison between locations easier. This eases the // implementation of intersection operator in the data flow. - LSLocation L(Mem); + LSLocation L; + if (BaseToLocIndex.find(Mem) != BaseToLocIndex.end()) { + L = BaseToLocIndex[Mem]; + } else { + SILValue UO = getUnderlyingObject(Mem); + L = LSLocation(UO, NewProjectionPath::getProjectionPath(UO, Mem)); + } // If we cant figure out the Base or Projection Path for the store - // instruction, - // simply ignore it for now. + // instruction, simply ignore it. if (!L.isValid()) return; -#ifndef NDEBUG - // Make sure that the LSLocation getType() returns the same type as the - // stored type. - if (auto *SI = dyn_cast(I)) { - assert(SI->getDest().getType().getObjectType() == L.getType() && - "LSLocation returns different type"); - } -#endif - // Expand the given Mem into individual fields and process them as separate // writes. bool Dead = true; LSLocationList Locs; LSLocation::expand(L, Mod, Locs, TE); - llvm::BitVector V(Locs.size()); - if (isBuildingGenKillSet(Kind)) { + llvm::SmallBitVector V(Locs.size()); + + // Are we computing max store set. + if (isComputeMaxStoreSet(Kind)) { for (auto &E : Locs) { - // Only building the gen and kill sets here. - updateGenKillSetForWrite(S, getLSLocationBit(E)); + // Update the max store set for the basic block. + processWriteForMaxStoreSet(S, getLocationBit(E)); } - } else { - unsigned idx = 0; + return; + } + + // Are we computing genset and killset. + if (isBuildingGenKillSet(Kind)) { for (auto &E : Locs) { - // This is the last iteration, compute WriteSetOut and perform the dead - // store elimination. - if (updateWriteSetForWrite(S, getLSLocationBit(E))) - V.set(idx); - Dead &= V.test(idx); - ++idx; + // Only building the gen and kill sets here. + processWriteForGenKillSet(S, getLocationBit(E)); } + // Data flow has not stabilized, do not perform the DSE just yet. + return; } - // Data flow has not stablized, do not perform the DSE just yet. - if (isBuildingGenKillSet(Kind)) - return; + // We are doing the actual DSE. + assert(isPerformingDSE(Kind) && "Invalid computation kind"); + unsigned idx = 0; + for (auto &E : Locs) { + // This is the last iteration, compute BBWriteSetOut and perform the dead + // store elimination. + if (processWriteForDSE(S, getLocationBit(E))) + V.set(idx); + Dead &= V.test(idx); + ++idx; + } // Fully dead store - stores to all the components are dead, therefore this // instruction is dead. @@ -724,14 +943,14 @@ void DSEContext::processWrite(SILInstruction *I, BlockState *S, SILValue Val, // particular instruction may not be accessing the base, so we need to // *rebase* the locations w.r.t. to the current instruction. SILValue B = Locs[0].getBase(); - Optional BP = ProjectionPath::getAddrProjectionPath(B, Mem); + Optional BP = NewProjectionPath::getProjectionPath(B, Mem); // Strip off the projection path from base to the accessed field. for (auto &X : Alives) { - X.subtractPaths(BP); + X.removePathPrefix(BP); } - // We merely setup the remain live stores, but do not materialize in IR yet, - // These stores will be materialized when before the algorithm exits. + // We merely setup the remaining live stores, but do not materialize in IR + // yet, These stores will be materialized before the algorithm exits. for (auto &X : Alives) { SILValue Value = SILValueProjection::createExtract(Val, X.getPath(), I, true); @@ -747,95 +966,183 @@ void DSEContext::processWrite(SILInstruction *I, BlockState *S, SILValue Val, } } -void DSEContext::processLoadInst(SILInstruction *I, DSEComputeKind Kind) { - SILValue Mem = cast(I)->getOperand(); - processRead(I, getBlockState(I), Mem, Kind); +void DSEContext::processLoadInst(SILInstruction *I, DSEKind Kind) { + processRead(I, getBlockState(I), cast(I)->getOperand(), Kind); } -void DSEContext::processStoreInst(SILInstruction *I, DSEComputeKind Kind) { - SILValue Val = cast(I)->getSrc(); - SILValue Mem = cast(I)->getDest(); - processWrite(I, getBlockState(I), Val, Mem, Kind); +void DSEContext::processStoreInst(SILInstruction *I, DSEKind Kind) { + auto *SI = cast(I); + processWrite(I, getBlockState(I), SI->getSrc(), SI->getDest(), Kind); } -void DSEContext::processDebugValueAddrInst(SILInstruction *I) { +void DSEContext::processDebugValueAddrInstForGenKillSet(SILInstruction *I) { BlockState *S = getBlockState(I); SILValue Mem = cast(I)->getOperand(); - for (unsigned i = 0; i < S->WriteSetOut.size(); ++i) { - if (!S->isTrackingLSLocation(i)) + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->BBMaxStoreSet.test(i)) continue; - if (AA->isNoAlias(Mem, LSLocationVault[i].getBase())) + if (AA->isNoAlias(Mem, LocationVault[i].getBase())) continue; - getBlockState(I)->stopTrackingLSLocation(i); + S->stopTrackingLocation(S->BBGenSet, i); + S->startTrackingLocation(S->BBKillSet, i); } } -void DSEContext::processUnknownReadMemInst(SILInstruction *I, - DSEComputeKind Kind) { +void DSEContext::processDebugValueAddrInstForDSE(SILInstruction *I) { BlockState *S = getBlockState(I); - // Update the gen kill set. + SILValue Mem = cast(I)->getOperand(); + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->isTrackingLocation(S->BBWriteSetMid, i)) + continue; + if (AA->isNoAlias(Mem, LocationVault[i].getBase())) + continue; + S->stopTrackingLocation(S->BBWriteSetMid, i); + } +} + +void DSEContext::processDebugValueAddrInst(SILInstruction *I, DSEKind Kind) { + // Are we building genset and killset. if (isBuildingGenKillSet(Kind)) { - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (!AA->mayReadFromMemory(I, LSLocationVault[i].getBase())) - continue; - S->BBKillSet.set(i); - S->BBGenSet.reset(i); - } + processDebugValueAddrInstForGenKillSet(I); + return; + } + + // Are we performing dead store elimination. + if (isPerformingDSE(Kind)) { + processDebugValueAddrInstForDSE(I); return; } - // We do not know what this instruction does or the memory that it *may* - // touch. Hand it to alias analysis to see whether we need to invalidate - // any LSLocation. - for (unsigned i = 0; i < S->LSLocationNum; ++i) { - if (!S->isTrackingLSLocation(i)) + llvm_unreachable("Unknown DSE compute kind"); +} + +void DSEContext::processUnknownReadInstForGenKillSet(SILInstruction *I) { + BlockState *S = getBlockState(I); + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->BBMaxStoreSet.test(i)) + continue; + if (!AA->mayReadFromMemory(I, LocationVault[i].getBase())) + continue; + // Update the genset and kill set. + S->startTrackingLocation(S->BBKillSet, i); + S->stopTrackingLocation(S->BBGenSet, i); + } +} + +void DSEContext::processUnknownReadInstForDSE(SILInstruction *I) { + BlockState *S = getBlockState(I); + for (unsigned i = 0; i < S->LocationNum; ++i) { + if (!S->isTrackingLocation(S->BBWriteSetMid, i)) continue; - if (!AA->mayReadFromMemory(I, LSLocationVault[i].getBase())) + if (!AA->mayReadFromMemory(I, LocationVault[i].getBase())) continue; - getBlockState(I)->stopTrackingLSLocation(i); + S->stopTrackingLocation(S->BBWriteSetMid, i); } } -void DSEContext::processInstruction(SILInstruction *I, DSEComputeKind Kind) { +void DSEContext::processUnknownReadInst(SILInstruction *I, DSEKind Kind) { + // Are we building genset and killset. + if (isBuildingGenKillSet(Kind)) { + processUnknownReadInstForGenKillSet(I); + return; + } + + // Are we performing dead store elimination. + if (isPerformingDSE(Kind)) { + processUnknownReadInstForDSE(I); + return; + } + + llvm_unreachable("Unknown DSE compute kind"); +} + +void DSEContext::processInstruction(SILInstruction *I, DSEKind Kind) { // If this instruction has side effects, but is inert from a store // perspective, skip it. if (isDeadStoreInertInstruction(I)) return; // A set of ad-hoc rules to process instructions. - // - // TODO: process more instructions. - // if (isa(I)) { processLoadInst(I, Kind); } else if (isa(I)) { processStoreInst(I, Kind); } else if (isa(I)) { - processDebugValueAddrInst(I); + processDebugValueAddrInst(I, Kind); } else if (I->mayReadFromMemory()) { - processUnknownReadMemInst(I, Kind); - } + processUnknownReadInst(I, Kind); + } - // Check whether this instruction will invalidate any other LSLocations. + // Check whether this instruction will invalidate any other locations. invalidateLSLocationBase(I, Kind); } +void DSEContext::runIterativeDSE() { + // Generate the genset and killset for each basic block. We can process the + // basic blocks in any order. + // + // We also Compute the max store set at the beginning of the basic block. + // + auto *PO = PM->getAnalysis()->get(F); + for (SILBasicBlock *B : PO->getPostOrder()) { + processBasicBlockForGenKillSet(B); + } + + // Process each basic block with the gen and kill set. Every time the + // BBWriteSetIn of a basic block changes, the optimization is rerun on its + // predecessors. + llvm::SmallVector WorkList; + llvm::DenseSet HandledBBs; + // Push into reverse post order so that we can pop from the back and get + // post order. + for (SILBasicBlock *B : PO->getReversePostOrder()) { + WorkList.push_back(B); + HandledBBs.insert(B); + } + while (!WorkList.empty()) { + SILBasicBlock *BB = WorkList.pop_back_val(); + HandledBBs.erase(BB); + if (processBasicBlockWithGenKillSet(BB)) { + for (auto X : BB->getPreds()) { + // We do not push basic block into the worklist if its already + // in the worklist. + if (HandledBBs.find(X) != HandledBBs.end()) + continue; + WorkList.push_back(X); + } + } + } +} + bool DSEContext::run() { + // Is this a one iteration function. + auto *PO = PM->getAnalysis()->get(F); + // Walk over the function and find all the locations accessed by // this function. - LSLocation::enumerateLSLocations(*F, LSLocationVault, LocToBitIndex, TE); + LSLocation::enumerateLSLocations(*F, LocationVault, LocToBitIndex, + BaseToLocIndex, TE); + + // Check how to optimize this function. + ProcessKind Kind = getProcessFunctionKind(); + + // We do not optimize this function at all. + if (Kind == ProcessKind::ProcessNone) + return false; - // For all basic blocks in the function, initialize a BB state. Since we - // know all the locations accessed in this function, we can resize the bit - // vector to the appropriate size. + // Do we run a pessimistic data flow ? + bool PessimisticDF = Kind == ProcessKind::ProcessOptimistic ? false : true; + + // For all basic blocks in the function, initialize a BB state. // // DenseMap has a minimum size of 64, while many functions do not have more // than 64 basic blocks. Therefore, allocate the BlockState in a vector and - // use - // pointer in BBToLocState to access them. + // use pointer in BBToLocState to access them. for (auto &B : *F) { BlockStates.push_back(BlockState(&B)); - BlockStates.back().init(LSLocationVault.size()); + // Since we know all the locations accessed in this function, we can resize + // the bit vector to the appropriate size. + BlockStates.back().init(*this, PessimisticDF); } // Initialize the BBToLocState mapping. @@ -843,32 +1150,37 @@ bool DSEContext::run() { BBToLocState[S.getBB()] = &S; } - // Generate the genset and killset for each basic block. - for (auto &B : *F) { - processBasicBlockForGenKillSet(&B); + // Initialize the store bit state at the end of each basic block. + for (auto &X : BlockStates) { + X.initStoreSetAtEndOfBlock(*this); } - // Process each basic block with the gen and kill set. Every time the - // WriteSetIn of a basic block changes, the optimization is rerun on its - // predecessors. - auto *PO = PM->getAnalysis()->get(F); - llvm::SmallVector WorkList; - for (SILBasicBlock *B : PO->getPostOrder()) { - WorkList.push_back(B); - } + // We perform dead store elimination in the following phases. + // + // Phase 1. we compute the max store set at the beginning of the basic block. + // + // Phase 2. we compute the genset and killset for every basic block. + // + // Phase 3. we run the data flow with the genset and killset until + // BBWriteSetIns stop changing. + // + // Phase 4. we run the data flow for the last iteration and perform the DSE. + // + // Phase 5. we remove the dead stores. + // + // Phase 1 - 3 are only performed when we know the data flow will not + // converge in a single iteration. Otherwise, we only run phase 4 and 5 + // on the function. - while (!WorkList.empty()) { - SILBasicBlock *BB = WorkList.pop_back_val(); - if (processBasicBlockWithGenKillSet(BB)) { - for (auto X : BB->getPreds()) - WorkList.push_back(X); - } + // We need to run the iterative data flow on the function. + if (!PessimisticDF) { + runIterativeDSE(); } - // The data flow has stablized, run one last iteration over all the basic + // The data flow has stabilized, run one last iteration over all the basic // blocks and try to remove dead stores. - for (SILBasicBlock &BB : *F) { - processBasicBlock(&BB); + for (SILBasicBlock *B : PO->getPostOrder()) { + processBasicBlockForDSE(B, PessimisticDF); } // Finally, delete the dead stores and create the live stores. @@ -876,9 +1188,11 @@ bool DSEContext::run() { for (SILBasicBlock &BB : *F) { // Create the stores that are alive due to partial dead stores. for (auto &I : getBlockState(&BB)->LiveStores) { - SILInstruction *IT = cast(I.first)->getNextNode(); + Changed = true; + SILInstruction *Inst = cast(I.first); + auto *IT = &*std::next(Inst->getIterator()); SILBuilderWithScope Builder(IT); - Builder.createStore(I.first.getLoc().getValue(), I.second, I.first); + Builder.createStore(Inst->getLoc(), I.second, Inst); } // Delete the dead stores. for (auto &I : getBlockState(&BB)->DeadStores) { @@ -888,6 +1202,7 @@ bool DSEContext::run() { recursivelyDeleteTriviallyDeadInstructions(I, true); } } + return Changed; } @@ -904,11 +1219,12 @@ class DeadStoreElimination : public SILFunctionTransform { /// The entry point to the transformation. void run() override { auto *AA = PM->getAnalysis(); + auto *EA = PM->getAnalysis(); auto *TE = PM->getAnalysis(); SILFunction *F = getFunction(); DEBUG(llvm::dbgs() << "*** DSE on function: " << F->getName() << " ***\n"); - DSEContext DSE(F, &F->getModule(), PM, AA, TE); + DSEContext DSE(F, &F->getModule(), PM, AA, EA, TE); if (DSE.run()) { invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); } diff --git a/lib/SILOptimizer/Transforms/Devirtualizer.cpp b/lib/SILOptimizer/Transforms/Devirtualizer.cpp new file mode 100644 index 0000000000000..5dd965d0e9e98 --- /dev/null +++ b/lib/SILOptimizer/Transforms/Devirtualizer.cpp @@ -0,0 +1,99 @@ +//===--- Devirtualizer.cpp - Devirtualize indirect calls -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Devirtualize indirect calls to functions, turning them into direct function +// references. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-devirtualizer" + +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" +#include "swift/SILOptimizer/Utils/Devirtualize.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/ADT/SmallVector.h" + +using namespace swift; + +namespace { + +class Devirtualizer : public SILFunctionTransform { + + bool devirtualizeAppliesInFunction(SILFunction &F, + ClassHierarchyAnalysis *CHA); + + /// The entry point to the transformation. + void run() override { + SILFunction &F = *getFunction(); + ClassHierarchyAnalysis *CHA = PM->getAnalysis(); + DEBUG(llvm::dbgs() << "***** Devirtualizer on function:" << F.getName() + << " *****\n"); + + if (devirtualizeAppliesInFunction(F, CHA)) + invalidateAnalysis(SILAnalysis::InvalidationKind::CallsAndInstructions); + } + + StringRef getName() override { return "Devirtualizer"; } +}; + +} // end anonymous namespace + +bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F, + ClassHierarchyAnalysis *CHA) { + bool Changed = false; + llvm::SmallVector DeadApplies; + + for (auto &BB : F) { + for (auto It = BB.begin(), End = BB.end(); It != End;) { + auto &I = *It++; + + // Skip non-apply instructions. + + auto Apply = FullApplySite::isa(&I); + if (!Apply) + continue; + + auto NewInstPair = tryDevirtualizeApply(Apply, CHA); + if (!NewInstPair.second) + continue; + + Changed = true; + + auto *CalleeFn = NewInstPair.second.getCalleeFunction(); + assert(CalleeFn && "Expected devirtualized callee!"); + + // We may not have optimized these functions yet, and it could + // be beneficial to rerun some earlier passes on the current + // function now that we've made these direct references visible. + if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize()) + notifyPassManagerOfFunction(CalleeFn); + + auto *AI = Apply.getInstruction(); + if (!isa(AI)) + AI->replaceAllUsesWith(NewInstPair.first); + + DeadApplies.push_back(AI); + } + } + + // Remove all the now-dead applies. + while (!DeadApplies.empty()) { + auto *AI = DeadApplies.pop_back_val(); + recursivelyDeleteTriviallyDeadInstructions(AI, true); + } + + return Changed; +} + +SILTransform *swift::createDevirtualizer() { return new Devirtualizer(); } diff --git a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp new file mode 100644 index 0000000000000..48f5c2e55cfce --- /dev/null +++ b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp @@ -0,0 +1,116 @@ +//===--- GenericSpecializer.cpp - Specialization of generic functions -----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Specialize calls to generic functions by substituting static type +// information. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-generic-specializer" + +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/Generics.h" +#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/ADT/SmallVector.h" + +using namespace swift; + +namespace { + +class GenericSpecializer : public SILFunctionTransform { + + bool specializeAppliesInFunction(SILFunction &F); + + /// The entry point to the transformation. + void run() override { + SILFunction &F = *getFunction(); + DEBUG(llvm::dbgs() << "***** GenericSpecializer on function:" << F.getName() + << " *****\n"); + + if (specializeAppliesInFunction(F)) + invalidateAnalysis(SILAnalysis::InvalidationKind::Everything); + } + + StringRef getName() override { return "Generic Specializer"; } +}; + +} // end anonymous namespace + +bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) { + bool Changed = false; + llvm::SmallVector DeadApplies; + + for (auto &BB : F) { + for (auto It = BB.begin(), End = BB.end(); It != End;) { + auto &I = *It++; + + // Skip non-apply instructions, apply instructions with no + // substitutions, apply instructions where we do not statically + // know the called function, and apply instructions where we do + // not have the body of the called function. + + ApplySite Apply = ApplySite::isa(&I); + if (!Apply || !Apply.hasSubstitutions()) + continue; + + auto *Callee = Apply.getCalleeFunction(); + if (!Callee || !Callee->isDefinition()) + continue; + + // We have a call that can potentially be specialized, so + // attempt to do so. + + // The specializer helper function currently expects a collector + // argument, but we aren't going to make use of the results so + // we'll have our filter always return false; + auto Filter = [](SILInstruction *I) -> bool { return false; }; + CloneCollector Collector(Filter); + + SILFunction *SpecializedFunction; + + auto Specialized = + trySpecializeApplyOfGeneric(Apply, SpecializedFunction, Collector); + + if (Specialized) { + Changed = true; + + // If calling the specialization utility resulted in a new + // function (as opposed to returning a previous + // specialization), we need to notify the pass manager so that + // the new function gets optimized. + if (SpecializedFunction) + notifyPassManagerOfFunction(SpecializedFunction); + + auto *AI = Apply.getInstruction(); + + if (!isa(AI)) + AI->replaceAllUsesWith(Specialized.getInstruction()); + + DeadApplies.push_back(AI); + } + } + } + + // Remove all the now-dead applies. + while (!DeadApplies.empty()) { + auto *AI = DeadApplies.pop_back_val(); + recursivelyDeleteTriviallyDeadInstructions(AI, true); + } + + return Changed; +} + +SILTransform *swift::createGenericSpecializer() { + return new GenericSpecializer(); +} diff --git a/lib/SILOptimizer/Transforms/MergeCondFail.cpp b/lib/SILOptimizer/Transforms/MergeCondFail.cpp index b1bcdf8854d6b..157a2c4e6ea38 100644 --- a/lib/SILOptimizer/Transforms/MergeCondFail.cpp +++ b/lib/SILOptimizer/Transforms/MergeCondFail.cpp @@ -1,8 +1,8 @@ -//===-- MergeCondFail.cpp - Merge cond_fail instructions -*- C++ -*-------===// +//===--- MergeCondFail.cpp - Merge cond_fail instructions ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,7 +37,7 @@ namespace { /// /// We can merge cond_fail instructions if there is no side-effect or memory /// write in between them. -/// This pass merges cond_fail instructions by building the disconjunction of +/// This pass merges cond_fail instructions by building the disjunction of /// their operands. class MergeCondFailInsts : public SILFunctionTransform { public: @@ -106,8 +106,8 @@ class MergeCondFailInsts : public SILFunctionTransform { auto CurCond = CondFailToMerge[I]->getOperand(); if (MergedCond) { CurCond = Builder.createBuiltinBinaryFunction(Loc, "or", - CurCond.getType(), - CurCond.getType(), + CurCond->getType(), + CurCond->getType(), {MergedCond, CurCond}); } diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index cb600f6466024..502f99b79dea1 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -1,8 +1,8 @@ -//===-------- RedundantLoadElimination.cpp - SIL Load Forwarding ---------===// +//===--- RedundantLoadElimination.cpp - SIL Load Forwarding ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,13 +15,12 @@ /// This pass eliminates redundant loads. /// /// A load can be eliminated if its value has already been held somewhere, -/// i.e. loaded by a previous load, LSLocation stored by a known -/// value. +/// i.e. generated by a previous load, LSLocation stored by a known value. /// /// In this case, one can replace the load instruction with the previous /// results. /// -/// Redudant Load Elimination (RLE) eliminates such loads by: +/// Redundant Load Elimination (RLE) eliminates such loads by: /// /// 1. Introducing a notion of a LSLocation that is used to model object /// fields. (See below for more details). @@ -32,11 +31,11 @@ /// /// 3. Performing a RPO walk over the control flow graph, tracking any /// LSLocations that are read from or stored into in each basic block. The -/// read or stored value, kept in a map (gen-set) between LSLocation and -/// LSValue, becomes the available value for the LSLocation. +/// read or stored value, kept in a map between LSLocation and LSValue, +/// becomes the available value for the LSLocation. /// /// 4. An optimistic iterative intersection-based dataflow is performed on the -/// gen sets until convergence. +/// gensets until convergence. /// /// At the core of RLE, there is the LSLocation class. A LSLocation is an /// abstraction of an object field in program. It consists of a base and a @@ -46,7 +45,7 @@ /// 2 Int fields. A store like this will generate 2 *indivisible* LSLocations, /// 1 for each field and in addition to keeping a list of LSLocation, RLE also /// keeps their available LSValues. We call it *indivisible* because it -/// can not be broken down to more LSLocations. +/// cannot be broken down to more LSLocations. /// /// LSValue consists of a base - a SILValue from the load or store inst, /// as well as a projection path to which the field it represents. So, a @@ -64,12 +63,12 @@ /// /// However, this may introduce a lot of extraction and aggregation which may /// not be necessary. i.e. a store the struct followed by a load from the -/// struct. To solve this problem, when RLE detects that an load instruction +/// struct. To solve this problem, when RLE detects that a load instruction /// can be replaced by forwarded value, it will try to find minimum # of -/// extraction necessary to form the forwarded value. It will group the -/// available value's by the LSValue base, i.e. the LSValues come -/// from the same instruction, and then use extraction to obtain the needed -/// components of the base. +/// extractions necessary to form the forwarded value. It will group the +/// available value's by the LSValue base, i.e. the LSValues come from the +/// same instruction, and then use extraction to obtain the needed components +/// of the base. /// //===----------------------------------------------------------------------===// @@ -91,7 +90,6 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Statistic.h" -#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -99,10 +97,45 @@ using namespace swift; STATISTIC(NumForwardedLoads, "Number of loads forwarded"); +/// ComputeAvailSetMax - If we ignore all unknown writes, what is the max +/// available set that can reach the a certain point in a basic block. This +/// helps generating the genset and killset. i.e. if there is no downward visible +/// value that can reach the end of a basic block, then we know that the genset +/// and killset for the location need not be set. +/// +/// ComputeAvailGenKillSet - Build the genset and killset of the basic block. +/// +/// ComputeAvailValue - Compute the available value at the end of the basic +/// block. +/// +/// PerformRLE - Perform the actual redundant load elimination. +enum class RLEKind : unsigned { + ComputeAvailSetMax = 0, + ComputeAvailGenKillSet = 1, + ComputeAvailValue = 2, + PerformRLE = 3, +}; + //===----------------------------------------------------------------------===// // Utility Functions //===----------------------------------------------------------------------===// +static bool inline isComputeAvailSetMax(RLEKind Kind) { + return Kind == RLEKind::ComputeAvailSetMax; +} + +static bool inline isComputeAvailGenKillSet(RLEKind Kind) { + return Kind == RLEKind::ComputeAvailGenKillSet; +} + +static bool inline isComputeAvailValue(RLEKind Kind) { + return Kind == RLEKind::ComputeAvailValue; +} + +static bool inline isPerformingRLE(RLEKind Kind) { + return Kind == RLEKind::PerformRLE; +} + /// Returns true if this is an instruction that may have side effects in a /// general sense but are inert from a load store perspective. static bool isRLEInertInstruction(SILInstruction *Inst) { @@ -115,65 +148,75 @@ static bool isRLEInertInstruction(SILInstruction *Inst) { case ValueKind::CondFailInst: case ValueKind::IsUniqueInst: case ValueKind::IsUniqueOrPinnedInst: + case ValueKind::FixLifetimeInst: return true; default: return false; } } -/// Returns true if the given basic block is reachable from the entry block. -/// -/// TODO: this is very inefficient, can we make use of the domtree. -static bool isReachable(SILBasicBlock *Block) { - SmallPtrSet Visited; - llvm::SmallVector Worklist; - SILBasicBlock *EntryBB = &*Block->getParent()->begin(); - Worklist.push_back(EntryBB); - Visited.insert(EntryBB); - - while (!Worklist.empty()) { - auto *CurBB = Worklist.back(); - Worklist.pop_back(); - - if (CurBB == Block) - return true; - - for (auto &Succ : CurBB->getSuccessors()) - if (!Visited.insert(Succ).second) - Worklist.push_back(Succ); - } - return false; -} - -static bool isForwardableEdge(SILBasicBlock *BB) { - if (auto *TI = BB->getTerminator()) { - if (isa(TI) || isa(TI)) - return true; - } - return false; -} - //===----------------------------------------------------------------------===// // Basic Block Location State //===----------------------------------------------------------------------===// namespace { +/// If this function has too many basic blocks or too many locations, it may +/// take a long time to compute the genset and killset. The number of memory +/// behavior or alias query we need to do in worst case is roughly linear to +/// # of BBs x(times) # of locations. +/// +/// we could run RLE on functions with 128 basic blocks and 128 locations, +/// which is a large function. +constexpr unsigned MaxLSLocationBBMultiplicationNone = 128*128; + +/// we could run optimistic RLE on functions with less than 64 basic blocks +/// and 64 locations which is a sizeable function. +constexpr unsigned MaxLSLocationBBMultiplicationPessimistic = 64*64; + /// forward declaration. class RLEContext; + /// State of the load store in one basic block which allows for forwarding from /// loads, stores -> loads class BlockState { +public: + enum class ValueState : unsigned { + CoverValues = 0, + ConcreteValues = 1, + CoverAndConcreteValues = 2, + }; + +private: + /// # of locations in the LocationVault. + unsigned LocationNum; + /// The basic block that we are optimizing. SILBasicBlock *BB; /// A bit vector for which the ith bit represents the ith LSLocation in - /// LSLocationVault. If the bit is set, then the location currently has an - /// downward visible value. - llvm::BitVector ForwardSetIn; + /// LocationVault. If the bit is set, then the location currently has an + /// downward visible value at the beginning of the basic block. + llvm::SmallBitVector ForwardSetIn; + + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If the bit is set, then the location currently has an + /// downward visible value at the end of the basic block. + llvm::SmallBitVector ForwardSetOut; - /// If ForwardSetOut changes while processing a basicblock, then all its - /// successors need to be rerun. - llvm::BitVector ForwardSetOut; + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If we ignore all unknown write, whats the maximum set + /// of available locations at the current position in the basic block. + llvm::SmallBitVector ForwardSetMax; + + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If the bit is set, then the basic block generates a + /// value for the location. + llvm::SmallBitVector BBGenSet; + + /// A bit vector for which the ith bit represents the ith LSLocation in + /// LocationVault. If the bit is set, then the basic block kills the + /// value for the location. + llvm::SmallBitVector BBKillSet; /// This is map between LSLocations and their available values at the /// beginning of this basic block. @@ -187,52 +230,54 @@ class BlockState { /// well as their SILValue replacement. llvm::DenseMap RedundantLoads; - /// Check whether the ForwardSetOut has changed. If it does, we need to - /// rerun the data flow to reach fixed point. - bool updateForwardSetOut() { - bool Changed = (ForwardSetIn != ForwardSetOut); - // Reached the end of this basic block, update the end-of-block - // ForwardSetOut and ForwardValOut; - ForwardSetOut = ForwardSetIn; - ForwardValOut = ForwardValIn; - return Changed; - } + /// LSLocation read or written has been extracted, expanded and mapped to the + /// bit position in the bitvector. Update it in the ForwardSetIn of the + /// current basic block. + void updateForwardSetForRead(RLEContext &Ctx, unsigned B); + void updateForwardSetForWrite(RLEContext &Ctx, unsigned B); - /// Merge in the state of an individual predecessor. - void mergePredecessorState(RLEContext &Ctx, BlockState &OtherState); + /// LSLocation read or written has been extracted, expanded and mapped to the + /// B position in the Bvector. Update it in the genset and killset of the + /// current basic block. + void updateGenKillSetForRead(RLEContext &Ctx, unsigned B); + void updateGenKillSetForWrite(RLEContext &Ctx, unsigned B); - /// LSLocation read has been extracted, expanded and mapped to the bit - /// position in the bitvector. process it using the bit position. - void updateForwardSetForRead(RLEContext &Ctx, unsigned LBit, unsigned VBit); + /// LSLocation read or written has been extracted, expanded and mapped to the + /// B position in the Bvector. Update it in the MaxAvailForwardSet of the + /// current basic block. + void updateMaxAvailSetForRead(RLEContext &Ctx, unsigned B); + void updateMaxAvailSetForWrite(RLEContext &Ctx, unsigned B); /// LSLocation written has been extracted, expanded and mapped to the bit /// position in the bitvector. process it using the bit position. - void updateForwardSetForWrite(RLEContext &Ctx, unsigned LBit, unsigned VBit); + void updateForwardSetAndValForRead(RLEContext &Ctx, unsigned L, unsigned V); + void updateForwardSetAndValForWrite(RLEContext &Ctx, unsigned L, unsigned V); /// There is a read to a LSLocation, expand the LSLocation into individual /// fields before processing them. void processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem, - SILValue Val, bool PF); + SILValue Val, RLEKind Kind); /// There is a write to a LSLocation, expand the LSLocation into individual /// fields before processing them. void processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem, - SILValue Val); + SILValue Val, RLEKind Kind); /// BitVector manipulation functions. - void clearLSLocations(); - void startTrackingLSLocation(unsigned bit, unsigned VBit); - void stopTrackingLSLocation(unsigned bit); - void updateTrackedLSLocation(unsigned bit, unsigned VBit); - bool isTrackingLSLocation(unsigned bit); + void startTrackingLocation(llvm::SmallBitVector &BV, unsigned B); + void stopTrackingLocation(llvm::SmallBitVector &BV, unsigned B); + bool isTrackingLocation(llvm::SmallBitVector &BV, unsigned B); + void startTrackingValue(ValueTableMap &VM, unsigned L, unsigned V); + void stopTrackingValue(ValueTableMap &VM, unsigned B); public: BlockState() = default; - void init(SILBasicBlock *NewBB, unsigned bitcnt, bool reachable) { + void init(SILBasicBlock *NewBB, unsigned bitcnt, bool optimistic) { BB = NewBB; - // The initial state of ForwardSetOut should be all 1's. Otherwise the - // dataflow solution could be too conservative. + LocationNum = bitcnt; + // For reachable basic blocks, the initial state of ForwardSetOut should be + // all 1's. Otherwise the dataflow solution could be too conservative. // // Consider this case, the forwardable value by var a = 10 before the loop // will not be forwarded if the ForwardSetOut is set to 0 initially. @@ -242,10 +287,49 @@ class BlockState { // use(a); // // However, by doing so, we can only do the data forwarding after the - // data flow stablizes. + // data flow stabilizes. // - ForwardSetIn.resize(bitcnt, false); - ForwardSetOut.resize(bitcnt, reachable); + // We set the initial state of unreachable block to 0, as we do not have + // a value for the location. + // + // This is a bit conservative as we could be missing forwarding + // opportunities. i.e. a joint block with 1 predecessor being an + // unreachable block. + // + // we rely on other passes to clean up unreachable block. + ForwardSetIn.resize(LocationNum, false); + ForwardSetOut.resize(LocationNum, optimistic); + + // If we are running an optimistic data flow, set forward max to true + // initially. + ForwardSetMax.resize(LocationNum, optimistic); + + BBGenSet.resize(LocationNum, false); + BBKillSet.resize(LocationNum, false); + } + + /// Initialize the AvailSetMax by intersecting this basic block's + /// predecessors' AvailSetMax. + void mergePredecessorsAvailSetMax(RLEContext &Ctx); + + /// Initialize the AvailSet by intersecting this basic block' predecessors' + /// AvailSet. + void mergePredecessorAvailSet(RLEContext &Ctx); + + /// Initialize the AvailSet and AvailVal of the current basic block. + void mergePredecessorAvailSetAndValue(RLEContext &Ctx); + + /// Reached the end of the basic block, update the ForwardValOut with the + /// ForwardValIn. + void updateForwardValOut() { ForwardValOut = ForwardValIn; } + + /// Check whether the ForwardSetOut has changed. If it does, we need to + /// rerun the data flow to reach fixed point. + bool updateForwardSetOut() { + if (ForwardSetIn == ForwardSetOut) + return false; + ForwardSetOut = ForwardSetIn; + return true; } /// Returns the current basic block we are processing. @@ -261,28 +345,46 @@ class BlockState { /// block. llvm::DenseMap &getRL() { return RedundantLoads; } - bool optimize(RLEContext &Ctx, bool PF); + /// Look into the value for the given LSLocation at end of the basic block, + /// return one of the three ValueState type. + ValueState getValueStateAtEndOfBlock(RLEContext &Ctx, LSLocation &L); + + /// Wrappers to query the value state of the location in this BlockState. + bool isCoverValues(RLEContext &Ctx, LSLocation &L) { + return getValueStateAtEndOfBlock(Ctx, L) == ValueState::CoverValues; + } + bool isConcreteValues(RLEContext &Ctx, LSLocation &L) { + return getValueStateAtEndOfBlock(Ctx, L) == ValueState::ConcreteValues; + } + + /// Iterate over the instructions in the basic block in forward order and + /// process them w.r.t. the given \p Kind. + void processInstructionWithKind(RLEContext &Ctx, SILInstruction *I, + RLEKind Kind); + void processBasicBlockWithKind(RLEContext &Ctx, RLEKind Kind); + + /// Process the current basic block with the genset and killset. Return true + /// if the ForwardSetOut changes. + bool processBasicBlockWithGenKillSet(); /// Set up the value for redundant load elimination. bool setupRLE(RLEContext &Ctx, SILInstruction *I, SILValue Mem); - /// Merge in the states of all predecessors. - void mergePredecessorStates(RLEContext &Ctx); - /// Process Instruction which writes to memory in an unknown way. - void processUnknownWriteInst(RLEContext &Ctx, SILInstruction *I); + void processUnknownWriteInst(RLEContext &Ctx, SILInstruction *I, + RLEKind Kind); + void processUnknownWriteInstForGenKillSet(RLEContext &Ctx, SILInstruction *I); + void processUnknownWriteInstForRLE(RLEContext &Ctx, SILInstruction *I); /// Process LoadInst. Extract LSLocations from LoadInst. - void processLoadInst(RLEContext &Ctx, LoadInst *LI, bool PF); + void processLoadInst(RLEContext &Ctx, LoadInst *LI, RLEKind Kind); /// Process LoadInst. Extract LSLocations from StoreInst. - void processStoreInst(RLEContext &Ctx, StoreInst *SI); + void processStoreInst(RLEContext &Ctx, StoreInst *SI, RLEKind Kind); /// Returns a *single* forwardable SILValue for the given LSLocation right /// before the InsertPt instruction. - SILValue computeForwardingValues(RLEContext &Ctx, LSLocation &L, - SILInstruction *InsertPt, - bool UseForwardValOut); + SILValue reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L); }; } // end anonymous namespace @@ -293,150 +395,242 @@ class BlockState { namespace { -/// This class stores global state that we use when computing redudant load and +using BBValueMap = llvm::DenseMap; + +/// This class stores global state that we use when computing redundant load and /// their replacement in each basic block. class RLEContext { + enum class ProcessKind { + ProcessMultipleIterations = 0, + ProcessOneIteration = 1, + ProcessNone = 2, + }; +private: /// Function currently processing. SILFunction *Fn; + /// The passmanager we are using. + SILPassManager *PM; + /// The alias analysis that we will use during all computations. AliasAnalysis *AA; /// The type expansion analysis we will use during all computations. TypeExpansionAnalysis *TE; - /// The range that we use to iterate over the reverse post order of the given - /// function. - PostOrderFunctionInfo::reverse_range ReversePostOrder; + /// The SSA updater we use to materialize covering values. + SILSSAUpdater Updater; + + /// The range that we use to iterate over the post order and reverse post + /// order of the given function. + PostOrderFunctionInfo *PO; /// Keeps all the locations for the current function. The BitVector in each /// BlockState is then laid on top of it to keep track of which LSLocation /// has a downward available value. - std::vector LSLocationVault; + std::vector LocationVault; - /// Contains a map between LSLocation to their index in the LSLocationVault. + /// Contains a map between LSLocation to their index in the LocationVault. /// Use for fast lookup. - llvm::DenseMap LocToBitIndex; + LSLocationIndexMap LocToBitIndex; + + /// Keeps a map between the accessed SILValue and the location. + LSLocationBaseMap BaseToLocIndex; /// Keeps all the loadstorevalues for the current function. The BitVector in - /// each BBState is then laid on top of it to keep track of which LSLocation + /// each g is then laid on top of it to keep track of which LSLocation /// has a downward available value. std::vector LSValueVault; - /// Contains a map between LSLocation to their index in the LSLocationVault. + /// Contains a map between LSLocation to their index in the LocationVault. /// Use for fast lookup. llvm::DenseMap ValToBitIndex; /// A map from each BasicBlock to its BlockState. - llvm::SmallDenseMap BBToLocState; - - /// A map for each basic block and whether its predecessors have forwardable - /// edges. - llvm::DenseMap ForwardableEdge; + llvm::SmallDenseMap BBToLocState; public: - RLEContext(SILFunction *F, AliasAnalysis *AA, TypeExpansionAnalysis *TE, - PostOrderFunctionInfo::reverse_range RPOT); + RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA, + TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO); RLEContext(const RLEContext &) = delete; RLEContext(RLEContext &&) = default; ~RLEContext() = default; + /// Entry point to redundant load elimination. bool run(); + /// Use a set of ad hoc rules to tell whether we should run a pessimistic + /// one iteration data flow on the function. + ProcessKind getProcessFunctionKind(); + + /// Run the iterative data flow until convergence. + void runIterativeRLE(); + + /// Process the basic blocks for the gen and kill set. + void processBasicBlocksForGenKillSet(); + + /// Process the basic blocks with the gen and kill set. + void processBasicBlocksWithGenKillSet(); + + /// Process the basic block for values generated in the current basic + /// block. + void processBasicBlocksForAvailValue(); + + /// Process basic blocks to perform the redundant load elimination. + void processBasicBlocksForRLE(); + /// Returns the alias analysis we will use during all computations. AliasAnalysis *getAA() const { return AA; } /// Returns the current type expansion analysis we are . TypeExpansionAnalysis *getTE() const { return TE; } + /// Returns the SILValue base to bit index. + LSLocationBaseMap &getBM() { return BaseToLocIndex; } + /// Return the BlockState for the basic block this basic block belongs to. BlockState &getBlockState(SILBasicBlock *B) { return BBToLocState[B]; } - /// Get the bit representing the LSLocation in the LSLocationVault. - unsigned getLSLocationBit(const LSLocation &L); + /// Get the bit representing the LSLocation in the LocationVault. + unsigned getLocationBit(const LSLocation &L); - /// Given the bit, get the LSLocation from the LSLocationVault. - LSLocation &getLSLocation(const unsigned index); + /// Given the bit, get the LSLocation from the LocationVault. + LSLocation &getLocation(const unsigned index); /// Get the bit representing the LSValue in the LSValueVault. - unsigned getLSValueBit(const LSValue &L); + unsigned getValueBit(const LSValue &L); /// Given the bit, get the LSValue from the LSValueVault. - LSValue &getLSValue(const unsigned index); - - /// Go to the predecessors of the given basic block, compute the value - /// for the given LSLocation. - SILValue computePredecessorCoveringValue(SILBasicBlock *B, LSLocation &L); - - /// Return true if all the predecessors of the basic block can have - /// BBArgument. - bool withTransistivelyForwardableEdges(SILBasicBlock *BB); - - /// Given a LSLocation, try to collect all the LSValues for this - /// LSLocation in the given basic block. If a LSValue is a covering - /// value, collectForwardingValues also create a SILArgument for it. As a - /// a result, collectForwardingValues may invalidate TerminatorInsts for - /// basic blocks. - /// - /// UseForwardValOut tells whether to use the ForwardValOut or not. i.e. - /// when materialize a covering value, we go to each predecessors and - /// collect forwarding values from their ForwardValOuts. - bool gatherValues(SILBasicBlock *B, LSLocation &L, LSLocationValueMap &Vs, - bool UseForwardValOut); + LSValue &getValue(const unsigned index); + + /// Given a LSLocation, try to collect all the LSValues for this LSLocation + /// in the given basic block. If part of the locations have covering values, + /// find the values in its predecessors. + bool collectLocationValues(SILBasicBlock *BB, LSLocation &L, + LSLocationValueMap &Values, ValueTableMap &VM); + + /// Transitively collect all the values that make up this location and + /// create a SILArgument out of them. + SILValue computePredecessorLocationValue(SILBasicBlock *BB, LSLocation &L); }; } // end anonymous namespace -bool BlockState::isTrackingLSLocation(unsigned bit) { - return ForwardSetIn.test(bit); +void BlockState::startTrackingValue(ValueTableMap &VM, unsigned L, unsigned V) { + VM[L] = V; +} + +void BlockState::stopTrackingValue(ValueTableMap &VM, unsigned B) { + VM.erase(B); +} + +bool BlockState::isTrackingLocation(llvm::SmallBitVector &BV, unsigned B) { + return BV.test(B); +} + +void BlockState::startTrackingLocation(llvm::SmallBitVector &BV, unsigned B) { + BV.set(B); +} + +void BlockState::stopTrackingLocation(llvm::SmallBitVector &BV, unsigned B) { + BV.reset(B); +} + +void BlockState::mergePredecessorsAvailSetMax(RLEContext &Ctx) { + if (BB->pred_empty()) { + ForwardSetMax.reset(); + return; + } + + auto Iter = BB->pred_begin(); + ForwardSetMax = Ctx.getBlockState(*Iter).ForwardSetMax; + Iter = std::next(Iter); + for (auto EndIter = BB->pred_end(); Iter != EndIter; ++Iter) { + ForwardSetMax &= Ctx.getBlockState(*Iter).ForwardSetMax; + } } -void BlockState::stopTrackingLSLocation(unsigned bit) { - ForwardSetIn.reset(bit); - ForwardValIn.erase(bit); +void BlockState::mergePredecessorAvailSet(RLEContext &Ctx) { + // Clear the state if the basic block has no predecessor. + if (BB->getPreds().begin() == BB->getPreds().end()) { + ForwardSetIn.reset(); + return; + } + + auto Iter = BB->pred_begin(); + ForwardSetIn = Ctx.getBlockState(*Iter).ForwardSetOut; + Iter = std::next(Iter); + for (auto EndIter = BB->pred_end(); Iter != EndIter; ++Iter) { + ForwardSetIn &= Ctx.getBlockState(*Iter).ForwardSetOut; + } } -void BlockState::clearLSLocations() { - ForwardSetIn.reset(); - ForwardValIn.clear(); +void BlockState::mergePredecessorAvailSetAndValue(RLEContext &Ctx) { + // Clear the state if the basic block has no predecessor. + if (BB->getPreds().begin() == BB->getPreds().end()) { + ForwardSetIn.reset(); + ForwardValIn.clear(); + return; + } + + auto Iter = BB->pred_begin(); + ForwardSetIn = Ctx.getBlockState(*Iter).ForwardSetOut; + ForwardValIn = Ctx.getBlockState(*Iter).ForwardValOut; + Iter = std::next(Iter); + for (auto EndIter = BB->pred_end(); Iter != EndIter; ++Iter) { + BlockState &OtherState = Ctx.getBlockState(*Iter); + ForwardSetIn &= OtherState.ForwardSetOut; + + // Merge in the predecessor state. + for (unsigned i = 0; i < LocationNum; ++i) { + if (OtherState.ForwardSetOut[i]) { + // There are multiple values from multiple predecessors, set this as + // a covering value. We do not need to track the value itself, as we + // can always go to the predecessors BlockState to find it. + ForwardValIn[i] = Ctx.getValueBit(LSValue(true)); + continue; + } + // If this location does have an available value, then clear it. + stopTrackingValue(ForwardValIn, i); + stopTrackingLocation(ForwardSetIn, i); + } + } } -void BlockState::startTrackingLSLocation(unsigned bit, unsigned VBit) { - ForwardSetIn.set(bit); - ForwardValIn[bit] = VBit; +void BlockState::processBasicBlockWithKind(RLEContext &Ctx, RLEKind Kind) { + // Iterate over instructions in forward order. + for (auto &II : *BB) { + processInstructionWithKind(Ctx, &II, Kind); + } } -void BlockState::updateTrackedLSLocation(unsigned bit, unsigned VBit) { - ForwardValIn[bit] = VBit; +bool BlockState::processBasicBlockWithGenKillSet() { + ForwardSetIn.reset(BBKillSet); + ForwardSetIn |= BBGenSet; + return updateForwardSetOut(); } -SILValue BlockState::computeForwardingValues(RLEContext &Ctx, LSLocation &L, - SILInstruction *InsertPt, - bool UseForwardValOut) { - SILBasicBlock *ParentBB = InsertPt->getParent(); - bool IsTerminator = (InsertPt == ParentBB->getTerminator()); - // We do not have a SILValue for the current LSLocation, try to construct - // one. - // - // Collect the locations and their corresponding values into a map. +SILValue BlockState::reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L) { // First, collect current available locations and their corresponding values // into a map. LSLocationValueMap Values; - if (!Ctx.gatherValues(ParentBB, L, Values, UseForwardValOut)) - return SILValue(); - // If the InsertPt is the terminator instruction of the basic block, we - // *refresh* it as terminator instruction could be deleted as a result - // of adding new edge values to the terminator instruction. - if (IsTerminator) - InsertPt = ParentBB->getTerminator(); + LSLocationList Locs; + LSLocation::expand(L, &BB->getModule(), Locs, Ctx.getTE()); + + // Find the values that this basic block defines and the locations which + // we do not have a concrete value in the current basic block. + ValueTableMap &OTM = getForwardValOut(); + for (unsigned i = 0; i < Locs.size(); ++i) { + Values[Locs[i]] = Ctx.getValue(OTM[Ctx.getLocationBit(Locs[i])]); + } // Second, reduce the available values into a single SILValue we can use to // forward. SILValue TheForwardingValue; - TheForwardingValue = LSValue::reduce(L, &ParentBB->getModule(), Values, - InsertPt, Ctx.getTE()); + TheForwardingValue = LSValue::reduce(L, &BB->getModule(), Values, + BB->getTerminator(), Ctx.getTE()); /// Return the forwarding value. return TheForwardingValue; } @@ -445,15 +639,23 @@ bool BlockState::setupRLE(RLEContext &Ctx, SILInstruction *I, SILValue Mem) { // Try to construct a SILValue for the current LSLocation. // // Collect the locations and their corresponding values into a map. - LSLocation L(Mem); + LSLocation L; + LSLocationBaseMap &BaseToLocIndex = Ctx.getBM(); + if (BaseToLocIndex.find(Mem) != BaseToLocIndex.end()) { + L = BaseToLocIndex[Mem]; + } else { + SILValue UO = getUnderlyingObject(Mem); + L = LSLocation(UO, NewProjectionPath::getProjectionPath(UO, Mem)); + } + LSLocationValueMap Values; - if (!Ctx.gatherValues(I->getParent(), L, Values, false)) + // Use the ForwardValIn as we are currently processing the basic block. + if (!Ctx.collectLocationValues(I->getParent(), L, Values, getForwardValIn())) return false; // Reduce the available values into a single SILValue we can use to forward. SILModule *Mod = &I->getModule(); - SILValue TheForwardingValue; - TheForwardingValue = LSValue::reduce(L, Mod, Values, I, Ctx.getTE()); + SILValue TheForwardingValue = LSValue::reduce(L, Mod, Values, I, Ctx.getTE()); if (!TheForwardingValue) return false; @@ -483,64 +685,157 @@ bool BlockState::setupRLE(RLEContext &Ctx, SILInstruction *I, SILValue Mem) { return true; } -void BlockState::updateForwardSetForRead(RLEContext &Ctx, unsigned LBit, - unsigned VBit) { - // If there is already an available value for this location, use - // the existing value. - if (isTrackingLSLocation(LBit)) - return; +void BlockState::updateForwardSetForRead(RLEContext &Ctx, unsigned B) { + startTrackingLocation(ForwardSetIn, B); +} + +void BlockState::updateGenKillSetForRead(RLEContext &Ctx, unsigned B) { + startTrackingLocation(BBGenSet, B); + stopTrackingLocation(BBKillSet, B); +} +void BlockState::updateForwardSetAndValForRead(RLEContext &Ctx, unsigned L, + unsigned V) { // Track the new location and value. - startTrackingLSLocation(LBit, VBit); + startTrackingValue(ForwardValIn, L, V); + startTrackingLocation(ForwardSetIn, L); } -void BlockState::updateForwardSetForWrite(RLEContext &Ctx, unsigned LBit, - unsigned VBit) { - // This is a store. Invalidate any Memlocation that this location may - // alias, as their value can no longer be forwarded. - LSLocation &R = Ctx.getLSLocation(LBit); - for (unsigned i = 0; i < ForwardSetIn.size(); ++i) { - if (!isTrackingLSLocation(i)) +void BlockState::updateGenKillSetForWrite(RLEContext &Ctx, unsigned B) { + // This is a store, invalidate any location that this location may alias, as + // their values can no longer be forwarded. + LSLocation &R = Ctx.getLocation(B); + for (unsigned i = 0; i < LocationNum; ++i) { + if (!isTrackingLocation(ForwardSetMax, i)) continue; - LSLocation &L = Ctx.getLSLocation(i); + LSLocation &L = Ctx.getLocation(i); if (!L.isMayAliasLSLocation(R, Ctx.getAA())) continue; - // MayAlias, invalidate the LSLocation. - stopTrackingLSLocation(i); + // MayAlias, invalidate the location. + stopTrackingLocation(BBGenSet, i); + startTrackingLocation(BBKillSet, i); } - // Start tracking this LSLocation. - startTrackingLSLocation(LBit, VBit); + // Start tracking this location. + startTrackingLocation(BBGenSet, B); + stopTrackingLocation(BBKillSet, B); +} + +void BlockState::updateMaxAvailSetForWrite(RLEContext &Ctx, unsigned B) { + startTrackingLocation(ForwardSetMax, B); +} + +void BlockState::updateMaxAvailSetForRead(RLEContext &Ctx, unsigned B) { + startTrackingLocation(ForwardSetMax, B); +} + +void BlockState::updateForwardSetForWrite(RLEContext &Ctx, unsigned B) { + // This is a store, invalidate any location that this location may alias, as + // their values can no longer be forwarded. + LSLocation &R = Ctx.getLocation(B); + for (unsigned i = 0; i < LocationNum; ++i) { + if (!isTrackingLocation(ForwardSetIn, i)) + continue; + LSLocation &L = Ctx.getLocation(i); + if (!L.isMayAliasLSLocation(R, Ctx.getAA())) + continue; + // MayAlias, invalidate the location. + stopTrackingLocation(ForwardSetIn, i); + } + + // Start tracking this location. + startTrackingLocation(ForwardSetIn, B); +} + +void BlockState::updateForwardSetAndValForWrite(RLEContext &Ctx, unsigned L, + unsigned V) { + // This is a store, invalidate any location that this location may alias, as + // their values can no longer be forwarded. + LSLocation &R = Ctx.getLocation(L); + for (unsigned i = 0; i < LocationNum; ++i) { + if (!isTrackingLocation(ForwardSetIn, i)) + continue; + LSLocation &L = Ctx.getLocation(i); + if (!L.isMayAliasLSLocation(R, Ctx.getAA())) + continue; + // MayAlias, invalidate the location and value. + stopTrackingValue(ForwardValIn, i); + stopTrackingLocation(ForwardSetIn, i); + } + + // Start tracking this location and value. + startTrackingLocation(ForwardSetIn, L); + startTrackingValue(ForwardValIn, L, V); } void BlockState::processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem, - SILValue Val) { + SILValue Val, RLEKind Kind) { // Initialize the LSLocation. - LSLocation L(Mem); + LSLocation L; + LSLocationBaseMap &BaseToLocIndex = Ctx.getBM(); + if (BaseToLocIndex.find(Mem) != BaseToLocIndex.end()) { + L = BaseToLocIndex[Mem]; + } else { + SILValue UO = getUnderlyingObject(Mem); + L = LSLocation(UO, NewProjectionPath::getProjectionPath(UO, Mem)); + } // If we cant figure out the Base or Projection Path for the write, // process it as an unknown memory instruction. if (!L.isValid()) { - processUnknownWriteInst(Ctx, I); + // we can ignore unknown store instructions if we are computing the + // AvailSetMax. + if (!isComputeAvailSetMax(Kind)) { + processUnknownWriteInst(Ctx, I, Kind); + } return; } - // Expand the given LSLocation and Val into individual fields and process + // Expand the given location and val into individual fields and process // them as separate writes. LSLocationList Locs; - LSValueList Vals; LSLocation::expand(L, &I->getModule(), Locs, Ctx.getTE()); + + if (isComputeAvailSetMax(Kind)) { + for (unsigned i = 0; i < Locs.size(); ++i) { + updateMaxAvailSetForWrite(Ctx, Ctx.getLocationBit(Locs[i])); + } + return; + } + + // Are we computing the genset and killset ? + if (isComputeAvailGenKillSet(Kind)) { + for (unsigned i = 0; i < Locs.size(); ++i) { + updateGenKillSetForWrite(Ctx, Ctx.getLocationBit(Locs[i])); + } + return; + } + + // Are we computing available value or performing RLE? + LSValueList Vals; LSValue::expand(Val, &I->getModule(), Vals, Ctx.getTE()); - for (unsigned i = 0; i < Locs.size(); ++i) { - updateForwardSetForWrite(Ctx, Ctx.getLSLocationBit(Locs[i]), - Ctx.getLSValueBit(Vals[i])); + if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { + for (unsigned i = 0; i < Locs.size(); ++i) { + updateForwardSetAndValForWrite(Ctx, Ctx.getLocationBit(Locs[i]), + Ctx.getValueBit(Vals[i])); + } + return; } + + llvm_unreachable("Unknown RLE compute kind"); } void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem, - SILValue Val, bool PF) { + SILValue Val, RLEKind Kind) { // Initialize the LSLocation. - LSLocation L(Mem); + LSLocation L; + LSLocationBaseMap &BaseToLocIndex = Ctx.getBM(); + if (BaseToLocIndex.find(Mem) != BaseToLocIndex.end()) { + L = BaseToLocIndex[Mem]; + } else { + SILValue UO = getUnderlyingObject(Mem); + L = LSLocation(UO, NewProjectionPath::getProjectionPath(UO, Mem)); + } // If we cant figure out the Base or Projection Path for the read, simply // ignore it for now. @@ -550,324 +845,221 @@ void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem, // Expand the given LSLocation and Val into individual fields and process // them as separate reads. LSLocationList Locs; - LSValueList Vals; LSLocation::expand(L, &I->getModule(), Locs, Ctx.getTE()); - LSValue::expand(Val, &I->getModule(), Vals, Ctx.getTE()); - bool CanForward = true; - for (auto &X : Locs) { - CanForward &= isTrackingLSLocation(Ctx.getLSLocationBit(X)); + if (isComputeAvailSetMax(Kind)) { + for (unsigned i = 0; i < Locs.size(); ++i) { + updateMaxAvailSetForRead(Ctx, Ctx.getLocationBit(Locs[i])); + } + return; } - // We do not have every location available, track the LSLocations and - // their values from this instruction, and return. - if (!CanForward) { + // Are we computing the genset and killset. + if (isComputeAvailGenKillSet(Kind)) { for (unsigned i = 0; i < Locs.size(); ++i) { - updateForwardSetForRead(Ctx, Ctx.getLSLocationBit(Locs[i]), - Ctx.getLSValueBit(Vals[i])); + updateGenKillSetForRead(Ctx, Ctx.getLocationBit(Locs[i])); } return; } - // At this point, we have all the LSLocations and their values available. - // - // If we are not doing forwarding just yet, simply return. - if (!PF) + // Are we computing available values ?. + bool CanForward = true; + LSValueList Vals; + LSValue::expand(Val, &I->getModule(), Vals, Ctx.getTE()); + if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { + for (unsigned i = 0; i < Locs.size(); ++i) { + if (isTrackingLocation(ForwardSetIn, Ctx.getLocationBit(Locs[i]))) + continue; + updateForwardSetAndValForRead(Ctx, Ctx.getLocationBit(Locs[i]), + Ctx.getValueBit(Vals[i])); + // We can not perform the forwarding as we are at least missing + // some pieces of the read location. + CanForward = false; + } + } + + // Simply return if we are not performing RLE or we do not have all the + // values available to perform RLE. + if (!isPerformingRLE(Kind) || !CanForward) return; // Lastly, forward value to the load. setupRLE(Ctx, I, Mem); } -void BlockState::processStoreInst(RLEContext &Ctx, StoreInst *SI) { - processWrite(Ctx, SI, SI->getDest(), SI->getSrc()); +void BlockState::processStoreInst(RLEContext &Ctx, StoreInst *SI, RLEKind Kind) { + processWrite(Ctx, SI, SI->getDest(), SI->getSrc(), Kind); } -void BlockState::processLoadInst(RLEContext &Ctx, LoadInst *LI, bool PF) { - processRead(Ctx, LI, LI->getOperand(), SILValue(LI), PF); +void BlockState::processLoadInst(RLEContext &Ctx, LoadInst *LI, RLEKind Kind) { + processRead(Ctx, LI, LI->getOperand(), SILValue(LI), Kind); } -void BlockState::processUnknownWriteInst(RLEContext &Ctx, SILInstruction *I) { +void BlockState::processUnknownWriteInstForGenKillSet(RLEContext &Ctx, + SILInstruction *I) { auto *AA = Ctx.getAA(); - for (unsigned i = 0; i < ForwardSetIn.size(); ++i) { - if (!isTrackingLSLocation(i)) + for (unsigned i = 0; i < LocationNum; ++i) { + if (!isTrackingLocation(ForwardSetMax, i)) continue; // Invalidate any location this instruction may write to. // // TODO: checking may alias with Base is overly conservative, // we should check may alias with base plus projection path. - LSLocation &R = Ctx.getLSLocation(i); + LSLocation &R = Ctx.getLocation(i); if (!AA->mayWriteToMemory(I, R.getBase())) continue; // MayAlias. - stopTrackingLSLocation(i); + stopTrackingLocation(BBGenSet, i); + startTrackingLocation(BBKillSet, i); } } -/// Promote stored values to loads and merge duplicated loads. -bool BlockState::optimize(RLEContext &Ctx, bool PF) { - for (auto &II : *BB) { - SILInstruction *Inst = &II; - DEBUG(llvm::dbgs() << " Visiting: " << *Inst); - - // This is a StoreInst, try to see whether it clobbers any forwarding - // value. - if (auto *SI = dyn_cast(Inst)) { - processStoreInst(Ctx, SI); - continue; - } - - // This is a LoadInst. Let's see if we can find a previous loaded, stored - // value to use instead of this load. - if (auto *LI = dyn_cast(Inst)) { - processLoadInst(Ctx, LI, PF); - continue; - } - - // If this instruction has side effects, but is inert from a load store - // perspective, skip it. - if (isRLEInertInstruction(Inst)) { - DEBUG(llvm::dbgs() << " Found inert instruction: " << *Inst); - continue; - } - - // If this instruction does not read or write memory, we can skip it. - if (!Inst->mayReadOrWriteMemory()) { - DEBUG(llvm::dbgs() << " Found readnone instruction, does not " - "affect loads and stores.\n"); +void BlockState::processUnknownWriteInstForRLE(RLEContext &Ctx, + SILInstruction *I) { + auto *AA = Ctx.getAA(); + for (unsigned i = 0; i < LocationNum; ++i) { + if (!isTrackingLocation(ForwardSetIn, i)) continue; - } - - // If we have an instruction that may write to memory and we can not prove - // that it and its operands can not alias a load we have visited, invalidate - // that load. - if (Inst->mayWriteToMemory()) { - processUnknownWriteInst(Ctx, Inst); + // Invalidate any location this instruction may write to. + // + // TODO: checking may alias with Base is overly conservative, + // we should check may alias with base plus projection path. + LSLocation &R = Ctx.getLocation(i); + if (!AA->mayWriteToMemory(I, R.getBase())) continue; - } + // MayAlias. + stopTrackingLocation(ForwardSetIn, i); + stopTrackingValue(ForwardValIn, i); } - - // The basic block is finished, see whether there is a change in the - // ForwardSetOut set. - return updateForwardSetOut(); } -void BlockState::mergePredecessorState(RLEContext &Ctx, - BlockState &OtherState) { - // Merge in the predecessor state. - llvm::SmallVector LocDeleteList; - for (unsigned i = 0; i < ForwardSetIn.size(); ++i) { - if (OtherState.ForwardSetOut[i]) { - // There are multiple values from multiple predecessors, set this as - // a covering value. We do not need to track the value itself, as we - // can always go to the predecessors BlockState to find it. - ForwardValIn[i] = Ctx.getLSValueBit(LSValue(true)); - continue; - } - // If this location does have an available value, then clear it. - stopTrackingLSLocation(i); +void BlockState::processUnknownWriteInst(RLEContext &Ctx, SILInstruction *I, + RLEKind Kind) { + // Are we computing the genset and killset ? + if (isComputeAvailGenKillSet(Kind)) { + processUnknownWriteInstForGenKillSet(Ctx, I); + return; } -} -void BlockState::mergePredecessorStates(RLEContext &Ctx) { - // Clear the state if the basic block has no predecessor. - if (BB->getPreds().begin() == BB->getPreds().end()) { - clearLSLocations(); + // Are we computing the available value or doing RLE ? + if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { + processUnknownWriteInstForRLE(Ctx, I); return; } - // We initialize the state with the first predecessor's state and merge - // in states of other predecessors. - bool HasAtLeastOnePred = false; - // For each predecessor of BB... - for (auto Pred : BB->getPreds()) { - BlockState &Other = Ctx.getBlockState(Pred); - - // If we have not had at least one predecessor, initialize BlockState - // with the state of the initial predecessor. - // If BB is also a predecessor of itself, we should not initialize. - if (!HasAtLeastOnePred) { - ForwardSetIn = Other.ForwardSetOut; - ForwardValIn = Other.ForwardValOut; - } else { - mergePredecessorState(Ctx, Other); - } - HasAtLeastOnePred = true; - } + llvm_unreachable("Unknown RLE compute kind"); } -//===----------------------------------------------------------------------===// -// RLEContext Implementation -//===----------------------------------------------------------------------===// - -RLEContext::RLEContext(SILFunction *F, AliasAnalysis *AA, - TypeExpansionAnalysis *TE, - PostOrderFunctionInfo::reverse_range RPOT) - : Fn(F), AA(AA), TE(TE), ReversePostOrder(RPOT) { - // Walk over the function and find all the locations accessed by - // this function. - LSLocation::enumerateLSLocations(*Fn, LSLocationVault, LocToBitIndex, TE); - - // Walk over the function and find all the values used in this function. - LSValue::enumerateLSValues(*Fn, LSValueVault, ValToBitIndex, TE); - // For all basic blocks in the function, initialize a BB state. Since we - // know all the locations accessed in this function, we can resize the bit - // vector to the appropriate size. - for (auto &B : *F) { - BBToLocState[&B] = BlockState(); - // We set the initial state of unreachable block to 0, as we do not have - // a value for the location. - // - // This is a bit conservative as we could be missing forwarding - // opportunities. i.e. a joint block with 1 predecessor being an - // unreachable block. - // - // we rely on other passes to clean up unreachable block. - BBToLocState[&B].init(&B, LSLocationVault.size(), isReachable(&B)); +void BlockState::processInstructionWithKind(RLEContext &Ctx, + SILInstruction *Inst, + RLEKind Kind) { + // This is a StoreInst, try to see whether it clobbers any forwarding value + if (auto *SI = dyn_cast(Inst)) { + processStoreInst(Ctx, SI, Kind); + return; } -} -bool RLEContext::withTransistivelyForwardableEdges(SILBasicBlock *BB) { - // Have we processed this basic block before ? - if (ForwardableEdge.find(BB) != ForwardableEdge.end()) - return ForwardableEdge[BB]; - - // Look at all predecessors whether have forwardable edges. - llvm::DenseSet Visited; - llvm::SmallVector Worklist; - for (auto Pred : BB->getPreds()) { - Worklist.push_back(Pred); - Visited.insert(Pred); + // This is a LoadInst. Let's see if we can find a previous loaded, stored + // value to use instead of this load. + if (auto *LI = dyn_cast(Inst)) { + processLoadInst(Ctx, LI, Kind); + return; } - while (!Worklist.empty()) { - auto *CurBB = Worklist.back(); - Worklist.pop_back(); + // If this instruction has side effects, but is inert from a load store + // perspective, skip it. + if (isRLEInertInstruction(Inst)) + return; - if (!isForwardableEdge(CurBB)) { - ForwardableEdge[BB] = false; - return false; - } + // If this instruction does not read or write memory, we can skip it. + if (!Inst->mayReadOrWriteMemory()) + return; - for (auto Pred : CurBB->getPreds()) { - if (Visited.find(Pred) == Visited.end()) { - Visited.insert(Pred); - Worklist.push_back(Pred); - } - } + // If we have an instruction that may write to memory and we cannot prove + // that it and its operands cannot alias a load we have visited, + // invalidate that load. + if (Inst->mayWriteToMemory()) { + processUnknownWriteInst(Ctx, Inst, Kind); + return; } - ForwardableEdge[BB] = true; - return true; } -SILValue RLEContext::computePredecessorCoveringValue(SILBasicBlock *BB, - LSLocation &L) { - // This is a covering value, need to go to each of the predecessors to - // materialize them and create a SILArgument to merge them. - // - // If any of the predecessors can not forward an edge value, bail out - // for now. - // - // *NOTE* This is a strong argument in favor of representing PHI nodes - // separately from SILArguments. - // - // TODO: we can create a trampoline basic block if the predecessor has - // a non-edgevalue terminator inst. - // - if (!withTransistivelyForwardableEdges(BB)) - return SILValue(); - - // At this point, we know this LSLocation has available value and we also - // know we can forward a SILValue from every predecesor. It is safe to - // insert the basic block argument. - BlockState &Forwarder = getBlockState(BB); - SILValue TheForwardingValue = BB->createBBArg(L.getType()); - - // For the given LSLocation, we just created a concrete value at the - // beginning of this basic block. Update the ForwardValOut for the - // current basic block. - // - // ForwardValOut keeps all the LSLocations and their forwarding values - // at the end of the basic block. If a LSLocation has a covering value - // at the end of the basic block, we can now replace the covering value with - // this concrete SILArgument. - // - // However, if the LSLocation has a concrete value, we know there must - // be an instruction that generated the concrete value between the current - // instruction and the end of the basic block, we do not update the - // ForwardValOut in this case. - // - // NOTE: This is necessary to prevent an infinite loop while materializing - // the covering value. - // - // Imagine an empty selfloop block with 1 predecessor having a load [A], to - // materialize [A]'s covering value, we go to its predecessors. However, - // the backedge will carry a covering value as well in this case. - // - LSLocationList Locs; - LSValueList Vals; - LSLocation::expand(L, &BB->getModule(), Locs, TE); - LSValue::expand(TheForwardingValue, &BB->getModule(), Vals, TE); - ValueTableMap &VTM = Forwarder.getForwardValOut(); - for (unsigned i = 0; i < Locs.size(); ++i) { - unsigned bit = getLSLocationBit(Locs[i]); - if (!getLSValue(VTM[bit]).isCoveringValue()) - continue; - VTM[bit] = getLSValueBit(Vals[i]); +RLEContext::ProcessKind RLEContext::getProcessFunctionKind() { + bool RunOneIteration = true; + unsigned BBCount = 0; + unsigned LocationCount = LocationVault.size(); + + // If all basic blocks will have their predecessors processed if + // the basic blocks in the functions are iterated in post order. + // Then this function can be processed in one iteration, i.e. no + // need to generate the genset and killset. + auto *PO = PM->getAnalysis()->get(Fn); + llvm::DenseSet HandledBBs; + for (SILBasicBlock *B : PO->getReversePostOrder()) { + ++BBCount; + for (auto X : B->getPreds()) { + if (HandledBBs.find(X) == HandledBBs.end()) { + RunOneIteration = false; + break; + } + } + HandledBBs.insert(B); } - // Compute the SILArgument for the covering value. - llvm::SmallVector Preds; - for (auto Pred : BB->getPreds()) { - Preds.push_back(Pred); - } + // Data flow may take too long to run. + if (BBCount * LocationCount > MaxLSLocationBBMultiplicationNone) + return ProcessKind::ProcessNone; - llvm::DenseMap Args; - for (auto Pred : Preds) { - BlockState &Forwarder = getBlockState(Pred); - // Call computeForwardingValues with using ForwardValOut as we are - // computing the LSLocation value at the end of each predecessor. - Args[Pred] = Forwarder.computeForwardingValues(*this, L, - Pred->getTerminator(), true); - assert(Args[Pred] && "Fail to create a forwarding value"); - } + // This function's data flow would converge in 1 iteration. + if (RunOneIteration) + return ProcessKind::ProcessOneIteration; + + // We run one pessimistic data flow to do dead store elimination on + // the function. + if (BBCount * LocationCount > MaxLSLocationBBMultiplicationPessimistic) + return ProcessKind::ProcessOneIteration; - // Create the new SILArgument and set ForwardingValue to it. - for (auto Pred : Preds) { - // Update all edges. We do not create new edges in between BBs so this - // information should always be correct. - addNewEdgeValueToBranch(Pred->getTerminator(), BB, Args[Pred]); - } + return ProcessKind::ProcessMultipleIterations; +} - return TheForwardingValue; +//===----------------------------------------------------------------------===// +// RLEContext Implementation +//===----------------------------------------------------------------------===// + +RLEContext::RLEContext(SILFunction *F, SILPassManager *PM, AliasAnalysis *AA, + TypeExpansionAnalysis *TE, PostOrderFunctionInfo *PO) + : Fn(F), PM(PM), AA(AA), TE(TE), PO(PO) { } -LSLocation &RLEContext::getLSLocation(const unsigned index) { - return LSLocationVault[index]; +LSLocation &RLEContext::getLocation(const unsigned index) { + return LocationVault[index]; } -unsigned RLEContext::getLSLocationBit(const LSLocation &Loc) { - // Return the bit position of the given Loc in the LSLocationVault. The bit +unsigned RLEContext::getLocationBit(const LSLocation &Loc) { + // Return the bit position of the given Loc in the LocationVault. The bit // position is then used to set/reset the bitvector kept by each BlockState. // // We should have the location populated by the enumerateLSLocation at this // point. - // auto Iter = LocToBitIndex.find(Loc); - assert(Iter != LocToBitIndex.end() && - "LSLocation should have been enumerated"); + assert(Iter != LocToBitIndex.end() && "Location should have been enum'ed"); return Iter->second; } -LSValue &RLEContext::getLSValue(const unsigned index) { +LSValue &RLEContext::getValue(const unsigned index) { return LSValueVault[index]; } -unsigned RLEContext::getLSValueBit(const LSValue &Val) { +unsigned RLEContext::getValueBit(const LSValue &Val) { // Return the bit position of the given Val in the LSValueVault. The bit - // position is then used to set/reset the bitvector kept by each BBState. + // position is then used to set/reset the bitvector kept by each g. auto Iter = ValToBitIndex.find(Val); + + // We do not walk over the function and find all the possible LSValues + // in this function, as some of the these values will not be used, i.e. + // if the LoadInst that generates this value is actually RLE'ed. + // Instead, we create the LSValues when we need them. if (Iter == ValToBitIndex.end()) { ValToBitIndex[Val] = LSValueVault.size(); LSValueVault.push_back(Val); @@ -876,117 +1068,324 @@ unsigned RLEContext::getLSValueBit(const LSValue &Val) { return Iter->second; } -bool RLEContext::gatherValues(SILBasicBlock *BB, LSLocation &L, - LSLocationValueMap &Values, - bool UseForwardValOut) { +BlockState::ValueState BlockState::getValueStateAtEndOfBlock(RLEContext &Ctx, + LSLocation &L) { + // Find number of covering value and concrete values for the locations + // expanded from the given location. + unsigned CSCount = 0, CTCount = 0; + LSLocationList Locs; + LSLocation::expand(L, &BB->getModule(), Locs, Ctx.getTE()); + + ValueTableMap &OTM = getForwardValOut(); + for (auto &X : Locs) { + LSValue &V = Ctx.getValue(OTM[Ctx.getLocationBit(X)]); + if (V.isCoveringValue()) { + ++CSCount; + continue; + } + ++CTCount; + } + + if (CSCount == Locs.size()) + return ValueState::CoverValues; + if (CTCount == Locs.size()) + return ValueState::ConcreteValues; + return ValueState::CoverAndConcreteValues; +} + +SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB, + LSLocation &L) { + BBValueMap Values; + llvm::DenseSet HandledBBs; + llvm::SmallVector WorkList; + + // Push in all the predecessors to get started. + for (auto Pred : BB->getPreds()) { + WorkList.push_back(Pred); + } + + while (!WorkList.empty()) { + auto *CurBB = WorkList.pop_back_val(); + BlockState &Forwarder = getBlockState(CurBB); + + // Mark this basic block as processed. + HandledBBs.insert(CurBB); + + // There are 3 cases that can happen here. + // + // 1. The current basic block contains concrete values for the entire + // location. + // 2. The current basic block contains covering values for the entire + // location. + // 3. The current basic block contains concrete value for part of the + // location and covering values for the rest. + // + // This BlockState contains concrete values for all the expanded + // locations, collect and reduce them into a single value in the current + // basic block. + if (Forwarder.isConcreteValues(*this, L)) { + Values[CurBB] = Forwarder.reduceValuesAtEndOfBlock(*this, L); + continue; + } + + // This BlockState does not contain concrete value for any of the expanded + // locations, collect in this block's predecessors. + if (Forwarder.isCoverValues(*this, L)) { + for (auto Pred : CurBB->getPreds()) { + if (HandledBBs.find(Pred) != HandledBBs.end()) + continue; + WorkList.push_back(Pred); + } + continue; + } + + // This block contains concrete values for some but not all the expanded + // locations, recursively call collectLocationValues to materialize the + // value that reaches this basic block. + LSLocationValueMap LSValues; + if (!collectLocationValues(CurBB, L, LSValues, Forwarder.getForwardValOut())) + return SILValue(); + + // Reduce the available values into a single SILValue we can use to forward + SILInstruction *IPt = CurBB->getTerminator(); + Values[CurBB] = LSValue::reduce(L, &BB->getModule(), LSValues, IPt, TE); + } + + // Finally, collect all the values for the SILArgument, materialize it using + // the SSAUpdater. + Updater.Initialize(L.getType(&BB->getModule()).getObjectType()); + for (auto V : Values) { + Updater.AddAvailableValue(V.first, V.second); + } + + return Updater.GetValueInMiddleOfBlock(BB); +} + +bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, + LSLocationValueMap &Values, + ValueTableMap &VM) { LSLocationSet CSLocs; LSLocationList Locs; LSLocation::expand(L, &BB->getModule(), Locs, TE); - // Are we using the ForwardVal at the end of the basic block or not. - // If we are collecting values at the end of the basic block, we can - // use its ForwardValOut. - // - BlockState &Forwarder = getBlockState(BB); - ValueTableMap &OTM = UseForwardValOut ? Forwarder.getForwardValOut() - : Forwarder.getForwardValIn(); + + auto *Mod = &BB->getModule(); + // Find the locations that this basic block defines and the locations which + // we do not have a concrete value in the current basic block. for (auto &X : Locs) { - Values[X] = getLSValue(OTM[getLSLocationBit(X)]); + Values[X] = getValue(VM[getLocationBit(X)]); if (!Values[X].isCoveringValue()) continue; CSLocs.insert(X); } - // Try to reduce it to the minimum # of locations possible, this will help - // us to generate as few extractions as possible. - LSLocation::reduce(L, &BB->getModule(), CSLocs, TE); + // For locations which we do not have concrete values for in this basic + // block, try to reduce it to the minimum # of locations possible, this + // will help us to generate as few SILArguments as possible. + LSLocation::reduce(L, Mod, CSLocs, TE); // To handle covering value, we need to go to the predecessors and // materialize them there. for (auto &X : CSLocs) { - SILValue V = computePredecessorCoveringValue(BB, X); + SILValue V = computePredecessorLocationValue(BB, X); if (!V) return false; + // We've constructed a concrete value for the covering value. Expand and // collect the newly created forwardable values. LSLocationList Locs; LSValueList Vals; - LSLocation::expand(X, &BB->getModule(), Locs, TE); - LSValue::expand(V, &BB->getModule(), Vals, TE); + LSLocation::expand(X, Mod, Locs, TE); + LSValue::expand(V, Mod, Vals, TE); for (unsigned i = 0; i < Locs.size(); ++i) { Values[Locs[i]] = Vals[i]; assert(Values[Locs[i]].isValid() && "Invalid load store value"); } } + return true; +} -// Sanity check to make sure we have valid load store values for each -// LSLocation. -#ifndef NDEBUG - for (auto &X : Locs) { - (void)X; - assert(Values[X].isValid() && "Invalid load store value"); +void RLEContext::processBasicBlocksForGenKillSet() { + for (SILBasicBlock *BB : PO->getReversePostOrder()) { + BlockState &S = getBlockState(BB); + + // Compute the AvailSetMax at the beginning of the basic block. + S.mergePredecessorsAvailSetMax(*this); + + // Compute the genset and killset. + // + // To optimize this process, we also compute the AvailSetMax at particular + // point in the basic block. + for (auto I = BB->begin(), E = BB->end(); I != E; ++I) { + if (auto *LI = dyn_cast(&*I)) { + S.processLoadInst(*this, LI, RLEKind::ComputeAvailSetMax); + } + if (auto *SI = dyn_cast(&*I)) { + S.processStoreInst(*this, SI, RLEKind::ComputeAvailSetMax); + } + + S.processInstructionWithKind(*this, &*I, RLEKind::ComputeAvailGenKillSet); + } } -#endif - return true; } -bool RLEContext::run() { +void RLEContext::processBasicBlocksWithGenKillSet() { + // Process each basic block with the gen and kill set. Every time the + // ForwardSetOut of a basic block changes, the optimization is rerun on its + // successors. + llvm::SmallVector WorkList; + llvm::DenseSet HandledBBs; + + // Push into the worklist in post order so that we can pop from the back and + // get reverse post order. + for (SILBasicBlock *BB : PO->getPostOrder()) { + WorkList.push_back(BB); + HandledBBs.insert(BB); + } + while (!WorkList.empty()) { + SILBasicBlock *BB = WorkList.pop_back_val(); + HandledBBs.erase(BB); + + // Intersection. + BlockState &Forwarder = getBlockState(BB); + // Compute the ForwardSetIn at the beginning of the basic block. + Forwarder.mergePredecessorAvailSet(*this); + + if (Forwarder.processBasicBlockWithGenKillSet()) { + for (auto &X : BB->getSuccessors()) { + // We do not push basic block into the worklist if its already + // in the worklist. + if (HandledBBs.find(X) != HandledBBs.end()) + continue; + WorkList.push_back(X); + } + } + } +} + +void RLEContext::processBasicBlocksForAvailValue() { + for (SILBasicBlock *BB : PO->getReversePostOrder()) { + BlockState &Forwarder = getBlockState(BB); + + // Merge the predecessors. After merging, BlockState now contains + // lists of available LSLocations and their values that reach the + // beginning of the basic block along all paths. + Forwarder.mergePredecessorAvailSetAndValue(*this); + + // Merge duplicate loads, and forward stores to + // loads. We also update lists of stores|loads to reflect the end + // of the basic block. + Forwarder.processBasicBlockWithKind(*this, RLEKind::ComputeAvailValue); + + // Update the locations with available values. We do not need to update + // the available BitVector here as they should have been initialized and + // stabilized in the processBasicBlocksWithGenKillSet. + Forwarder.updateForwardValOut(); + } +} + +void RLEContext::processBasicBlocksForRLE() { + for (SILBasicBlock *BB : PO->getReversePostOrder()) { + BlockState &Forwarder = getBlockState(BB); + + // Merge the predecessors. After merging, BlockState now contains + // lists of available LSLocations and their values that reach the + // beginning of the basic block along all paths. + Forwarder.mergePredecessorAvailSetAndValue(*this); + + // Perform the actual redundant load elimination. + Forwarder.processBasicBlockWithKind(*this, RLEKind::PerformRLE); + + // Update the locations with available values and their values. + Forwarder.updateForwardSetOut(); + Forwarder.updateForwardValOut(); + } +} + +void RLEContext::runIterativeRLE() { + // Generate the genset and killset for every basic block. + processBasicBlocksForGenKillSet(); + // Process basic blocks in RPO. After the data flow converges, run last // iteration and perform load forwarding. - bool LastIteration = false; - bool ForwardSetChanged = false; - do { - ForwardSetChanged = false; - for (SILBasicBlock *BB : ReversePostOrder) { - BlockState &Forwarder = getBlockState(BB); - - // Merge the predecessors. After merging, BlockState now contains - // lists of available LSLocations and their values that reach the - // beginning of the basic block along all paths. - Forwarder.mergePredecessorStates(*this); - - // Merge duplicate loads, and forward stores to - // loads. We also update lists of stores|loads to reflect the end - // of the basic block. - ForwardSetChanged |= Forwarder.optimize(*this, LastIteration); - } + processBasicBlocksWithGenKillSet(); + + // We have computed the available value bit, now go through every basic + // block and compute the forwarding value locally. This is necessary as + // when we perform the RLE in the last iteration, we must handle loops, i.e. + // predecessor blocks which have not been processed when a basic block is + // processed. + processBasicBlocksForAvailValue(); +} - // Last iteration completed, we are done here. - if (LastIteration) - break; +bool RLEContext::run() { + // We perform redundant load elimination in the following phases. + // + // Phase 1. Compute the genset and killset for every basic block. + // + // Phase 2. Use an iterative data flow to compute whether there is an + // available value at a given point, we do not yet care about what the value + // is. + // + // Phase 3. we compute the real forwardable value at a given point. + // + // Phase 4. we perform the redundant load elimination. - // ForwardSetOut have not changed in any basic block. Run one last - // the data flow has converged, run last iteration and try to perform - // load forwarding. - // - if (!ForwardSetChanged) { - LastIteration = true; - } + // Walk over the function and find all the locations accessed by + // this function. + LSLocation::enumerateLSLocations(*Fn, LocationVault, LocToBitIndex, + BaseToLocIndex, TE); + + // Check how to optimize this function. + ProcessKind Kind = getProcessFunctionKind(); + + // We do not optimize this function at all. + if (Kind == ProcessKind::ProcessNone) + return false; - // ForwardSetOut in some basic blocks changed, rerun the data flow. - // - // TODO: We only need to rerun basic blocks with predecessors changed. - // use a worklist in the future. - // - } while (ForwardSetChanged || LastIteration); + // Do we run a multi-iteration data flow ? + bool MultiIteration = Kind == ProcessKind::ProcessMultipleIterations ? + true : false; + + // These are a list of basic blocks that we actually processed. + // We do not process unreachable block, instead we set their liveouts to nil. + llvm::DenseSet BBToProcess; + for (auto X : PO->getPostOrder()) + BBToProcess.insert(X); + + // For all basic blocks in the function, initialize a BB state. Since we + // know all the locations accessed in this function, we can resize the bit + // vector to the appropriate size. + for (auto &B : *Fn) { + BBToLocState[&B] = BlockState(); + BBToLocState[&B].init(&B, LocationVault.size(), MultiIteration && + BBToProcess.find(&B) != BBToProcess.end()); + } + + if (MultiIteration) + runIterativeRLE(); + + // We have the available value bit computed and the local forwarding value. + // Set up the load forwarding. + processBasicBlocksForRLE(); // Finally, perform the redundant load replacements. - llvm::DenseSet InstsToRemove; + llvm::DenseSet InstsToDelete; bool SILChanged = false; for (auto &X : BBToLocState) { for (auto &F : X.second.getRL()) { DEBUG(llvm::dbgs() << "Replacing " << SILValue(F.first) << "With " << F.second); SILChanged = true; - SILValue(F.first).replaceAllUsesWith(F.second); - InstsToRemove.insert(F.first); + F.first->replaceAllUsesWith(F.second); + InstsToDelete.insert(F.first); ++NumForwardedLoads; } } // Erase the instructions recursively, this way, we get rid of pass // dependence on DCE. - for (auto &X : InstsToRemove) { + for (auto &X : InstsToDelete) { // It is possible that the instruction still has uses, because it could be // used as the replacement Value, i.e. F.second, for some other RLE pairs. // @@ -1006,23 +1405,22 @@ namespace { class RedundantLoadElimination : public SILFunctionTransform { + StringRef getName() override { return "SIL Redundant Load Elimination"; } + /// The entry point to the transformation. void run() override { SILFunction *F = getFunction(); - DEBUG(llvm::dbgs() << "***** Redundant Load Elimination on function: " - << F->getName() << " *****\n"); + DEBUG(llvm::dbgs() << "*** RLE on function: " << F->getName() << " ***\n"); auto *AA = PM->getAnalysis(); auto *TE = PM->getAnalysis(); auto *PO = PM->getAnalysis()->get(F); - RLEContext RLE(F, AA, TE, PO->getReversePostOrder()); + RLEContext RLE(F, PM, AA, TE, PO); if (RLE.run()) { invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); } } - - StringRef getName() override { return "SIL Redundant Load Elimination"; } }; } // end anonymous namespace diff --git a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp index 648e76dc12b1c..6ce5c2499eaf7 100644 --- a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp +++ b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp @@ -1,8 +1,8 @@ -//===-- RedundantOverflowCheckRemoval.cpp ----------------------*- C++ -*-===// +//===--- RedundantOverflowCheckRemoval.cpp --------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -130,7 +130,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { // Perform a forward scan and use control flow and previously detected // overflow checks to remove the overflow checks. - // For each block in a Reverse Post Prder scan: + // For each block in a Reverse Post Order scan: for (auto &BB : ReversePostOrder) { // For each instruction: for (auto Inst = BB->begin(), End = BB->end(); Inst != End; Inst++) { @@ -232,7 +232,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { static bool isKnownPositive(SILValue N) { if (IntegerLiteralInst *NI = dyn_cast(N)) return NI->getValue().isStrictlyPositive(); - return false; + return false; } /// Return true if the absolute value of \p A is smaller than the @@ -255,6 +255,21 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { // L and R are the righthand and lefthand sides of the constraint. SILValue L = F.Left; SILValue R = F.Right; + assert(L->getType() == R->getType() && "Invalid constraint type"); + + // Make sure that the types of the constraints match the types of the + // arithmetic operation. + switch (BI->getBuiltinInfo().ID) { + default: return false; + case BuiltinValueKind::SAddOver: + case BuiltinValueKind::UAddOver: + case BuiltinValueKind::SMulOver: + case BuiltinValueKind::UMulOver: + case BuiltinValueKind::USubOver: + case BuiltinValueKind::SSubOver: + if (L->getType() != BI->getOperand(0)->getType()) + return false; + } switch (BI->getBuiltinInfo().ID) { default: return false; @@ -263,7 +278,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { if (F.Relationship == ValueRelation::SAdd) { // L + R already known to not trap at this point in the program. // And the following applies: - // L >= A and R >= B or (commutatively) R >= A and L >= B. + // L >= A and R >= B or (commutatively) R >= A and L >= B. SILValue A = BI->getOperand(0); SILValue B = BI->getOperand(1); if (knownRelation(A, L, ValueRelation::SLE) && @@ -292,7 +307,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { if (F.Relationship == ValueRelation::UAdd) { // L + R already known to not trap at this point in the program. // And the following applies: - // L >= A and R >= B or (commutatively) R >= A and L >= B. + // L >= A and R >= B or (commutatively) R >= A and L >= B. SILValue A = BI->getOperand(0); SILValue B = BI->getOperand(1); if (knownRelation(A, L, ValueRelation::ULE) && @@ -353,7 +368,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { if (F.Relationship == ValueRelation::UMul) { // L * R already known to not trap at this point in the program. // And the following applies: - // L >= A and R >= B or (commutatively) R >= A and L >= B. + // L >= A and R >= B or (commutatively) R >= A and L >= B. SILValue A = BI->getOperand(0); SILValue B = BI->getOperand(1); if (knownRelation(A, L, ValueRelation::ULE) && @@ -511,7 +526,7 @@ class RedundantOverflowCheckRemovalPass : public SILFunctionTransform { ValueRelation Rel; switch (BI->getBuiltinInfo().ID) { default: return; - case BuiltinValueKind::SAddOver: + case BuiltinValueKind::SAddOver: Rel = ValueRelation::SAdd; break; case BuiltinValueKind::UAddOver: diff --git a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp index 883e4516bfce1..b793d89386093 100644 --- a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp +++ b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp @@ -1,8 +1,8 @@ -//===---- ReleaseDevirtualizer.cpp - Devirtualizes release-instructions ---===// +//===--- ReleaseDevirtualizer.cpp - Devirtualizes release-instructions ----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -164,7 +164,7 @@ devirtualizeReleaseOfBuffer(SILInstruction *ReleaseInst, if (!IEMTI) return false; - SILType MType = IEMTI->getOperand().getType(); + SILType MType = IEMTI->getOperand()->getType(); auto *MetaType = MType.getSwiftRValueType()->getAs(); if (!MetaType) return false; @@ -213,7 +213,7 @@ bool ReleaseDevirtualizer::createDeinitCall(SILType AllocType, SILType DeinitSILType = SILType::getPrimitiveObjectType(DeinitType); SILBuilder B(ReleaseInst); - if (object.getType() != AllocType) + if (object->getType() != AllocType) object = B.createUncheckedRefCast(ReleaseInst->getLoc(), object, AllocType); // Create the call to the destructor with the allocated object as self diff --git a/lib/SILOptimizer/Transforms/RemovePin.cpp b/lib/SILOptimizer/Transforms/RemovePin.cpp index 6be17623cefe2..7e4ed06467a39 100644 --- a/lib/SILOptimizer/Transforms/RemovePin.cpp +++ b/lib/SILOptimizer/Transforms/RemovePin.cpp @@ -1,8 +1,8 @@ -//===------- RemovePin.cpp - StrongPin/Unpin removal -----*- C++ -*-------===// +//===--- RemovePin.cpp - StrongPin/Unpin removal -------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -101,8 +101,8 @@ class RemovePinInsts : public SILFunctionTransform { if (auto *Unpin = dyn_cast(CurInst)) { DEBUG(llvm::dbgs() << " Found unpin!\n"); SILValue RCId = RCIA->getRCIdentityRoot(Unpin->getOperand()); - DEBUG(llvm::dbgs() << " RCID Source: " << *RCId.getDef()); - auto *PinDef = dyn_cast(RCId.getDef()); + DEBUG(llvm::dbgs() << " RCID Source: " << *RCId); + auto *PinDef = dyn_cast(RCId); if (PinDef && AvailablePins.count(PinDef)){ DEBUG(llvm::dbgs() << " Found matching pin: " << *PinDef); SmallVector MarkDependentInsts; @@ -110,8 +110,8 @@ class RemovePinInsts : public SILFunctionTransform { DEBUG(llvm::dbgs() << " Pin users are safe! Removing!\n"); Changed = true; auto *Enum = SILBuilder(PinDef).createOptionalSome( - PinDef->getLoc(), PinDef->getOperand(), PinDef->getType(0)); - SILValue(PinDef).replaceAllUsesWith(Enum); + PinDef->getLoc(), PinDef->getOperand(), PinDef->getType()); + PinDef->replaceAllUsesWith(Enum); Unpin->eraseFromParent(); PinDef->eraseFromParent(); // Remove this pindef from AvailablePins. @@ -119,7 +119,7 @@ class RemovePinInsts : public SILFunctionTransform { ++NumPinPairsRemoved; } else { DEBUG(llvm::dbgs() - << " Pin users are not safe! Can not remove!\n"); + << " Pin users are not safe! Cannot remove!\n"); } continue; @@ -185,8 +185,8 @@ class RemovePinInsts : public SILFunctionTransform { // A mark_dependence is safe if it is marking a dependence on a base that // is the strong_pinned value. if (auto *MD = dyn_cast(U)) - if (Pin == MD->getBase().getDef() || - std::find(Users.begin(), Users.end(), MD->getBase().getDef()) != + if (Pin == MD->getBase() || + std::find(Users.begin(), Users.end(), MD->getBase()) != Users.end()) { MarkDeps.push_back(MD); continue; diff --git a/lib/SILOptimizer/Transforms/SILCleanup.cpp b/lib/SILOptimizer/Transforms/SILCleanup.cpp index 4932ad2623029..3fbea434b94d4 100644 --- a/lib/SILOptimizer/Transforms/SILCleanup.cpp +++ b/lib/SILOptimizer/Transforms/SILCleanup.cpp @@ -1,8 +1,8 @@ -//===-- SILCleanup.cpp - Removes diagnostics instructions -----------------===// +//===--- SILCleanup.cpp - Removes diagnostics instructions ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp index cd688037c7104..1572b3a0f3833 100644 --- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp @@ -1,8 +1,8 @@ -//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===// +//===--- SILCodeMotion.cpp - Code Motion Optimizations --------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -56,7 +56,7 @@ static void createRefCountOpForPayload(SILBuilder &Builder, SILInstruction *I, // argument to the refcount instruction. SILValue EnumVal = DefOfEnum ? DefOfEnum : I->getOperand(0); - SILType ArgType = EnumVal.getType().getEnumElementType(EnumDecl, Mod); + SILType ArgType = EnumVal->getType().getEnumElementType(EnumDecl, Mod); auto *UEDI = Builder.createUncheckedEnumData(I->getLoc(), EnumVal, EnumDecl, ArgType); @@ -141,7 +141,7 @@ enum OperandRelation { /// \brief Find a root value for operand \p In. This function inspects a sil /// value and strips trivial conversions such as values that are passed /// as arguments to basic blocks with a single predecessor or type casts. -/// This is a shallow one-spet search and not a deep recursive search. +/// This is a shallow one-step search and not a deep recursive search. /// /// For example, in the SIL code below, the root of %10 is %3, because it is /// the only possible incoming value. @@ -170,7 +170,7 @@ static SILValue findValueShallowRoot(const SILValue &In) { // object references. For example: func f(x : C.Type) -> Any {return x} // Here we check that the uncasted reference is reference counted. SILValue V = CCBI->getOperand(); - if (V.getType().isReferenceCounted(Pred->getParent()->getModule())) { + if (V->getType().isReferenceCounted(Pred->getParent()->getModule())) { return V; } } @@ -261,7 +261,7 @@ static llvm::Optional cheaperToPassOperandsAsArguments(SILInstruction *First, SILInstruction *Second) { // This will further enable to sink strong_retain_unowned instructions, - // which provides more opportinities for the unowned-optimization in + // which provides more opportunities for the unowned-optimization in // LLVMARCOpts. UnownedToRefInst *UTORI1 = dyn_cast(First); UnownedToRefInst *UTORI2 = dyn_cast(Second); @@ -277,7 +277,7 @@ cheaperToPassOperandsAsArguments(SILInstruction *First, return None; assert(First->getNumOperands() == Second->getNumOperands() && - First->getNumTypes() == Second->getNumTypes() && + First->getType() == Second->getType() && "Types should be identical"); llvm::Optional DifferentOperandIndex; @@ -298,7 +298,7 @@ cheaperToPassOperandsAsArguments(SILInstruction *First, // Found a different operand, now check to see if its type is something // cheap enough to sink. // TODO: Sink more than just integers. - const auto &ArgTy = First->getOperand(*DifferentOperandIndex).getType(); + const auto &ArgTy = First->getOperand(*DifferentOperandIndex)->getType(); if (!ArgTy.is()) return None; @@ -331,7 +331,7 @@ static bool sinkLiteralArguments(SILBasicBlock *BB, unsigned ArgNum) { // Check if the argument passed to the first predecessor is a literal inst. SILBasicBlock *FirstPred = *BB->pred_begin(); SILValue FirstArg = getArgForBlock(FirstPred, BB, ArgNum); - LiteralInst *FirstLiteral = dyn_cast_or_null(FirstArg.getDef()); + LiteralInst *FirstLiteral = dyn_cast_or_null(FirstArg); if (!FirstLiteral) return false; @@ -342,7 +342,7 @@ static bool sinkLiteralArguments(SILBasicBlock *BB, unsigned ArgNum) { // Check that the incoming value is identical to the first literal. SILValue PredArg = getArgForBlock(P, BB, ArgNum); - LiteralInst *PredLiteral = dyn_cast_or_null(PredArg.getDef()); + LiteralInst *PredLiteral = dyn_cast_or_null(PredArg); if (!PredLiteral || !PredLiteral->isIdenticalTo(FirstLiteral)) return false; } @@ -369,7 +369,7 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { Clones.push_back(FirstPredArg); // We only move instructions with a single use. - if (!FSI || !hasOneNonDebugUse(*FSI)) + if (!FSI || !hasOneNonDebugUse(FSI)) return false; // Don't move instructions that are sensitive to their location. @@ -398,7 +398,7 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { // Find the Nth argument passed to BB. SILValue Arg = TI->getOperand(ArgNum); SILInstruction *SI = dyn_cast(Arg); - if (!SI || !hasOneNonDebugUse(*SI)) + if (!SI || !hasOneNonDebugUse(SI)) return false; if (SI->isIdenticalTo(FSI)) { Clones.push_back(SI); @@ -423,7 +423,7 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { if (!FSI) return false; - SILValue Undef = SILUndef::get(FirstPredArg.getType(), BB->getModule()); + auto *Undef = SILUndef::get(FirstPredArg->getType(), BB->getModule()); // Delete the debug info of the instruction that we are about to sink. deleteAllDebugUses(FSI); @@ -435,9 +435,9 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { // The instruction we are lowering has an argument which is different // for each predecessor. We need to sink the instruction, then add // arguments for each predecessor. - SILValue(BB->getBBArg(ArgNum)).replaceAllUsesWith(FSI); + BB->getBBArg(ArgNum)->replaceAllUsesWith(FSI); - const auto &ArgType = FSI->getOperand(*DifferentOperandIndex).getType(); + const auto &ArgType = FSI->getOperand(*DifferentOperandIndex)->getType(); BB->replaceBBArg(ArgNum, ArgType); // Update all branch instructions in the predecessors to pass the new @@ -465,17 +465,17 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { } // Sink one of the copies of the instruction. - FirstPredArg.replaceAllUsesWith(Undef); + FirstPredArg->replaceAllUsesWith(Undef); FSI->moveBefore(&*BB->begin()); - SILValue(BB->getBBArg(ArgNum)).replaceAllUsesWith(FirstPredArg); + BB->getBBArg(ArgNum)->replaceAllUsesWith(FirstPredArg); // The argument is no longer in use. Replace all incoming inputs with undef // and try to delete the instruction. for (auto S : Clones) - if (S.getDef() != FSI) { - deleteAllDebugUses(S.getDef()); - S.replaceAllUsesWith(Undef); - auto DeadArgInst = cast(S.getDef()); + if (S != FSI) { + deleteAllDebugUses(S); + S->replaceAllUsesWith(Undef); + auto DeadArgInst = cast(S); recursivelyDeleteTriviallyDeadInstructions(DeadArgInst); } @@ -485,8 +485,8 @@ static bool sinkArgument(SILBasicBlock *BB, unsigned ArgNum) { /// Try to sink literals that are passed to arguments that are coming from /// multiple predecessors. -/// Notice that unline other sinking methods in this file we do allow sinking -/// of literals from blocks with multiple sucessors. +/// Notice that unlike other sinking methods in this file we do allow sinking +/// of literals from blocks with multiple successors. static bool sinkLiteralsFromPredecessors(SILBasicBlock *BB) { if (BB->pred_empty() || BB->getSinglePredecessor()) return false; @@ -766,7 +766,7 @@ static bool tryToSinkRefCountAcrossSelectEnum(CondBranchInst *CondBr, // If the enum only has 2 values and its tag isn't the true branch, then we // know the true branch must be the other tag. EnumElementDecl *Elts[2] = {TrueElement.get(), nullptr}; - EnumDecl *E = SEI->getEnumOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *E = SEI->getEnumOperand()->getType().getEnumOrBoundGenericEnum(); if (!E) return false; @@ -812,7 +812,7 @@ static bool tryToSinkRefCountInst(SILBasicBlock::iterator T, // successor. if (CanSinkToSuccessors) { // If we have a switch, try to sink ref counts across it and then return - // that result. We do not keep processing since the code below can not + // that result. We do not keep processing since the code below cannot // properly sink ref counts over switch_enums so we might as well exit // early. if (auto *S = dyn_cast(T)) @@ -838,7 +838,7 @@ static bool tryToSinkRefCountInst(SILBasicBlock::iterator T, } // Ok, we have a ref count instruction that *could* be sunk. If we have a - // terminator that we can not sink through or the cfg will not let us sink + // terminator that we cannot sink through or the cfg will not let us sink // into our predecessors, just move the increment before the terminator. if (!CanSinkToSuccessors || (!isa(T) && !isa(T))) { @@ -849,7 +849,7 @@ static bool tryToSinkRefCountInst(SILBasicBlock::iterator T, // Ok, it is legal for us to sink this increment to our successors. Create a // copy of this instruction in each one of our successors unless they are - // ignoreable trap blocks. + // ignorable trap blocks. DEBUG(llvm::dbgs() << " Sinking " << *I); SILBuilderWithScope Builder(T, &*I); for (auto &Succ : T->getParent()->getSuccessors()) { @@ -896,9 +896,9 @@ static bool isRetainAvailableInSomeButNotAllPredecessors( }); // Check that there is no decrement or check from the increment to the end - // of the basic block. After we have hoisted the first release this release + // of the basic block. After we have hoisted the first release this release // would prevent further hoisting. Instead we check that no decrement or - // check occurs upto this hoisted release. + // check occurs up to this hoisted release. auto End = CheckUpToInstruction[Pred]; auto EndIt = SILBasicBlock::iterator(End ? *End : Pred->getTerminator()); if (Retain == Pred->rend() || valueHasARCDecrementOrCheckInInstructionRange( @@ -945,7 +945,7 @@ static bool hoistDecrementsToPredecessors(SILBasicBlock *BB, AliasAnalysis *AA, SILValue Ptr = Inst->getOperand(0); // The pointer must be defined outside of this basic block. - if (Ptr.getDef()->getParentBB() == BB) + if (Ptr->getParentBB() == BB) continue; // No arc use to the beginning of this block. @@ -981,7 +981,7 @@ static bool hoistDecrementsToPredecessors(SILBasicBlock *BB, AliasAnalysis *AA, return HoistedDecrement; } -/// Try sink a retain as far as possible. This is either to sucessor BBs, +/// Try sink a retain as far as possible. This is either to successor BBs, /// or as far down the current BB as possible static bool sinkRefCountIncrement(SILBasicBlock *BB, AliasAnalysis *AA, RCIdentityFunctionInfo *RCIA) { @@ -1068,9 +1068,6 @@ class BBEnumTagDataflowState using iterator = decltype(ValueToCaseMap)::iterator; iterator begin() { return ValueToCaseMap.getItems().begin(); } iterator end() { return ValueToCaseMap.getItems().begin(); } - iterator_range currentTrackedState() { - return ValueToCaseMap.getItems(); - } void clear() { ValueToCaseMap.clear(); } @@ -1203,7 +1200,7 @@ void BBEnumTagDataflowState::handlePredCondSelectEnum(CondBranchInst *CondBr) { // If the enum only has 2 values and its tag isn't the true branch, then we // know the true branch must be the other tag. - if (EnumDecl *E = Operand.getType().getEnumOrBoundGenericEnum()) { + if (EnumDecl *E = Operand->getType().getEnumOrBoundGenericEnum()) { // Look for a single other element on this enum. EnumElementDecl *OtherElt = nullptr; for (EnumElementDecl *Elt : E->getAllElements()) { @@ -1282,7 +1279,7 @@ void BBEnumTagDataflowState:: mergePredecessorStates(BBToDataflowStateMap &BBToStateMap) { - // If we have no precessors, there is nothing to do so return early... + // If we have no predecessors, there is nothing to do so return early... if (getBB()->pred_empty()) { DEBUG(llvm::dbgs() << " No Preds.\n"); return; @@ -1323,7 +1320,7 @@ mergePredecessorStates(BBToDataflowStateMap &BBToStateMap) { llvm::SmallVector CurBBValuesToBlot; // If we do not find state for a specific value in any of our predecessor BBs, - // we can not be the end of a switch region since we can not cover our + // we cannot be the end of a switch region since we cannot cover our // predecessor BBs with enum decls. Blot after the loop. llvm::SmallVector PredBBValuesToBlot; @@ -1357,9 +1354,9 @@ mergePredecessorStates(BBToDataflowStateMap &BBToStateMap) { // the predecessor we are processing. auto PredValue = PredBBState->ValueToCaseMap.find(P->first); - // If we can not find the state associated with this SILValue in this + // If we cannot find the state associated with this SILValue in this // predecessor or the value in the corresponding predecessor was blotted, - // we can not find a covering switch for this BB or forward any enum tag + // we cannot find a covering switch for this BB or forward any enum tag // information for this enum value. if (PredValue == PredBBState->ValueToCaseMap.end() || !(*PredValue)->first) { // Otherwise, we are conservative and do not forward the EnumTag that we @@ -1371,7 +1368,7 @@ mergePredecessorStates(BBToDataflowStateMap &BBToStateMap) { } // Check if out predecessor has any other successors. If that is true we - // clear all the state since we can not hoist safely. + // clear all the state since we cannot hoist safely. if (!PredBB->getSingleSuccessor()) { EnumToEnumBBCaseListMap.clear(); DEBUG(llvm::dbgs() << " Predecessor has other " @@ -1497,9 +1494,9 @@ BBEnumTagDataflowState::hoistDecrementsIntoSwitchRegions(AliasAnalysis *AA) { } // Finally ensure that we have no users of this operand preceding the - // release_value in this BB. If we have users like that we can not hoist the + // release_value in this BB. If we have users like that we cannot hoist the // release past them unless we know that there is an additional set of - // releases that together post-dominate this release. If we can not do this, + // releases that together post-dominate this release. If we cannot do this, // skip this release. // // TODO: We need information from the ARC optimizer to prove that property @@ -1525,7 +1522,7 @@ BBEnumTagDataflowState::hoistDecrementsIntoSwitchRegions(AliasAnalysis *AA) { // Otherwise create the release_value before the terminator of the // predecessor. assert(P.first->getSingleSuccessor() && - "Can not hoist release into BB that has multiple successors"); + "Cannot hoist release into BB that has multiple successors"); SILBuilderWithScope Builder(P.first->getTerminator(), RVI); createRefCountOpForPayload(Builder, RVI, P.second); } @@ -1563,7 +1560,7 @@ findLastSinkableMatchingEnumValueRCIncrementInPred(AliasAnalysis *AA, // Otherwise, see if there are any instructions in between FirstPredInc and // the end of the given basic block that could decrement first pred. If such - // an instruction exists, we can not perform this optimization so continue. + // an instruction exists, we cannot perform this optimization so continue. if (valueHasARCDecrementOrCheckInInstructionRange( EnumValue, (*FirstInc).getIterator(), BB->getTerminator()->getIterator(), AA)) diff --git a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp index 8a00439a94969..4b0af0d0b8910 100644 --- a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp +++ b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp @@ -1,8 +1,8 @@ -//===- SILLowerAggregateInstrs.cpp - Aggregate insts to Scalar insts -----===// +//===--- SILLowerAggregateInstrs.cpp - Aggregate insts to Scalar insts ---===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -74,7 +74,7 @@ static bool expandCopyAddr(CopyAddrInst *CA) { SILValue Source = CA->getSrc(); // If we have an address only type don't do anything. - SILType SrcType = Source.getType(); + SILType SrcType = Source->getType(); if (SrcType.isAddressOnly(M)) return false; @@ -137,7 +137,7 @@ static bool expandDestroyAddr(DestroyAddrInst *DA) { SILValue Addr = DA->getOperand(); // If we have an address only type, do nothing. - SILType Type = Addr.getType(); + SILType Type = Addr->getType(); if (Type.isAddressOnly(Module)) return false; @@ -156,14 +156,14 @@ static bool expandDestroyAddr(DestroyAddrInst *DA) { static bool expandReleaseValue(ReleaseValueInst *DV) { SILModule &Module = DV->getModule(); - SILBuilderWithScope Builder(DV); + SILBuilderWithScope Builder(DV); // Strength reduce destroy_addr inst into release/store if // we have a non-address only type. SILValue Value = DV->getOperand(); // If we have an address only type, do nothing. - SILType Type = Value.getType(); + SILType Type = Value->getType(); assert(Type.isLoadable(Module) && "release_value should never be called on a non-loadable type."); @@ -186,7 +186,7 @@ static bool expandRetainValue(RetainValueInst *CV) { SILValue Value = CV->getOperand(); // If we have an address only type, do nothing. - SILType Type = Value.getType(); + SILType Type = Value->getType(); assert(Type.isLoadable(Module) && "Copy Value can only be called on loadable " "types."); diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp index b0db56610b053..aa4e703f9242b 100644 --- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp +++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -217,7 +217,7 @@ static bool isCaptured(AllocStackInst *ASI, bool &inSingleBlock) { // We can store into an AllocStack (but not the pointer). if (StoreInst *SI = dyn_cast(II)) - if (SI->getDest().getDef() == ASI) + if (SI->getDest() == ASI) continue; // Deallocation is also okay, as are DebugValueAddr. We will turn @@ -228,7 +228,7 @@ static bool isCaptured(AllocStackInst *ASI, bool &inSingleBlock) { // Destroys of loadable types can be rewritten as releases, so // they are fine. if (auto *DAI = dyn_cast(II)) - if (DAI->getOperand().getType().isLoadable(DAI->getModule())) + if (DAI->getOperand()->getType().isLoadable(DAI->getModule())) continue; // Other instructions are assumed to capture the AllocStack. @@ -265,7 +265,7 @@ bool MemoryToRegisters::isWriteOnlyAllocation(AllocStackInst *ASI, // Destroys of loadable types can be rewritten as releases, so // they are fine. if (auto *DAI = dyn_cast(II)) - if (!Promoted && DAI->getOperand().getType().isLoadable(DAI->getModule())) + if (!Promoted && DAI->getOperand()->getType().isLoadable(DAI->getModule())) continue; // Can't do anything else with it. @@ -279,7 +279,7 @@ bool MemoryToRegisters::isWriteOnlyAllocation(AllocStackInst *ASI, /// Promote a DebugValueAddr to a DebugValue of the given value. static void promoteDebugValueAddr(DebugValueAddrInst *DVAI, SILValue Value, SILBuilder &B) { - assert(Value.isValid() && "Expected valid value"); + assert(Value && "Expected valid value"); B.setInsertionPoint(DVAI); B.setCurrentDebugScope(DVAI->getDebugScope()); B.createDebugValue(DVAI->getLoc(), Value, DVAI->getVarInfo()); @@ -292,12 +292,12 @@ static bool isLoadFromStack(SILInstruction *I, AllocStackInst *ASI) { return false; // Skip struct and tuple address projections. - ValueBase *op = I->getOperand(0).getDef(); + ValueBase *op = I->getOperand(0); while (op != ASI) { if (!isa(op) && !isa(op)) return false; - op = cast(op)->getOperand(0).getDef(); + op = cast(op)->getOperand(0); } return true; } @@ -321,7 +321,7 @@ static void collectLoads(SILInstruction *I, SmallVectorImpl &Loads) static void replaceLoad(LoadInst *LI, SILValue val, AllocStackInst *ASI) { ProjectionPath projections; SILValue op = LI->getOperand(); - while (op.getDef() != ASI) { + while (op != ASI) { assert(isa(op) || isa(op)); SILInstruction *Inst = cast(op); auto projection = Projection::addressProjectionForInstruction(Inst); @@ -334,9 +334,9 @@ static void replaceLoad(LoadInst *LI, SILValue val, AllocStackInst *ASI) { val = projection.createValueProjection(builder, LI->getLoc(), val).get(); } op = LI->getOperand(); - SILValue(LI, 0).replaceAllUsesWith(val); + LI->replaceAllUsesWith(val); LI->eraseFromParent(); - while (op.getDef() != ASI && op.use_empty()) { + while (op != ASI && op->use_empty()) { assert(isa(op) || isa(op)); SILInstruction *Inst = cast(op); SILValue next = Inst->getOperand(0); @@ -346,14 +346,14 @@ static void replaceLoad(LoadInst *LI, SILValue val, AllocStackInst *ASI) { } static void replaceDestroy(DestroyAddrInst *DAI, SILValue NewValue) { - assert(DAI->getOperand().getType().isLoadable(DAI->getModule()) && + assert(DAI->getOperand()->getType().isLoadable(DAI->getModule()) && "Unexpected promotion of address-only type!"); - assert(NewValue.isValid() && "Expected a value to release!"); + assert(NewValue && "Expected a value to release!"); SILBuilderWithScope Builder(DAI); - auto Ty = DAI->getOperand().getType(); + auto Ty = DAI->getOperand()->getType(); auto &TL = DAI->getModule().getTypeLowering(Ty); TL.emitLoweredReleaseValue(Builder, DAI->getLoc(), NewValue, Lowering::TypeLowering::LoweringStyle::DeepNoEnum); @@ -375,14 +375,14 @@ StackAllocationPromoter::promoteAllocationInBlock(SILBasicBlock *BB) { ++BBI; if (isLoadFromStack(Inst, ASI)) { - if (RunningVal.isValid()) { + if (RunningVal) { // If we are loading from the AllocStackInst and we already know the // content of the Alloca then use it. DEBUG(llvm::dbgs() << "*** Promoting load: " << *Inst); replaceLoad(cast(Inst), RunningVal, ASI); NumInstRemoved++; - } else if (Inst->getOperand(0).getDef() == ASI) { + } else if (Inst->getOperand(0) == ASI) { // If we don't know the content of the AllocStack then the loaded // value *is* the new value; DEBUG(llvm::dbgs() << "*** First load: " << *Inst); @@ -394,7 +394,7 @@ StackAllocationPromoter::promoteAllocationInBlock(SILBasicBlock *BB) { // Remove stores and record the value that we are saving as the running // value. if (StoreInst *SI = dyn_cast(Inst)) { - if (SI->getDest().getDef() != ASI) + if (SI->getDest() != ASI) continue; // The stored value is the new running value. @@ -414,16 +414,16 @@ StackAllocationPromoter::promoteAllocationInBlock(SILBasicBlock *BB) { // if we have a valid value to use at this point. Otherwise we'll // promote this when we deal with hooking up phis. if (auto *DVAI = dyn_cast(Inst)) { - if (DVAI->getOperand() == ASI->getAddressResult() && - RunningVal.isValid()) + if (DVAI->getOperand() == ASI && + RunningVal) promoteDebugValueAddr(DVAI, RunningVal, B); continue; } // Replace destroys with a release of the value. if (auto *DAI = dyn_cast(Inst)) { - if (DAI->getOperand() == ASI->getAddressResult() && - RunningVal.isValid()) { + if (DAI->getOperand() == ASI && + RunningVal) { replaceDestroy(DAI, RunningVal); } continue; @@ -460,7 +460,7 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) { // Remove instructions that we are loading from. Replace the loaded value // with our running value. if (isLoadFromStack(Inst, ASI)) { - if (!RunningVal.isValid()) { + if (!RunningVal) { assert(ASI->getElementType().isVoid() && "Expected initialization of non-void type!"); RunningVal = SILUndef::get(ASI->getElementType(), ASI->getModule()); @@ -473,7 +473,7 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) { // Remove stores and record the value that we are saving as the running // value. if (StoreInst *SI = dyn_cast(Inst)) { - if (SI->getDest().getDef() == ASI) { + if (SI->getDest() == ASI) { RunningVal = SI->getSrc(); Inst->eraseFromParent(); NumInstRemoved++; @@ -483,8 +483,8 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) { // Replace debug_value_addr with debug_value of the promoted value. if (auto *DVAI = dyn_cast(Inst)) { - if (DVAI->getOperand() == ASI->getAddressResult()) { - if (RunningVal.isValid()) { + if (DVAI->getOperand() == ASI) { + if (RunningVal) { promoteDebugValueAddr(DVAI, RunningVal, B); } else { // Drop debug_value_addr of uninitialized void values. @@ -498,7 +498,7 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *ASI) { // Replace destroys with a release of the value. if (auto *DAI = dyn_cast(Inst)) { - if (DAI->getOperand() == ASI->getAddressResult()) { + if (DAI->getOperand() == ASI) { replaceDestroy(DAI, RunningVal); } continue; @@ -846,29 +846,29 @@ bool MemoryToRegisters::run() { continue; } - // For AllocStacks that are only used within a single basic blocks, use - // the linear sweep to remove the AllocStack. - if (inSingleBlock) { - removeSingleBlockAllocation(ASI); + // Remove write-only AllocStacks. + if (isWriteOnlyAllocation(ASI)) { + eraseUsesOfInstruction(ASI); - DEBUG(llvm::dbgs() << "*** Deleting single block AllocStackInst: " - << *ASI); + DEBUG(llvm::dbgs() << "*** Deleting store-only AllocStack: " << *ASI); I++; ASI->eraseFromParent(); - NumInstRemoved++; Changed = true; + NumInstRemoved++; continue; } - // Remove write-only AllocStacks. - if (isWriteOnlyAllocation(ASI)) { - eraseUsesOfInstruction(ASI); + // For AllocStacks that are only used within a single basic blocks, use + // the linear sweep to remove the AllocStack. + if (inSingleBlock) { + removeSingleBlockAllocation(ASI); - DEBUG(llvm::dbgs() << "*** Deleting store-only AllocStack: " << *ASI); + DEBUG(llvm::dbgs() << "*** Deleting single block AllocStackInst: " + << *ASI); I++; ASI->eraseFromParent(); - Changed = true; NumInstRemoved++; + Changed = true; continue; } diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp index 82b6e1f1fce97..23ed9d1812582 100644 --- a/lib/SILOptimizer/Transforms/SILSROA.cpp +++ b/lib/SILOptimizer/Transforms/SILSROA.cpp @@ -1,8 +1,8 @@ -//===-- SILSROA.cpp - Scalar Replacement of Aggregates -------------------===// +//===--- SILSROA.cpp - Scalar Replacement of Aggregates ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -47,8 +47,6 @@ class SROAMemoryUseAnalyzer { llvm::SmallVector Loads; // Stores to AI. llvm::SmallVector Stores; - // Dealloc instructions for AI. - llvm::SmallVector Deallocs; // Instructions which extract from aggregates. llvm::SmallVector ExtractInsts; @@ -125,7 +123,7 @@ unsigned SROAMemoryUseAnalyzer::getEltNoForProjection(SILInstruction *Inst) { bool SROAMemoryUseAnalyzer::analyze() { // We only know how to split structs and tuples... So if we have a scalar or a // different sort of aggregate, bail. - SILType Type = SILValue(AI, 1).getType(); + SILType Type = AI->getType(); TT = Type.getAs(); SD = Type.getStructOrBoundGenericStruct(); @@ -139,14 +137,14 @@ bool SROAMemoryUseAnalyzer::analyze() { } // Go through uses of the memory allocation of AI... - for (auto *Operand : getNonDebugUses(SILValue(AI, 1))) { + for (auto *Operand : getNonDebugUses(SILValue(AI))) { SILInstruction *User = Operand->getUser(); DEBUG(llvm::dbgs() << " Visiting use: " << *User); - // If we store the alloca pointer, we can not analyze its uses so bail... + // If we store the alloca pointer, we cannot analyze its uses so bail... // It is ok if we store into the alloca pointer though. if (auto *SI = dyn_cast(User)) { - if (SI->getDest().getDef() == AI) { + if (SI->getDest() == AI) { DEBUG(llvm::dbgs() << " Found a store into the " "projection.\n"); Stores.push_back(SI); @@ -182,6 +180,11 @@ bool SROAMemoryUseAnalyzer::analyze() { continue; } + if (isa(User)) { + // We can ignore the dealloc_stack. + continue; + } + // Otherwise we do not understand this instruction, so bail. DEBUG(llvm::dbgs() << " Found unknown user, pointer escapes!\n"); ++NumEscapingAllocas; @@ -197,7 +200,7 @@ void SROAMemoryUseAnalyzer:: createAllocas(llvm::SmallVector &NewAllocations) { SILBuilderWithScope B(AI); - SILType Type = AI->getType(1).getObjectType(); + SILType Type = AI->getType().getObjectType(); if (TT) { for (unsigned EltNo : indices(TT->getElementTypes())) { @@ -230,10 +233,10 @@ void SROAMemoryUseAnalyzer::chopUpAlloca(std::vector &Worklist SILBuilderWithScope B(LI); llvm::SmallVector Elements; for (auto *NewAI : NewAllocations) - Elements.push_back(B.createLoad(LI->getLoc(), SILValue(NewAI, 1))); + Elements.push_back(B.createLoad(LI->getLoc(), NewAI)); auto *Agg = createAgg(B, LI->getLoc(), LI->getType().getObjectType(), Elements); - SILValue(LI).replaceAllUsesWith(Agg); + LI->replaceAllUsesWith(Agg); LI->eraseFromParent(); } @@ -243,21 +246,20 @@ void SROAMemoryUseAnalyzer::chopUpAlloca(std::vector &Worklist for (unsigned EltNo : indices(NewAllocations)) B.createStore(SI->getLoc(), createAggProjection(B, SI->getLoc(), SI->getSrc(), EltNo), - SILValue(NewAllocations[EltNo], 1)); + NewAllocations[EltNo]); SI->eraseFromParent(); } // Forward any field extracts to the new allocation. for (auto *Ext : ExtractInsts) { - SILValue NewValue = SILValue(NewAllocations[getEltNoForProjection(Ext)], 1); - SILValue(Ext).replaceAllUsesWith(NewValue); + AllocStackInst *NewValue = NewAllocations[getEltNoForProjection(Ext)]; + Ext->replaceAllUsesWith(NewValue); Ext->eraseFromParent(); } - // Find all dealloc instruction that touch the local storage handle for AI - // and then chop them up. + // Find all dealloc instructions for AI and then chop them up. llvm::SmallVector ToRemove; - for (auto *Operand : getNonDebugUses(SILValue(AI, 0))) { + for (auto *Operand : getNonDebugUses(SILValue(AI))) { SILInstruction *User = Operand->getUser(); SILBuilderWithScope B(User); diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 6a1b428d6e280..d67373c7af6de 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,8 +18,10 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CFG.h" #include "swift/SILOptimizer/Utils/Local.h" @@ -35,6 +37,7 @@ using namespace swift; STATISTIC(NumBlocksDeleted, "Number of unreachable blocks removed"); STATISTIC(NumBlocksMerged, "Number of blocks merged together"); STATISTIC(NumJumpThreads, "Number of jumps threaded"); +STATISTIC(NumTermBlockSimplified, "Number of programterm block simplified"); STATISTIC(NumConstantFolded, "Number of terminators constant folded"); STATISTIC(NumDeadArguments, "Number of unused arguments removed"); STATISTIC(NumSROAArguments, "Number of aggregate argument levels split by " @@ -44,7 +47,7 @@ STATISTIC(NumSROAArguments, "Number of aggregate argument levels split by " // CFG Simplification //===----------------------------------------------------------------------===// -/// dominatorBasedSimplify iterates between dominator based simplifation of +/// dominatorBasedSimplify iterates between dominator based simplification of /// terminator branch condition values and cfg simplification. This is the /// maximum number of iterations we run. The number is the maximum number of /// iterations encountered when compiling the stdlib on April 2 2015. @@ -169,6 +172,7 @@ namespace { bool simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI); bool simplifySwitchEnumBlock(SwitchEnumInst *SEI); bool simplifyUnreachableBlock(UnreachableInst *UI); + bool simplifyProgramTerminationBlock(SILBasicBlock *BB); bool simplifyArgument(SILBasicBlock *BB, unsigned i); bool simplifyArgs(SILBasicBlock *BB); bool trySimplifyCheckedCastBr(TermInst *Term, DominanceInfo *DT); @@ -187,7 +191,7 @@ namespace { /// Return true if there are any users of V outside the specified block. static bool isUsedOutsideOfBlock(SILValue V, SILBasicBlock *BB) { - for (auto UI : V.getUses()) + for (auto UI : V->getUses()) if (UI->getUser()->getParent() != BB) return true; return false; @@ -209,25 +213,16 @@ void swift::updateSSAAfterCloning(BaseThreadingCloner &Cloner, if (Inst->use_empty()) continue; - for (unsigned i = 0, e = Inst->getNumTypes(); i != e; ++i) { - // Get the result index for the cloned instruction. This is going to be - // the result index stored in the available value for arguments (we look - // through the phi node) and the same index as the original value - // otherwise. - unsigned ResIdx = i; - if (isa(Inst)) - ResIdx = AvailValPair.second.getResultNumber(); - - SILValue Res(Inst, i); - SILValue NewRes(AvailValPair.second.getDef(), ResIdx); + if (Inst->hasValue()) { + SILValue NewRes(AvailValPair.second); SmallVector UseList; // Collect the uses of the value. - for (auto Use : Res.getUses()) + for (auto Use : Inst->getUses()) UseList.push_back(UseWrapper(Use)); - SSAUp.Initialize(Res.getType()); - SSAUp.AddAvailableValue(DestBB, Res); + SSAUp.Initialize(Inst->getType()); + SSAUp.AddAvailableValue(DestBB, Inst); SSAUp.AddAvailableValue(SrcBB, NewRes); if (UseList.empty()) @@ -273,7 +268,7 @@ SimplifyCFG::trySimplifyCheckedCastBr(TermInst *Term, DominanceInfo *DT) { static SILValue getTerminatorCondition(TermInst *Term) { if (auto *CondBr = dyn_cast(Term)) - return CondBr->getCondition().stripExpectIntrinsic(); + return stripExpectIntrinsic(CondBr->getCondition()); if (auto *SEI = dyn_cast(Term)) return SEI->getOperand(); @@ -379,12 +374,12 @@ class ThreadInfo { SILBuilderWithScope Builder(SEI); if (!ThreadedSuccessorBlock->bbarg_empty()) { auto EnumVal = SEI->getOperand(); - auto EnumTy = EnumVal->getType(0); + auto EnumTy = EnumVal->getType(); auto Loc = SEI->getLoc(); auto Ty = EnumTy.getEnumElementType(EnumCase, SEI->getModule()); SILValue UED( Builder.createUncheckedEnumData(Loc, EnumVal, EnumCase, Ty)); - assert(UED.getType() == + assert(UED->getType() == (*ThreadedSuccessorBlock->bbarg_begin())->getType() && "Argument types must match"); Builder.createBranch(SEI->getLoc(), ThreadedSuccessorBlock, {UED}); @@ -420,13 +415,13 @@ static bool isKnownEdgeValue(TermInst *Term, SILBasicBlock *SuccBB, return SuccBB->getSinglePredecessor() != nullptr; } -/// Create a enum element by extracting the operand of a switch_enum. +/// Create an enum element by extracting the operand of a switch_enum. static SILInstruction *createEnumElement(SILBuilder &Builder, SwitchEnumInst *SEI, EnumElementDecl *EnumElement) { auto EnumVal = SEI->getOperand(); // Do we have a payload. - auto EnumTy = EnumVal->getType(0); + auto EnumTy = EnumVal->getType(); if (EnumElement->hasArgumentType()) { auto Ty = EnumTy.getEnumElementType(EnumElement, SEI->getModule()); SILValue UED(Builder.createUncheckedEnumData(SEI->getLoc(), EnumVal, @@ -445,7 +440,7 @@ static SILInstruction *createValueForEdge(SILInstruction *UserInst, if (auto *CBI = dyn_cast(DominatingTerminator)) return Builder.createIntegerLiteral( - CBI->getLoc(), CBI->getCondition().getType(), EdgeIdx == 0 ? -1 : 0); + CBI->getLoc(), CBI->getCondition()->getType(), EdgeIdx == 0 ? -1 : 0); auto *SEI = cast(DominatingTerminator); auto *DstBlock = SEI->getSuccessors()[EdgeIdx].getBB(); @@ -454,7 +449,7 @@ static SILInstruction *createValueForEdge(SILInstruction *UserInst, return createEnumElement(Builder, SEI, Case.get()); } -/// Peform dominator based value simplifications and jump threading on all users +/// Perform dominator based value simplifications and jump threading on all users /// of the operand of 'DominatingBB's terminator. static bool tryDominatorBasedSimplifications( SILBasicBlock *DominatingBB, DominanceInfo *DT, @@ -519,7 +514,7 @@ static bool tryDominatorBasedSimplifications( // DestBB // cond_br %dominating_cond SmallVector UsersToReplace; - for (auto *Op : ignore_expect_uses(DominatingCondition.getDef())) { + for (auto *Op : ignore_expect_uses(DominatingCondition)) { auto *CondUserInst = Op->getUser(); // Ignore the DominatingTerminator itself. @@ -584,7 +579,7 @@ static bool tryDominatorBasedSimplifications( for (auto *UserInst : UsersToReplace) { SILInstruction *EdgeValue = nullptr; for (auto &Op : UserInst->getAllOperands()) { - if (Op.get().stripExpectIntrinsic() == DominatingCondition) { + if (stripExpectIntrinsic(Op.get()) == DominatingCondition) { if (!EdgeValue) EdgeValue = createValueForEdge(UserInst, DominatingTerminator, Idx); Op.set(EdgeValue); @@ -966,7 +961,7 @@ bool SimplifyCFG::simplifyBranchOperands(OperandValueArrayRef Operands) { for (auto O = Operands.begin(), E = Operands.end(); O != E; ++O) if (auto *I = dyn_cast(*O)) if (SILValue Result = simplifyInstruction(I)) { - SILValue(I, 0).replaceAllUsesWith(Result.getDef()); + I->replaceAllUsesWith(Result); if (isInstructionTriviallyDead(I)) { eraseFromParentWithDebugInsts(I); Simplified = true; @@ -1059,7 +1054,8 @@ static bool isReachable(SILBasicBlock *Block) { return true; for (auto &Succ : CurBB->getSuccessors()) - if (!Visited.insert(Succ).second) + // Second is true if the insertion took place. + if (Visited.insert(Succ).second) Worklist.push_back(Succ); } @@ -1082,8 +1078,8 @@ bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) { // If there are any BB arguments in the destination, replace them with the // branch operands, since they must dominate the dest block. for (unsigned i = 0, e = BI->getArgs().size(); i != e; ++i) { - if (DestBB->getBBArg(i) != BI->getArg(i).getDef()) - SILValue(DestBB->getBBArg(i)).replaceAllUsesWith(BI->getArg(i)); + if (DestBB->getBBArg(i) != BI->getArg(i)) + DestBB->getBBArg(i)->replaceAllUsesWith(BI->getArg(i)); else { // We must be processing an unreachable part of the cfg with a cycle. // bb1(arg1): // preds: bb3 @@ -1197,7 +1193,7 @@ static SILValue skipInvert(SILValue Cond, bool &Inverted, /// \brief Returns the first cond_fail if it is the first side-effect /// instruction in this block. -static CondFailInst *getFistCondFail(SILBasicBlock *BB) { +static CondFailInst *getFirstCondFail(SILBasicBlock *BB) { auto It = BB->begin(); CondFailInst *CondFail = nullptr; // Skip instructions that don't have side-effects. @@ -1216,7 +1212,7 @@ static CondFailInst *getFistCondFail(SILBasicBlock *BB) { /// If \p Inverted is true, \p BB is on the false-edge of the cond_br. static CondFailInst *getUnConditionalFail(SILBasicBlock *BB, SILValue Cond, bool Inverted) { - CondFailInst *CondFail = getFistCondFail(BB); + CondFailInst *CondFail = getFirstCondFail(BB); if (!CondFail) return nullptr; @@ -1239,9 +1235,9 @@ static CondFailInst *getUnConditionalFail(SILBasicBlock *BB, SILValue Cond, static void createCondFail(CondFailInst *Orig, SILValue Cond, bool inverted, SILBuilder &Builder) { if (inverted) { - auto *True = Builder.createIntegerLiteral(Orig->getLoc(), Cond.getType(), 1); + auto *True = Builder.createIntegerLiteral(Orig->getLoc(), Cond->getType(), 1); Cond = Builder.createBuiltinBinaryFunction(Orig->getLoc(), "xor", - Cond.getType(), Cond.getType(), + Cond->getType(), Cond->getType(), {Cond, True}); } Builder.createCondFail(Orig->getLoc(), Cond); @@ -1261,7 +1257,7 @@ static SILValue invertExpectAndApplyTo(SILBuilder &Builder, if (!IL) return V; SILValue NegatedExpectedValue = Builder.createIntegerLiteral( - IL->getLoc(), Args[1].getType(), IL->getValue() == 0 ? -1 : 0); + IL->getLoc(), Args[1]->getType(), IL->getValue() == 0 ? -1 : 0); return Builder.createBuiltin(BI->getLoc(), BI->getName(), BI->getType(), {}, {V, NegatedExpectedValue}); } @@ -1300,7 +1296,7 @@ bool SimplifyCFG::simplifyCondBrBlock(CondBranchInst *BI) { // This looks through expect intrinsic calls and applies the ultimate expect // call inverted to the condition. if (auto *Xor = - dyn_cast(BI->getCondition().stripExpectIntrinsic())) { + dyn_cast(stripExpectIntrinsic(BI->getCondition()))) { if (Xor->getBuiltinInfo().ID == BuiltinValueKind::Xor) { // Check if it's a boolean inversion of the condition. OperandValueArrayRef Args = Xor->getArguments(); @@ -1399,7 +1395,7 @@ bool SimplifyCFG::simplifyCondBrBlock(CondBranchInst *BI) { // select_enum with the first case and swap our operands. This simplifies // later dominance based processing. if (auto *SEI = dyn_cast(BI->getCondition())) { - EnumDecl *E = SEI->getEnumOperand().getType().getEnumOrBoundGenericEnum(); + EnumDecl *E = SEI->getEnumOperand()->getType().getEnumOrBoundGenericEnum(); auto AllElts = E->getAllElements(); auto Iter = AllElts.begin(); @@ -1540,7 +1536,7 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { } auto &Mod = SEI->getModule(); - auto OpndTy = SEI->getOperand()->getType(0); + auto OpndTy = SEI->getOperand()->getType(); auto Ty = OpndTy.getEnumElementType(Element, Mod); auto *UED = SILBuilderWithScope(SEI) .createUncheckedEnumData(SEI->getLoc(), SEI->getOperand(), Element, Ty); @@ -1557,7 +1553,7 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { } /// simplifySwitchEnumBlock - Simplify a basic block that ends with a -/// switch_enum instruction that gets its operand from a an enum +/// switch_enum instruction that gets its operand from an enum /// instruction. bool SimplifyCFG::simplifySwitchEnumBlock(SwitchEnumInst *SEI) { auto *EI = dyn_cast(SEI->getOperand()); @@ -1600,7 +1596,7 @@ bool SimplifyCFG::simplifySwitchEnumBlock(SwitchEnumInst *SEI) { } /// simplifySwitchValueBlock - Simplify a basic block that ends with a -/// switch_value instruction that gets its operand from a an integer +/// switch_value instruction that gets its operand from an integer /// literal instruction. bool SimplifyCFG::simplifySwitchValueBlock(SwitchValueInst *SVI) { auto *ThisBB = SVI->getParent(); @@ -1692,11 +1688,10 @@ bool SimplifyCFG::simplifyUnreachableBlock(UnreachableInst *UI) { } } - for (unsigned i = 0, e = MaybeDead->getNumTypes(); i != e; ++i) - if (!SILValue(&*MaybeDead, i).use_empty()) { - auto Undef = SILUndef::get(MaybeDead->getType(i), BB->getModule()); - SILValue(&*MaybeDead, i).replaceAllUsesWith(Undef); - } + if (!MaybeDead->use_empty()) { + auto Undef = SILUndef::get(MaybeDead->getType(), BB->getModule()); + MaybeDead->replaceAllUsesWith(Undef); + } DeadInstrs.push_back(&*MaybeDead); Changed = true; @@ -1799,7 +1794,7 @@ static bool isTryApplyOfConvertFunction(TryApplyInst *TAI, // Check if it is a conversion of a non-throwing function into // a throwing function. If this is the case, replace by a // simple apply. - auto OrigFnTy = dyn_cast(CFI->getConverted().getType(). + auto OrigFnTy = dyn_cast(CFI->getConverted()->getType(). getSwiftRValueType()); if (!OrigFnTy || OrigFnTy->hasErrorResult()) return false; @@ -1827,7 +1822,7 @@ static bool isTryApplyOfConvertFunction(TryApplyInst *TAI, // Look through the conversions and find the real callee. Callee = getActualCallee(CFI->getConverted()); - CalleeType = Callee.getType(); + CalleeType = Callee->getType(); // If it a call of a throwing callee, bail. auto CalleeFnTy = dyn_cast(CalleeType.getSwiftRValueType()); @@ -1885,24 +1880,38 @@ bool SimplifyCFG::simplifyTryApplyBlock(TryApplyInst *TAI) { } auto OrigFnTy = dyn_cast( - TAI->getCallee().getType().getSwiftRValueType()); + TAI->getCallee()->getType().getSwiftRValueType()); if (OrigFnTy->isPolymorphic()) { OrigFnTy = OrigFnTy->substGenericArgs(TAI->getModule(), TAI->getModule().getSwiftModule(), TAI->getSubstitutions()); } + auto OrigParamTypes = OrigFnTy->getParameterSILTypes(); + auto TargetParamTypes = TargetFnTy->getParameterSILTypes(); + unsigned numArgs = TAI->getNumArguments(); + + // First check if it is possible to convert all arguments. + // Currently we believe that castValueToABICompatibleType can handle all + // cases, so this check should never fail. We just do it to be absolutely + // sure that we don't crash. + for (unsigned i = 0; i < numArgs; ++i) { + if (!canCastValueToABICompatibleType(TAI->getModule(), + OrigParamTypes[i], + TargetParamTypes[i])) { + return false; + } + } + SmallVector Args; - for (int i = 0, e = TAI->getNumArguments(); i < e; ++i) { + for (unsigned i = 0; i < numArgs; ++i) { auto Arg = TAI->getArgument(i); // Cast argument if required. Arg = castValueToABICompatibleType(&Builder, TAI->getLoc(), Arg, - OrigFnTy->getParameterSILTypes()[i], - TargetFnTy->getParameterSILTypes()[i]). - getValue(); + OrigParamTypes[i], + TargetParamTypes[i]).getValue(); Args.push_back(Arg); } - assert (CalleeFnTy->getParameters().size() == Args.size() && "The number of arguments should match"); @@ -1987,7 +1996,7 @@ bool RemoveUnreachable::run() { } /// Checks if the block contains a cond_fail as first side-effect instruction -/// and trys to move it to the predecessors (if beneficial). A sequence +/// and tries to move it to the predecessors (if beneficial). A sequence /// /// bb1: /// br bb3(%c) @@ -2010,13 +2019,13 @@ bool RemoveUnreachable::run() { /// static bool tryMoveCondFailToPreds(SILBasicBlock *BB) { - CondFailInst *CFI = getFistCondFail(BB); + CondFailInst *CFI = getFirstCondFail(BB); if (!CFI) return false; // Find the underlying condition value of the cond_fail. // We only accept single uses. This is not a correctness check, but we only - // want to to the optimization if the condition gets dead after moving the + // want to the optimization if the condition gets dead after moving the // cond_fail. bool inverted = false; SILValue cond = skipInvert(CFI->getOperand(), inverted, true); @@ -2081,37 +2090,39 @@ bool SimplifyCFG::simplifyBlocks() { // Otherwise, try to simplify the terminator. TermInst *TI = BB->getTerminator(); - switch (TI->getKind()) { - case ValueKind::BranchInst: + switch (TI->getTermKind()) { + case TermKind::BranchInst: Changed |= simplifyBranchBlock(cast(TI)); break; - case ValueKind::CondBranchInst: + case TermKind::CondBranchInst: Changed |= simplifyCondBrBlock(cast(TI)); break; - case ValueKind::SwitchValueInst: + case TermKind::SwitchValueInst: // FIXME: Optimize for known switch values. Changed |= simplifySwitchValueBlock(cast(TI)); break; - case ValueKind::SwitchEnumInst: + case TermKind::SwitchEnumInst: Changed |= simplifySwitchEnumBlock(cast(TI)); Changed |= simplifyTermWithIdenticalDestBlocks(BB); break; - case ValueKind::UnreachableInst: + case TermKind::UnreachableInst: Changed |= simplifyUnreachableBlock(cast(TI)); break; - case ValueKind::CheckedCastBranchInst: + case TermKind::CheckedCastBranchInst: Changed |= simplifyCheckedCastBranchBlock(cast(TI)); break; - case ValueKind::CheckedCastAddrBranchInst: + case TermKind::CheckedCastAddrBranchInst: Changed |= simplifyCheckedCastAddrBranchBlock(cast(TI)); break; - case ValueKind::TryApplyInst: + case TermKind::TryApplyInst: Changed |= simplifyTryApplyBlock(cast(TI)); break; - case ValueKind::SwitchEnumAddrInst: + case TermKind::SwitchEnumAddrInst: Changed |= simplifyTermWithIdenticalDestBlocks(BB); break; - default: + case TermKind::ThrowInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::ReturnInst: break; } // If the block has a cond_fail, try to move it to the predecessors. @@ -2119,6 +2130,9 @@ bool SimplifyCFG::simplifyBlocks() { // Simplify the block argument list. Changed |= simplifyArgs(BB); + + // Simplify the program termination block. + Changed |= simplifyProgramTerminationBlock(BB); } return Changed; @@ -2172,7 +2186,7 @@ static SILBasicBlock *isObjCMethodCallBlock(SILBasicBlock &Block) { return nullptr; for (auto &Inst : Block) { - // Look for a objc method call. + // Look for an objc method call. auto *Apply = dyn_cast(&Inst); if (!Apply) continue; @@ -2259,7 +2273,7 @@ deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef TermOperands, auto *I = dyn_cast(Op.get()); if (!I) return; - Op.set(SILUndef::get(Op.get().getType(), M)); + Op.set(SILUndef::get(Op.get()->getType(), M)); recursivelyDeleteTriviallyDeadInstructions(I); } @@ -2475,10 +2489,10 @@ bool ArgumentSplitter::createNewArguments() { auto Loc = RegularLocation::getAutoGeneratedLocation(); Agg = Projection::createAggFromFirstLevelProjections( B, Loc, Arg->getType(), NewArgumentValues).get(); - assert(Agg->getNumTypes() == 1 && "Expected only one result"); + assert(Agg->hasValue() && "Expected a result"); } - SILValue(Arg).replaceAllUsesWith(SILValue(Agg)); + Arg->replaceAllUsesWith(Agg); // Look at all users of agg and see if we can simplify any of them. This will // eliminate struct_extracts/tuple_extracts from the newly created aggregate @@ -2572,7 +2586,7 @@ static bool splitBBArguments(SILFunction &Fn) { bool Changed = false; std::vector Worklist; - // We know that we have atleast one BB, so this is safe since in such a case + // We know that we have at least one BB, so this is safe since in such a case // std::next(Fn->begin()) == Fn->end(), the exit case of iteration on a range. for (auto &BB : make_range(std::next(Fn.begin()), Fn.end())) { for (auto *Arg : BB.getBBArgs()) { @@ -2740,7 +2754,6 @@ getSwitchEnumPred(SILBasicBlock *BB, SwitchEnumInst *SEI, SILBasicBlock *PostBB, // Check that this block only produces the value, but does not // have any side effects. - bool BBHasIntegerLiteral = false; auto First = BB->begin(); auto *BI = dyn_cast(BB->getTerminator()); if (!BI) @@ -2765,7 +2778,6 @@ getSwitchEnumPred(SILBasicBlock *BB, SwitchEnumInst *SEI, SILBasicBlock *PostBB, // The branch can pass arguments only to the PostBB. if (BI->getDestBB() != PostBB) return nullptr; - BBHasIntegerLiteral = true; } // Each BB on the path should have only a single branch instruction. @@ -2814,7 +2826,7 @@ getSILValueFromCaseResult(SILBuilder &B, SILLocation Loc, return B.createIntegerLiteral(Loc, Type, Value.getBoolValue()); } else { llvm::errs() << "Non IntegerLiteralInst switch case result\n"; - Val.dump(); + Val->dump(); return Val; } } @@ -2946,7 +2958,7 @@ bool simplifySwitchEnumToSelectEnum(SILBasicBlock *BB, unsigned ArgNum, // If it does, then pick one of those cases as a default. // Count the number of possible case tags for a given enum type - auto *Enum = SEI->getOperand().getType().getEnumOrBoundGenericEnum(); + auto *Enum = SEI->getOperand()->getType().getEnumOrBoundGenericEnum(); unsigned ElemCount = 0; for (auto E : Enum->getAllElements()) { if (E) @@ -3012,7 +3024,7 @@ bool simplifySwitchEnumToSelectEnum(SILBasicBlock *BB, unsigned ArgNum, // Do not replace the bbarg SmallVector Args; Args.push_back(SelectInst); - B.setInsertionPoint(SelectInst->getNextNode()); + B.setInsertionPoint(&*std::next(SelectInst->getIterator())); B.createBranch(SEI->getLoc(), BB, Args); // Remove switch_enum instruction SEI->getParent()->getTerminator()->eraseFromParent(); @@ -3279,7 +3291,7 @@ bool SimplifyCFG::simplifyArgument(SILBasicBlock *BB, unsigned i) { // Okay, we'll replace the BB arg with one with the right type, replace // the uses in this block, and then rewrite the branch operands. A->replaceAllUsesWith(SILUndef::get(A->getType(), BB->getModule())); - auto *NewArg = BB->replaceBBArg(i, User->getType(0)); + auto *NewArg = BB->replaceBBArg(i, User->getType()); User->replaceAllUsesWith(NewArg); // Rewrite the branch operand for each incoming branch. @@ -3313,12 +3325,12 @@ static void tryToReplaceArgWithIncomingValue(SILBasicBlock *BB, unsigned i, // If the incoming values of all predecessors are equal usually this means // that the common incoming value dominates the BB. But: this might be not // the case if BB is unreachable. Therefore we still have to check it. - if (!DT->dominates(V.getDef()->getParentBB(), BB)) + if (!DT->dominates(V->getParentBB(), BB)) return; // An argument has one result value. We need to replace this with the *value* // of the incoming block(s). - SILValue(A, 0).replaceAllUsesWith(V); + A->replaceAllUsesWith(V); } bool SimplifyCFG::simplifyArgs(SILBasicBlock *BB) { @@ -3359,6 +3371,40 @@ bool SimplifyCFG::simplifyArgs(SILBasicBlock *BB) { return Changed; } +bool SimplifyCFG::simplifyProgramTerminationBlock(SILBasicBlock *BB) { + // If this is not ARC-inert, do not do anything to it. + // + // TODO: should we use ProgramTerminationAnalysis ?. The reason we do not + // use the analysis is because the CFG is likely to be invalidated right + // after this pass, o we do not really get the benefit of reusing the + // computation for the next iteration of the pass. + if (!isARCInertTrapBB(BB)) + return false; + + // This is going to be the last basic block this program is going to execute + // and this block is inert from the ARC's prospective, no point to do any + // releases at this point. + bool Changed = false; + llvm::SmallPtrSet InstsToRemove; + for (auto &I : *BB) { + if (!isa(I) && !isa(I) && + !isa(I) && !isa(I)) + continue; + InstsToRemove.insert(&I); + } + + // Remove the instructions. + for (auto I : InstsToRemove) { + I->eraseFromParent(); + Changed = true; + } + + if (Changed) + ++NumTermBlockSimplified; + + return Changed; +} + namespace { class SimplifyCFGPass : public SILFunctionTransform { bool EnableJumpThread; @@ -3466,4 +3512,3 @@ SILTransform *swift::createSROABBArgs() { return new SROABBArgs(); } SILTransform *swift::createSimplifyBBArgs() { return new SimplifyBBArgs(); } - diff --git a/lib/SILOptimizer/Transforms/Sink.cpp b/lib/SILOptimizer/Transforms/Sink.cpp index f4aaad5b493fe..1430384d19778 100644 --- a/lib/SILOptimizer/Transforms/Sink.cpp +++ b/lib/SILOptimizer/Transforms/Sink.cpp @@ -1,17 +1,20 @@ -//===-- Sink.cpp ----- Code Sinking -----------------------------*- C++ -*-===// +//===--- Sink.cpp ----- Code Sinking --------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// -// Many SIL instructions that don't have side effects at the SIL level are -// lowered to a sequence of LLVM instructions that does have side effects that -// LLVM can't sink. This pass sinks instructions close to their users. +/// +/// \file +/// Many SIL instructions that don't have side effects at the SIL level are +/// lowered to a sequence of LLVM instructions that does have side effects that +/// LLVM can't sink. This pass sinks instructions close to their users. +/// //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sink-instructions" diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp index 9c3514bd57529..ffb868ea927c4 100644 --- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp +++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp @@ -1,8 +1,8 @@ -//===-- SpeculativeDevirtualizer.cpp -- Speculatively devirtualize calls --===// +//===--- SpeculativeDevirtualizer.cpp - Speculatively devirtualize calls --===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,7 +15,7 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "sil-speculative-devirtualizer-pass" +#define DEBUG_TYPE "sil-speculative-devirtualizer" #include "swift/Basic/DemangleWrappers.h" #include "swift/Basic/Fallthrough.h" #include "swift/SIL/SILArgument.h" @@ -23,6 +23,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/SILOptimizer/PassManager/Passes.h" @@ -306,8 +307,8 @@ static bool tryToSpeculateTarget(FullApplySite AI, // Strip any upcasts off of our 'self' value, potentially leaving us // with a value whose type is closer (in the class hierarchy) to the // actual dynamic type. - auto SubTypeValue = CMI->getOperand().stripUpCasts(); - SILType SubType = SubTypeValue.getType(); + auto SubTypeValue = stripUpCasts(CMI->getOperand()); + SILType SubType = SubTypeValue->getType(); // Bail if any generic types parameters of the class instance type are // unbound. @@ -369,7 +370,7 @@ static bool tryToSpeculateTarget(FullApplySite AI, // bound generic class in a general case. if (isa(SubCanTy)) return false; - // Handle the ususal case here: the class in question + // Handle the usual case here: the class in question // should be a real subclass of a bound generic class. return !ClassType.isSuperclassOf( SILType::getPrimitiveObjectType(SubCanTy)); @@ -377,12 +378,15 @@ static bool tryToSpeculateTarget(FullApplySite AI, Subs.erase(RemovedIt, Subs.end()); } + // Number of subclasses which cannot be handled by checked_cast_br checks. + int NotHandledSubsNum = 0; if (Subs.size() > MaxNumSpeculativeTargets) { DEBUG(llvm::dbgs() << "Class " << CD->getName() << " has too many (" << Subs.size() << ") subclasses. Performing speculative " "devirtualization only for the first " << MaxNumSpeculativeTargets << " of them.\n"); + NotHandledSubsNum += (Subs.size() - MaxNumSpeculativeTargets); Subs.erase(&Subs[MaxNumSpeculativeTargets], Subs.end()); } @@ -434,9 +438,6 @@ static bool tryToSpeculateTarget(FullApplySite AI, // TODO: The ordering of checks may benefit from using a PGO, because // the most probable alternatives could be checked first. - // Number of subclasses which cannot be handled by checked_cast_br checks. - int NotHandledSubsNum = 0; - for (auto S : Subs) { DEBUG(llvm::dbgs() << "Inserting a speculative call for class " << CD->getName() << " and subclass " << S->getName() << "\n"); diff --git a/lib/SILOptimizer/Transforms/StackPromotion.cpp b/lib/SILOptimizer/Transforms/StackPromotion.cpp index d7e465847cf5e..539a8c8aa890c 100644 --- a/lib/SILOptimizer/Transforms/StackPromotion.cpp +++ b/lib/SILOptimizer/Transforms/StackPromotion.cpp @@ -1,8 +1,8 @@ -//===------- StackPromotion.cpp - Promotes allocations to the stack -------===// +//===--- StackPromotion.cpp - Promotes allocations to the stack -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -290,7 +290,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI, SILInstruction *&DeallocInsertionPoint) { AllocInsertionPoint = nullptr; DeallocInsertionPoint = nullptr; - auto *Node = ConGraph->getNode(AI, EA); + auto *Node = ConGraph->getNodeOrNull(AI, EA); if (!Node) return false; @@ -306,7 +306,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI, int NumUsePointsToFind = ConGraph->getNumUsePoints(Node); if (NumUsePointsToFind == 0) { // There should always be at least one release for an allocated object. - // But in case all pathes from this block end in unreachable then the + // But in case all paths from this block end in unreachable then the // final release of the object may be optimized away. We bail out in this // case. return false; @@ -391,7 +391,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI, // to fix the nesting. if (!isa(AI)) return false; - auto *Alloc = dyn_cast(I.getOperand(0).getDef()); + auto *Alloc = dyn_cast(I.getOperand(0)); if (!Alloc) return false; // This should always be the case, but let's be on the safe side. @@ -409,7 +409,7 @@ bool StackPromoter::canPromoteAlloc(SILInstruction *AI, if (WorkList.empty()) { if (EndBlock == BB) { // We reached the EndBlock but didn't find a place for the deallocation - // so far (because we didn't find all uses yet or we entered a another + // so far (because we didn't find all uses yet or we entered another // stack alloc-dealloc region). Let's extend our lifetime region. // E.g.: // %obj = alloc_ref // the allocation diff --git a/lib/SILOptimizer/UtilityPasses/AADumper.cpp b/lib/SILOptimizer/UtilityPasses/AADumper.cpp index fe173b54af380..aa8cac6501b55 100644 --- a/lib/SILOptimizer/UtilityPasses/AADumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/AADumper.cpp @@ -1,19 +1,20 @@ -//===-------- AADumper.cpp - Compare all values in Function with AA -------===// +//===--- AADumper.cpp - Compare all values in Function with AA ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// -// -// This pass collects all values in a function and applies alias analysis to -// them. The purpose of this is to enable unit tests for SIL Alias Analysis -// implementations independent of any other passes. -// +/// +/// \file +/// This pass collects all values in a function and applies alias analysis to +/// them. The purpose of this is to enable unit tests for SIL Alias Analysis +/// implementations independent of any other passes. +/// //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-aa-evaluator" @@ -40,8 +41,8 @@ static bool gatherValues(SILFunction &Fn, std::vector &Values) { for (auto *Arg : BB.getBBArgs()) Values.push_back(SILValue(Arg)); for (auto &II : BB) - for (unsigned i = 0, e = II.getNumTypes(); i != e; ++i) - Values.push_back(SILValue(&II, i)); + if (II.hasValue()) + Values.push_back(&II); } return Values.size() > 1; } @@ -98,61 +99,7 @@ class SILAADumper : public SILModuleTransform { StringRef getName() override { return "AA Dumper"; } }; - -/// Dumps the memory behavior of instructions in a function. -class MemBehaviorDumper : public SILModuleTransform { - - // To reduce the amount of output, we only dump the memory behavior of - // selected types of instructions. - static bool shouldTestInstruction(SILInstruction *I) { - // Only consider function calls. - if (FullApplySite::isa(I)) - return true; - - return false; - } - - void run() override { - for (auto &Fn: *getModule()) { - llvm::outs() << "@" << Fn.getName() << "\n"; - // Gather up all Values in Fn. - std::vector Values; - if (!gatherValues(Fn, Values)) - continue; - - AliasAnalysis *AA = PM->getAnalysis(); - - unsigned PairCount = 0; - for (auto &BB : Fn) { - for (auto &I : BB) { - if (shouldTestInstruction(&I)) { - - // Print the memory behavior in relation to all other values in the - // function. - for (auto &V : Values) { - bool Read = AA->mayReadFromMemory(&I, V); - bool Write = AA->mayWriteToMemory(&I, V); - bool SideEffects = AA->mayHaveSideEffects(&I, V); - llvm::outs() << - "PAIR #" << PairCount++ << ".\n" << - " " << SILValue(&I) << - " " << V << - " r=" << Read << ",w=" << Write << ",se=" << SideEffects << "\n"; - } - } - } - } - llvm::outs() << "\n"; - } - } - - StringRef getName() override { return "Memory Behavior Dumper"; } -}; } // end anonymous namespace SILTransform *swift::createAADumper() { return new SILAADumper(); } - -SILTransform *swift::createMemBehaviorDumper() { - return new MemBehaviorDumper(); -} diff --git a/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp b/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp index 098cc26482808..37446659bf9cb 100644 --- a/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/BasicCalleePrinter.cpp @@ -1,8 +1,8 @@ -//===-- BasicCalleePrinter.cpp - Callee cache printing pass ---*- C++ -*---===// +//===--- BasicCalleePrinter.cpp - Callee cache printing pass --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/CFGPrinter.cpp b/lib/SILOptimizer/UtilityPasses/CFGPrinter.cpp index 5e45fc09f5146..6880115ee8bbf 100644 --- a/lib/SILOptimizer/UtilityPasses/CFGPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/CFGPrinter.cpp @@ -1,8 +1,8 @@ -//===-- CFGPrinter.cpp - CFG printer pass ---------------------------------===// +//===--- CFGPrinter.cpp - CFG printer pass --------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt index f4a2b7996756f..2641f19f3c43c 100644 --- a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt +++ b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt @@ -1,6 +1,8 @@ set(UTILITYPASSES_SOURCES UtilityPasses/AADumper.cpp UtilityPasses/BasicCalleePrinter.cpp + UtilityPasses/ComputeDominanceInfo.cpp + UtilityPasses/ComputeLoopInfo.cpp UtilityPasses/CFGPrinter.cpp UtilityPasses/EscapeAnalysisDumper.cpp UtilityPasses/FunctionOrderPrinter.cpp @@ -11,6 +13,8 @@ set(UTILITYPASSES_SOURCES UtilityPasses/LoopCanonicalizer.cpp UtilityPasses/LoopRegionPrinter.cpp UtilityPasses/LSLocationPrinter.cpp + UtilityPasses/MemBehaviorDumper.cpp + UtilityPasses/RCIdentityDumper.cpp UtilityPasses/SideEffectsDumper.cpp UtilityPasses/StripDebugInfo.cpp PARENT_SCOPE) diff --git a/lib/SILOptimizer/UtilityPasses/ComputeDominanceInfo.cpp b/lib/SILOptimizer/UtilityPasses/ComputeDominanceInfo.cpp new file mode 100644 index 0000000000000..f941eb4cfad72 --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/ComputeDominanceInfo.cpp @@ -0,0 +1,30 @@ +//===--- ComputeDominanceInfo.cpp -----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-compute-dominance-info" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" + +using namespace swift; + +class ComputeDominanceInfo : public SILFunctionTransform { + + void run() override { + PM->getAnalysis()->get(getFunction()); + PM->getAnalysis()->get(getFunction()); + } + + StringRef getName() override { return "Compute Dominance Info"; } +}; + +SILTransform *swift::createComputeDominanceInfo() { return new ComputeDominanceInfo(); } diff --git a/lib/SILOptimizer/UtilityPasses/ComputeLoopInfo.cpp b/lib/SILOptimizer/UtilityPasses/ComputeLoopInfo.cpp new file mode 100644 index 0000000000000..3f6558421a41f --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/ComputeLoopInfo.cpp @@ -0,0 +1,29 @@ +//===--- ComputeLoopInfo.cpp ----------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-compute-loop-info" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Analysis/LoopAnalysis.h" + +using namespace swift; + +class ComputeLoopInfo : public SILFunctionTransform { + + void run() override { + PM->getAnalysis()->get(getFunction()); + } + + StringRef getName() override { return "Compute Loop Info"; } +}; + +SILTransform *swift::createComputeLoopInfo() { return new ComputeLoopInfo(); } diff --git a/lib/SILOptimizer/UtilityPasses/EscapeAnalysisDumper.cpp b/lib/SILOptimizer/UtilityPasses/EscapeAnalysisDumper.cpp index 0ea8d87e95ebd..abe0017299878 100644 --- a/lib/SILOptimizer/UtilityPasses/EscapeAnalysisDumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/EscapeAnalysisDumper.cpp @@ -1,8 +1,8 @@ -//===-------- EscapeAnalysisDumper.cpp - Dumps the escape analysis --------===// +//===--- EscapeAnalysisDumper.cpp - Dumps the escape analysis -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,12 +25,11 @@ namespace { class EscapeAnalysisDumper : public SILModuleTransform { void run() override { - DEBUG(llvm::dbgs() << "** EscapeAnalysisDumper **\n"); +#ifndef NDEBUG auto *EA = PM->getAnalysis(); -#ifndef NDEBUG llvm::outs() << "Escape information of module\n"; for (auto &F : *getModule()) { if (!F.isExternalDeclaration()) { diff --git a/lib/SILOptimizer/UtilityPasses/FunctionOrderPrinter.cpp b/lib/SILOptimizer/UtilityPasses/FunctionOrderPrinter.cpp index 933a18b98ba9e..5ddabe4532ffd 100644 --- a/lib/SILOptimizer/UtilityPasses/FunctionOrderPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/FunctionOrderPrinter.cpp @@ -1,8 +1,8 @@ -//===-- FunctionOrderPrinter.cpp - Function ordering test pass ------------===// +//===--- FunctionOrderPrinter.cpp - Function ordering test pass -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp b/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp index 43566ee88c801..6764f99f177f7 100644 --- a/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/IVInfoPrinter.cpp @@ -1,8 +1,8 @@ -//===------------ IVInfoPrinter.cpp - Print SIL IV Info -*- C++ -*-------===// +//===--- IVInfoPrinter.cpp - Print SIL IV Info ----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/InstCount.cpp b/lib/SILOptimizer/UtilityPasses/InstCount.cpp index 6d193fa677f85..c9f2613f85356 100644 --- a/lib/SILOptimizer/UtilityPasses/InstCount.cpp +++ b/lib/SILOptimizer/UtilityPasses/InstCount.cpp @@ -1,8 +1,8 @@ -//===-- InstCount.cpp - Collects the count of all instructions ------------===// +//===--- InstCount.cpp - Collects the count of all instructions -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp index 56026d84fb0b1..18c923a061e93 100644 --- a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp @@ -1,19 +1,19 @@ -///===--- LSLocationPrinter.cpp - Dump all memory locations in program ---===// -/// -/// This source file is part of the Swift.org open source project -/// -/// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -/// Licensed under Apache License v2.0 with Runtime Library Exception -/// -/// See http://swift.org/LICENSE.txt for license information -/// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -/// -///===---------------------------------------------------------------------===// -/// -/// This pass tests type expansion, memlocation expansion and memlocation -/// reduction. -/// -///===---------------------------------------------------------------------===// +//===--- LSLocationPrinter.cpp - Dump all memory locations in program -----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This pass tests type expansion, memlocation expansion and memlocation +// reduction. +// +//===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-memlocation-dumper" #include "swift/SILOptimizer/PassManager/Passes.h" @@ -52,6 +52,9 @@ static llvm::cl::opt LSLocationKinds( "only-type-expansion"), clEnumValN(MLKind::All, "all", "all"), clEnumValEnd)); +static llvm::cl::opt UseNewProjection("lslocation-dump-use-new-projection", + llvm::cl::init(false)); + namespace { class LSLocationPrinter : public SILModuleTransform { @@ -74,12 +77,12 @@ class LSLocationPrinter : public SILModuleTransform { if (auto *LI = dyn_cast(&II)) { SILValue V = LI->getOperand(); // This is an address type, take it object type. - SILType Ty = V.getType().getObjectType(); + SILType Ty = V->getType().getObjectType(); ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); } else if (auto *SI = dyn_cast(&II)) { SILValue V = SI->getDest(); // This is an address type, take it object type. - SILType Ty = V.getType().getObjectType(); + SILType Ty = V->getType().getObjectType(); ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); } else { // Not interested in these instructions yet. @@ -96,6 +99,39 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "\n"; } + void printTypeExpansionWithNewProjection(SILFunction &Fn) { + SILModule *M = &Fn.getModule(); + llvm::SmallVector, 8> PPList; + unsigned Counter = 0; + for (auto &BB : Fn) { + for (auto &II : BB) { + SILValue V; + SILType Ty; + if (auto *LI = dyn_cast(&II)) { + V = LI->getOperand(); + // This is an address type, take it object type. + Ty = V->getType().getObjectType(); + NewProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + } else if (auto *SI = dyn_cast(&II)) { + V = SI->getDest(); + // This is an address type, take it object type. + Ty = V->getType().getObjectType(); + NewProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + } else { + // Not interested in these instructions yet. + continue; + } + + llvm::outs() << "#" << Counter++ << II; + for (auto &T : PPList) { + T.getValue().print(llvm::outs(), *M); + } + PPList.clear(); + } + } + llvm::outs() << "\n"; + } + /// Dumps the expansions of memory locations accessed in the function. /// This tests the expand function in LSLocation class. /// @@ -109,12 +145,16 @@ class LSLocationPrinter : public SILModuleTransform { for (auto &BB : Fn) { for (auto &II : BB) { if (auto *LI = dyn_cast(&II)) { - L.initialize(LI->getOperand()); + SILValue Mem = LI->getOperand(); + SILValue UO = getUnderlyingObject(Mem); + L.init(UO, NewProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; LSLocation::expand(L, &Fn.getModule(), Locs, TE); } else if (auto *SI = dyn_cast(&II)) { - L.initialize(SI->getDest()); + SILValue Mem = SI->getDest(); + SILValue UO = getUnderlyingObject(Mem); + L.init(UO, NewProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; LSLocation::expand(L, &Fn.getModule(), Locs, TE); @@ -125,9 +165,8 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "#" << Counter++ << II; for (auto &Loc : Locs) { - Loc.print(); + Loc.print(&Fn.getModule()); } - L.reset(); Locs.clear(); } } @@ -150,12 +189,16 @@ class LSLocationPrinter : public SILModuleTransform { // Expand it first. // if (auto *LI = dyn_cast(&II)) { - L.initialize(LI->getOperand()); + SILValue Mem = LI->getOperand(); + SILValue UO = getUnderlyingObject(Mem); + L.init(UO, NewProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; LSLocation::expand(L, &Fn.getModule(), Locs, TE); } else if (auto *SI = dyn_cast(&II)) { - L.initialize(SI->getDest()); + SILValue Mem = SI->getDest(); + SILValue UO = getUnderlyingObject(Mem); + L.init(UO, NewProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; LSLocation::expand(L, &Fn.getModule(), Locs, TE); @@ -166,16 +209,17 @@ class LSLocationPrinter : public SILModuleTransform { // Try to reduce it. // - // Add into the set in reverse order, Reduction should not care - // about the order of the memory locations in the set. - for (auto I = Locs.rbegin(); I != Locs.rend(); ++I) { + // Reduction should not care about the order of the memory locations in + // the set. + for (auto I = Locs.begin(); I != Locs.end(); ++I) { SLocs.insert(*I); } + // This should get the original (unexpanded) location back. LSLocation::reduce(L, &Fn.getModule(), SLocs, TE); llvm::outs() << "#" << Counter++ << II; for (auto &Loc : SLocs) { - Loc.print(); + Loc.print(&Fn.getModule()); } L.reset(); Locs.clear(); @@ -195,7 +239,7 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "@" << Fn.getName() << "\n"; switch (LSLocationKinds) { case MLKind::OnlyTypeExpansion: - printTypeExpansion(Fn); + printTypeExpansionWithNewProjection(Fn); break; case MLKind::OnlyExpansion: printMemExpansion(Fn); diff --git a/lib/SILOptimizer/UtilityPasses/Link.cpp b/lib/SILOptimizer/UtilityPasses/Link.cpp index 3aed01b5dadf3..a1458394f8a32 100644 --- a/lib/SILOptimizer/UtilityPasses/Link.cpp +++ b/lib/SILOptimizer/UtilityPasses/Link.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/LoopCanonicalizer.cpp b/lib/SILOptimizer/UtilityPasses/LoopCanonicalizer.cpp index dfcb7b8c652e8..bb3e57592fccf 100644 --- a/lib/SILOptimizer/UtilityPasses/LoopCanonicalizer.cpp +++ b/lib/SILOptimizer/UtilityPasses/LoopCanonicalizer.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/LoopInfoPrinter.cpp b/lib/SILOptimizer/UtilityPasses/LoopInfoPrinter.cpp index 2d64a0389ad7d..b1ae9770c9bef 100644 --- a/lib/SILOptimizer/UtilityPasses/LoopInfoPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/LoopInfoPrinter.cpp @@ -1,8 +1,8 @@ -//===------------ LoopInfoPrinter.h - Print SIL Loop Info -*- C++ -*-------===// +//===--- LoopInfoPrinter.cpp - Print SIL Loop Info ------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/LoopRegionPrinter.cpp b/lib/SILOptimizer/UtilityPasses/LoopRegionPrinter.cpp index a3e3723392bf8..64e3f4430e64b 100644 --- a/lib/SILOptimizer/UtilityPasses/LoopRegionPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/LoopRegionPrinter.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp new file mode 100644 index 0000000000000..897fc86f30240 --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/MemBehaviorDumper.cpp @@ -0,0 +1,102 @@ +//===--- MemBehaviorDumper.cpp --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-mem-behavior-dumper" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/Support/Debug.h" + +using namespace swift; + +//===----------------------------------------------------------------------===// +// Value Gatherer +//===----------------------------------------------------------------------===// + +// Return a list of all instruction values in Fn. Returns true if we have at +// least two values to compare. +static bool gatherValues(SILFunction &Fn, std::vector &Values) { + for (auto &BB : Fn) { + for (auto *Arg : BB.getBBArgs()) + Values.push_back(SILValue(Arg)); + for (auto &II : BB) + if (II.hasValue()) + Values.push_back(&II); + } + return Values.size() > 1; +} + +//===----------------------------------------------------------------------===// +// Top Level Driver +//===----------------------------------------------------------------------===// + +namespace { + +/// Dumps the memory behavior of instructions in a function. +class MemBehaviorDumper : public SILModuleTransform { + + // To reduce the amount of output, we only dump the memory behavior of + // selected types of instructions. + static bool shouldTestInstruction(SILInstruction *I) { + // Only consider function calls. + if (FullApplySite::isa(I)) + return true; + + return false; + } + + void run() override { + for (auto &Fn : *getModule()) { + llvm::outs() << "@" << Fn.getName() << "\n"; + // Gather up all Values in Fn. + std::vector Values; + if (!gatherValues(Fn, Values)) + continue; + + AliasAnalysis *AA = PM->getAnalysis(); + + unsigned PairCount = 0; + for (auto &BB : Fn) { + for (auto &I : BB) { + if (shouldTestInstruction(&I)) { + + // Print the memory behavior in relation to all other values in the + // function. + for (auto &V : Values) { + bool Read = AA->mayReadFromMemory(&I, V); + bool Write = AA->mayWriteToMemory(&I, V); + bool SideEffects = AA->mayHaveSideEffects(&I, V); + llvm::outs() << "PAIR #" << PairCount++ << ".\n" + << " " << SILValue(&I) << " " << V + << " r=" << Read << ",w=" << Write + << ",se=" << SideEffects << "\n"; + } + } + } + } + llvm::outs() << "\n"; + } + } + + StringRef getName() override { return "Memory Behavior Dumper"; } +}; + +} // end anonymous namespace + +SILTransform *swift::createMemBehaviorDumper() { + return new MemBehaviorDumper(); +} diff --git a/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp b/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp new file mode 100644 index 0000000000000..6b063df460c3a --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/RCIdentityDumper.cpp @@ -0,0 +1,81 @@ +//===--- RCIdentityDumper.cpp ---------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This pass applies the RCIdentityAnalysis to all SILValues in a function in +/// order to apply FileCheck testing to RCIdentityAnalysis without needing to +/// test any other passes. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sil-rc-identity-dumper" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "llvm/Support/Debug.h" + +using namespace swift; + +namespace { + +/// Dumps the alias relations between all instructions of a function. +class RCIdentityDumper : public SILFunctionTransform { + + void run() override { + auto *Fn = getFunction(); + auto *RCId = PM->getAnalysis()->get(Fn); + + std::vector> Results; + unsigned ValueCount = 0; + llvm::MapVector ValueToValueIDMap; + + llvm::outs() << "@" << Fn->getName() << "@\n"; + + for (auto &BB : *Fn) { + for (auto *Arg : BB.getBBArgs()) { + ValueToValueIDMap[Arg] = ValueCount++; + Results.push_back({Arg, RCId->getRCIdentityRoot(Arg)}); + } + for (auto &II : BB) { + if (II.hasValue()) { + SILValue V(&II); + ValueToValueIDMap[V] = ValueCount++; + Results.push_back({V, RCId->getRCIdentityRoot(V)}); + } + } + } + + llvm::outs() << "ValueMap:\n"; + for (auto P : ValueToValueIDMap) { + llvm::outs() << "\tValueMap[" << P.second << "] = " << P.first; + } + + unsigned ResultCount = 0; + for (auto P : Results) { + llvm::outs() << "RESULT #" << ResultCount++ << ": " + << ValueToValueIDMap[P.first] << " = " + << ValueToValueIDMap[P.second] << "\n"; + } + + llvm::outs() << "\n"; + } + + StringRef getName() override { return "RC Identity Dumper"; } +}; + +} // end anonymous namespace + +SILTransform *swift::createRCIdentityDumper() { return new RCIdentityDumper(); } diff --git a/lib/SILOptimizer/UtilityPasses/SideEffectsDumper.cpp b/lib/SILOptimizer/UtilityPasses/SideEffectsDumper.cpp index b8d860a49728d..f3a3fb7577155 100644 --- a/lib/SILOptimizer/UtilityPasses/SideEffectsDumper.cpp +++ b/lib/SILOptimizer/UtilityPasses/SideEffectsDumper.cpp @@ -1,8 +1,8 @@ -//===------- SideEffectsDumper.cpp - Dumps the side effect analysis -------===// +//===--- SideEffectsDumper.cpp - Dumps the side effect analysis -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,9 +28,9 @@ class SideEffectsDumper : public SILModuleTransform { DEBUG(llvm::dbgs() << "** SideEffectsDumper **\n"); +#ifndef NDEBUG auto *SEA = PM->getAnalysis(); -#ifndef NDEBUG llvm::outs() << "Side effects of module\n"; for (auto &F : *getModule()) { llvm::outs() << " sil @" << F.getName() << '\n'; diff --git a/lib/SILOptimizer/UtilityPasses/StripDebugInfo.cpp b/lib/SILOptimizer/UtilityPasses/StripDebugInfo.cpp index b89dbb3ffa4b4..2dff3ff013339 100644 --- a/lib/SILOptimizer/UtilityPasses/StripDebugInfo.cpp +++ b/lib/SILOptimizer/UtilityPasses/StripDebugInfo.cpp @@ -1,8 +1,8 @@ -//===-------- StripDebugInfo.cpp - Strip debug info from SIL --------------===// +//===--- StripDebugInfo.cpp - Strip debug info from SIL -------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp index 62089497dd908..4930639b70520 100644 --- a/lib/SILOptimizer/Utils/CFG.cpp +++ b/lib/SILOptimizer/Utils/CFG.cpp @@ -1,8 +1,8 @@ -//===--- CFG.cpp - Utilities for SIL CFG transformations --------*- C++ -*-===// +//===--- CFG.cpp - Utilities for SIL CFG transformations ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -63,10 +63,8 @@ TermInst *swift::addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest, assert(Args.size() == Dest->getNumBBArg()); NewBr = Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); } else { - NewBr->dump(); // At the moment we can only add arguments to br and cond_br. llvm_unreachable("Can't add argument to terminator"); - return NewBr; } Branch->dropAllReferences(); @@ -98,7 +96,7 @@ TermInst *swift::changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, bool BranchOnTrue = CBI->getTrueBB() == Dest; assert((!BranchOnTrue || Idx < OldTrueArgs.size()) && "Not enough edges"); - // Copy the edge values overwritting the edge at Idx. + // Copy the edge values overwriting the edge at Idx. for (unsigned i = 0, e = OldTrueArgs.size(); i != e; ++i) { if (BranchOnTrue && Idx == i) TrueArgs.push_back(Val); @@ -112,7 +110,7 @@ TermInst *swift::changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, bool BranchOnFalse = CBI->getFalseBB() == Dest; assert((!BranchOnFalse || Idx < OldFalseArgs.size()) && "Not enough edges"); - // Copy the edge values overwritting the edge at Idx. + // Copy the edge values overwriting the edge at Idx. for (unsigned i = 0, e = OldFalseArgs.size(); i != e; ++i) { if (BranchOnFalse && Idx == i) FalseArgs.push_back(Val); @@ -136,7 +134,7 @@ TermInst *swift::changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, assert(Idx < BI->getNumArgs() && "Not enough edges"); OperandValueArrayRef OldArgs = BI->getArgs(); - // Copy the edge values overwritting the edge at Idx. + // Copy the edge values overwriting the edge at Idx. for (unsigned i = 0, e = OldArgs.size(); i != e; ++i) { if (Idx == i) Args.push_back(Val); @@ -173,13 +171,9 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewDest, bool PreserveArgs) { SILBuilderWithScope B(T); - switch (T->getKind()) { -#define TERMINATOR(ID, PARENT, MEM, RELEASE) -#define VALUE(ID, PARENT) case ValueKind::ID: -#include "swift/SIL/SILNodes.def" - llvm_unreachable("Unexpected terminator instruction!"); + switch (T->getTermKind()) { // Only Branch and CondBranch may have arguments. - case ValueKind::BranchInst: { + case TermKind::BranchInst: { auto Br = dyn_cast(T); SmallVector Args; if (PreserveArgs) { @@ -192,7 +186,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::CondBranchInst: { + case TermKind::CondBranchInst: { auto CondBr = dyn_cast(T); SmallVector TrueArgs; if (EdgeIdx == CondBranchInst::FalseIdx || PreserveArgs) { @@ -218,7 +212,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::SwitchValueInst: { + case TermKind::SwitchValueInst: { auto SII = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SII, Cases, EdgeIdx, NewDest); @@ -227,7 +221,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::SwitchEnumInst: { + case TermKind::SwitchEnumInst: { auto SEI = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SEI, Cases, EdgeIdx, NewDest); @@ -236,7 +230,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::SwitchEnumAddrInst: { + case TermKind::SwitchEnumAddrInst: { auto SEI = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SEI, Cases, EdgeIdx, NewDest); @@ -245,7 +239,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::DynamicMethodBranchInst: { + case TermKind::DynamicMethodBranchInst: { auto DMBI = dyn_cast(T); assert(EdgeIdx == 0 || EdgeIdx == 1 && "Invalid edge index"); auto HasMethodBB = !EdgeIdx ? NewDest : DMBI->getHasMethodBB(); @@ -256,7 +250,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::CheckedCastBranchInst: { + case TermKind::CheckedCastBranchInst: { auto CBI = dyn_cast(T); assert(EdgeIdx == 0 || EdgeIdx == 1 && "Invalid edge index"); auto SuccessBB = !EdgeIdx ? NewDest : CBI->getSuccessBB(); @@ -267,7 +261,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::CheckedCastAddrBranchInst: { + case TermKind::CheckedCastAddrBranchInst: { auto CBI = dyn_cast(T); assert(EdgeIdx == 0 || EdgeIdx == 1 && "Invalid edge index"); auto SuccessBB = !EdgeIdx ? NewDest : CBI->getSuccessBB(); @@ -280,7 +274,7 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::TryApplyInst: { + case TermKind::TryApplyInst: { auto *TAI = dyn_cast(T); assert((EdgeIdx == 0 || EdgeIdx == 1) && "Invalid edge index"); auto *NormalBB = !EdgeIdx ? NewDest : TAI->getNormalBB(); @@ -297,9 +291,9 @@ void swift::changeBranchTarget(TermInst *T, unsigned EdgeIdx, return; } - case ValueKind::ReturnInst: - case ValueKind::ThrowInst: - case ValueKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::UnreachableInst: llvm_unreachable("Branch target cannot be changed for this terminator instruction!"); } llvm_unreachable("Not yet implemented!"); @@ -331,13 +325,9 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, SILBasicBlock *NewDest, bool PreserveArgs) { SILBuilderWithScope B(T); - switch (T->getKind()) { -#define TERMINATOR(ID, PARENT, MEM, RELEASE) -#define VALUE(ID, PARENT) case ValueKind::ID: -#include "swift/SIL/SILNodes.def" - llvm_unreachable("Unexpected terminator instruction!"); + switch (T->getTermKind()) { // Only Branch and CondBranch may have arguments. - case ValueKind::BranchInst: { + case TermKind::BranchInst: { auto Br = dyn_cast(T); SmallVector Args; if (PreserveArgs) { @@ -350,7 +340,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::CondBranchInst: { + case TermKind::CondBranchInst: { auto CondBr = dyn_cast(T); SmallVector TrueArgs; if (OldDest == CondBr->getFalseBB() || PreserveArgs) { @@ -376,7 +366,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::SwitchValueInst: { + case TermKind::SwitchValueInst: { auto SII = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SII, Cases, OldDest, NewDest); @@ -385,7 +375,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::SwitchEnumInst: { + case TermKind::SwitchEnumInst: { auto SEI = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); @@ -394,7 +384,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::SwitchEnumAddrInst: { + case TermKind::SwitchEnumAddrInst: { auto SEI = dyn_cast(T); SmallVector, 8> Cases; auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); @@ -403,7 +393,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::DynamicMethodBranchInst: { + case TermKind::DynamicMethodBranchInst: { auto DMBI = dyn_cast(T); assert(OldDest == DMBI->getHasMethodBB() || OldDest == DMBI->getNoMethodBB() && "Invalid edge index"); auto HasMethodBB = OldDest == DMBI->getHasMethodBB() ? NewDest : DMBI->getHasMethodBB(); @@ -414,7 +404,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::CheckedCastBranchInst: { + case TermKind::CheckedCastBranchInst: { auto CBI = dyn_cast(T); assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); @@ -425,7 +415,7 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::CheckedCastAddrBranchInst: { + case TermKind::CheckedCastAddrBranchInst: { auto CBI = dyn_cast(T); assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); @@ -438,10 +428,10 @@ void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, return; } - case ValueKind::ReturnInst: - case ValueKind::ThrowInst: - case ValueKind::TryApplyInst: - case ValueKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::TryApplyInst: + case TermKind::UnreachableInst: llvm_unreachable("Branch target cannot be replaced for this terminator instruction!"); } llvm_unreachable("Not yet implemented!"); @@ -500,8 +490,7 @@ static void getEdgeArgs(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewEdgeBB, assert(SuccBB->getNumBBArg() < 2 && "Can take at most one argument"); if (!SuccBB->getNumBBArg()) return; - Args.push_back( - SILValue(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType()), 0)); + Args.push_back(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType())); return; } @@ -511,8 +500,7 @@ static void getEdgeArgs(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewEdgeBB, (EdgeIdx == 0) ? DMBI->getHasMethodBB() : DMBI->getNoMethodBB(); if (!SuccBB->getNumBBArg()) return; - Args.push_back( - SILValue(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType()), 0)); + Args.push_back(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType())); return; } @@ -521,16 +509,14 @@ static void getEdgeArgs(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewEdgeBB, auto SuccBB = EdgeIdx == 0 ? CBI->getSuccessBB() : CBI->getFailureBB(); if (!SuccBB->getNumBBArg()) return; - Args.push_back( - SILValue(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType()), 0)); + Args.push_back(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType())); return; } if (auto CBI = dyn_cast(T)) { auto SuccBB = EdgeIdx == 0 ? CBI->getSuccessBB() : CBI->getFailureBB(); if (!SuccBB->getNumBBArg()) return; - Args.push_back( - SILValue(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType()), 0)); + Args.push_back(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType())); return; } @@ -538,8 +524,7 @@ static void getEdgeArgs(TermInst *T, unsigned EdgeIdx, SILBasicBlock *NewEdgeBB, auto *SuccBB = EdgeIdx == 0 ? TAI->getNormalBB() : TAI->getErrorBB(); if (!SuccBB->getNumBBArg()) return; - Args.push_back( - SILValue(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType()), 0)); + Args.push_back(NewEdgeBB->createBBArg(SuccBB->getBBArg(0)->getType())); return; } @@ -664,7 +649,7 @@ SILBasicBlock *swift::splitEdge(TermInst *T, unsigned EdgeIdx, } // Neither loop contains the other. The destination must be the header of its - // loop. Otherwise, we would be creating irreducable control flow. + // loop. Otherwise, we would be creating irreducible control flow. assert(DstBBLoop->getHeader() == DestBB && "Creating irreducible control flow?"); @@ -743,7 +728,7 @@ bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, // If there are any BB arguments in the destination, replace them with the // branch operands, since they must dominate the dest block. for (unsigned i = 0, e = Branch->getArgs().size(); i != e; ++i) - SILValue(SuccBB->getBBArg(i)).replaceAllUsesWith(Branch->getArg(i)); + SuccBB->getBBArg(i)->replaceAllUsesWith(Branch->getArg(i)); Branch->eraseFromParent(); diff --git a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp index 2266c16cbffc3..584e2c031fc74 100644 --- a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp +++ b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp @@ -2,6 +2,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Utils/CFG.h" #include "swift/SILOptimizer/Utils/Local.h" @@ -147,7 +148,7 @@ static unsigned basicBlockInlineCost(SILBasicBlock *BB, unsigned Cutoff) { return Cost; } -/// We can not duplicate blocks with AllocStack instructions (they need to be +/// We cannot duplicate blocks with AllocStack instructions (they need to be /// FIFO). Other instructions can be duplicated. static bool canDuplicateBlock(SILBasicBlock *BB) { for (auto &I : *BB) { @@ -213,10 +214,10 @@ SILValue CheckedCastBrJumpThreading::isArgValueEquivalentToCondition( SILValue Value, SILBasicBlock *DomBB, SILValue DomValue, DominanceInfo *DT) { SmallPtrSet SeenValues; - DomValue = DomValue.stripClassCasts(); + DomValue = stripClassCasts(DomValue); while (true) { - Value = Value.stripClassCasts(); + Value = stripClassCasts(Value); if (Value == DomValue) return Value; @@ -226,7 +227,7 @@ SILValue CheckedCastBrJumpThreading::isArgValueEquivalentToCondition( return SILValue(); // Have we visited this BB already? - if (!SeenValues.insert(Value.getDef()).second) + if (!SeenValues.insert(Value).second) return SILValue(); if (SeenValues.size() > 10) @@ -241,18 +242,18 @@ SILValue CheckedCastBrJumpThreading::isArgValueEquivalentToCondition( // Each incoming value should be either from a block // dominated by DomBB or it should be the value used in // condition in DomBB - Value = IncomingValue.stripClassCasts(); + Value = stripClassCasts(IncomingValue); if (Value == DomValue) continue; // Values should be the same if (!Def) - Def = Value.getDef(); + Def = Value; - if (Def != Value.getDef()) + if (Def != Value) return SILValue(); - if (!DT->dominates(DomBB, Value.getDef()->getParentBB())) + if (!DT->dominates(DomBB, Value->getParentBB())) return SILValue(); // OK, this value is a potential candidate } @@ -537,7 +538,7 @@ bool CheckedCastBrJumpThreading::areEquivalentConditionsAlongSomePaths() { } /// Check if conditions of CCBI and DomCCBI are equivalent along -/// all or at least some paths. +/// all or at least some paths. bool CheckedCastBrJumpThreading::areEquivalentConditionsAlongPaths() { // Are conditions equivalent along all paths? if (DomCondition == Condition) { @@ -578,7 +579,7 @@ bool CheckedCastBrJumpThreading::trySimplify(TermInst *Term) { // Init information about the checked_cast_br we try to // jump-thread. BB = Term->getParent(); - Condition = Term->getOperand(0).stripClassCasts(); + Condition = stripClassCasts(Term->getOperand(0)); SuccessBB = CCBI->getSuccessBB(); FailureBB = CCBI->getFailureBB(); @@ -636,7 +637,7 @@ bool CheckedCastBrJumpThreading::trySimplify(TermInst *Term) { // based on the found dominating checked_cast_br. DomSuccessBB = DomCCBI->getSuccessBB(); DomFailureBB = DomCCBI->getFailureBB(); - DomCondition = DomTerm->getOperand(0).stripClassCasts(); + DomCondition = stripClassCasts(DomTerm->getOperand(0)); // Init state variables for paths analysis SuccessPreds.clear(); @@ -654,7 +655,7 @@ bool CheckedCastBrJumpThreading::trySimplify(TermInst *Term) { if (!areEquivalentConditionsAlongPaths()) continue; - // Check if any jump-threding is required and possible. + // Check if any jump-threading is required and possible. if (SuccessPreds.empty() && FailurePreds.empty()) return false; diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index 94adadf922c19..d3bf7cabf0a39 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -1,8 +1,8 @@ -//===- ConstantFolding.cpp - Utilities for SIL constant folding -*- C++ -*-===// +//===--- ConstantFolding.cpp - Utils for SIL constant folding -------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 251af0a336a0f..d44e4ff2007de 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -1,8 +1,8 @@ -//===-- Devirtualize.cpp - Helper for devirtualizing apply ------*- C++ -*-===// +//===--- Devirtualize.cpp - Helper for devirtualizing apply ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,6 +21,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SILOptimizer/Utils/Local.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Statistic.h" @@ -71,7 +72,7 @@ static void getAllSubclasses(ClassHierarchyAnalysis *CHA, // bound generic class in a general case. if (isa(SubCanTy)) return false; - // Handle the ususal case here: the class in question + // Handle the usual case here: the class in question // should be a real subclass of a bound generic class. return !ClassType.isSuperclassOf( SILType::getPrimitiveObjectType(SubCanTy)); @@ -187,7 +188,7 @@ static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, break; } - // Take the ClassHieararchyAnalysis into account. + // Take the ClassHierarchyAnalysis into account. // If a given class has no subclasses and // - private // - or internal and it is a WMO compilation @@ -224,7 +225,7 @@ static SILValue getInstanceWithExactDynamicType(SILValue S, SILModule &M, ClassHierarchyAnalysis *CHA) { while (S) { - S = S.stripCasts(); + S = stripCasts(S); if (isa(S) || isa(S)) return S; @@ -347,7 +348,6 @@ getSubstitutionsForCallee(SILModule &M, CanSILFunctionType GenCalleeType, // Class F belongs to. CanType FSelfClass = GenCalleeType->getSelfParameter().getType(); - SILType FSelfSubstType; auto *Module = M.getSwiftModule(); ArrayRef ClassSubs; @@ -387,7 +387,7 @@ getSubstitutionsForCallee(SILModule &M, CanSILFunctionType GenCalleeType, auto AISubs = AI.getSubstitutions(); CanSILFunctionType AIGenCalleeType = - AI.getCallee().getType().castTo(); + AI.getCallee()->getType().castTo(); CanType AISelfClass = AIGenCalleeType->getSelfParameter().getType(); @@ -535,7 +535,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI, SILModule &Mod = AI.getModule(); auto *MI = cast(AI.getCallee()); - auto ClassOrMetatypeType = ClassOrMetatype.getType(); + auto ClassOrMetatypeType = ClassOrMetatype->getType(); auto *F = getTargetClassMethod(Mod, ClassOrMetatypeType, MI->getMember()); CanSILFunctionType GenCalleeType = F->getLoweredFunctionType(); @@ -558,7 +558,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI, for (unsigned i = 0, e = Args.size() - 1; i != e; ++i) NewArgs.push_back(castValueToABICompatibleType(&B, AI.getLoc(), Args[i], - Args[i].getType(), + Args[i]->getType(), ParamTypes[i]).getValue()); // Add the self argument, upcasting if required because we're @@ -590,7 +590,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI, if (!isa(AI)) { NewAI = B.createApply(AI.getLoc(), FRI, SubstCalleeSILType, ResultTy, Subs, NewArgs, cast(AI)->isNonThrowing()); - ResultValue = SILValue(NewAI.getInstruction(), 0); + ResultValue = NewAI.getInstruction(); } else { auto *TAI = cast(AI); // Create new normal and error BBs only if: @@ -668,12 +668,12 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI, // casted into an appropriate type. This SILValue may be a BB arg, if it // was a cast between optional types. // - the second one is the new apply site. - return std::make_pair(ResultValue.getDef(), NewAI); + return std::make_pair(ResultValue, NewAI); } DevirtualizationResult swift::tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance) { - if (!canDevirtualizeClassMethod(AI, ClassInstance.getType())) + if (!canDevirtualizeClassMethod(AI, ClassInstance->getType())) return std::make_pair(nullptr, FullApplySite()); return devirtualizeClassMethod(AI, ClassInstance); } @@ -695,17 +695,34 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, // Collect all the required substitutions. // // The complete set of substitutions may be different, e.g. because the found - // witness thunk F may have been created by a specialization pass and have + // witness thunk F may have been created by a specialization pass and have // additional generic parameters. SmallVector NewSubstList(Subs.begin(), Subs.end()); + if (auto generics = AI.getOrigCalleeType()->getGenericSignature()) { + ArrayRef origSubs = AI.getSubstitutions(); + for (auto genericParam : generics->getAllDependentTypes()) { + auto origSub = origSubs.front(); + origSubs = origSubs.slice(1); + + // Ignore generic parameters derived from 'self', the generic + // parameter at depth 0, index 0. + auto type = genericParam->getCanonicalType(); + while (auto memberType = dyn_cast(type)) { + type = memberType.getBase(); + } + auto paramType = cast(type); + if (paramType->getDepth() == 0) { + // There shouldn't be any other parameters at this depth. + assert(paramType->getIndex() == 0); + continue; + } - // Add the non-self-derived substitutions from the original application. - ArrayRef SubstList; - SubstList = AI.getSubstitutionsWithoutSelfSubstitution(); - - for (auto &origSub : SubstList) - if (!origSub.getArchetype()->isSelfDerived()) + // Okay, remember this substitution. NewSubstList.push_back(origSub); + } + + assert(origSubs.empty() && "subs not parallel to dependent types"); + } // Figure out the exact bound type of the function to be called by // applying all substitutions. @@ -724,7 +741,7 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, for (unsigned ArgN = 0, ArgE = AI.getNumArguments(); ArgN != ArgE; ++ArgN) { SILValue A = AI.getArgument(ArgN); auto ParamType = ParamTypes[ParamTypes.size() - AI.getNumArguments() + ArgN]; - if (A.getType() != ParamType) + if (A->getType() != ParamType) A = B.createUpcast(AI.getLoc(), A, ParamType); Arguments.push_back(A); @@ -813,8 +830,8 @@ swift::tryDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) { /// %YY = function_ref @... if (auto *CMI = dyn_cast(AI.getCallee())) { auto &M = AI.getModule(); - auto Instance = CMI->getOperand().stripUpCasts(); - auto ClassType = Instance.getType(); + auto Instance = stripUpCasts(CMI->getOperand()); + auto ClassType = Instance->getType(); if (ClassType.is()) ClassType = ClassType.getMetatypeInstanceType(M); diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index 78b51b0a28469..6d888ba0da6fd 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -1,8 +1,8 @@ -//===--------- GenericCloner.cpp - Specializes generic functions ---------===// +//===--- GenericCloner.cpp - Specializes generic functions ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -50,7 +50,9 @@ SILFunction *GenericCloner::initCloned(SILFunction *Orig, Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope(), Orig->getDeclContext()); NewF->setDeclCtx(Orig->getDeclContext()); - NewF->setSemanticsAttr(Orig->getSemanticsAttr()); + for (auto &Attr : Orig->getSemanticsAttrs()) { + NewF->addSemanticsAttr(Attr); + } return NewF; } @@ -84,15 +86,3 @@ void GenericCloner::populateCloned() { visit(BI->first->getTerminator()); } } - -void dumpTypeSubstitutionMap(const TypeSubstitutionMap &map) { - llvm::errs() << "{\n"; - for (auto &kv : map) { - llvm::errs() << " "; - kv.first->print(llvm::errs()); - llvm::errs() << " => "; - kv.second->print(llvm::errs()); - llvm::errs() << "\n"; - } - llvm::errs() << "}\n"; -} diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 7d1bc8f2ddbc7..844a23710fc6c 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -1,8 +1,8 @@ -//===- Generics.cpp ---- Utilities for transforming generics ----*- C++ -*-===// +//===--- Generics.cpp ---- Utilities for transforming generics ------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -53,7 +53,7 @@ ApplySite swift::replaceWithSpecializedFunction(ApplySite AI, /// Try to convert definition into declaration. -static bool convertExtenralDefinitionIntoDeclaration(SILFunction *F) { +static bool convertExternalDefinitionIntoDeclaration(SILFunction *F) { // Bail if it is a declaration already. if (!F->isDefinition()) return false; @@ -207,9 +207,9 @@ SILFunction *swift::getExistingSpecialization(SILModule &M, Specialization->setLinkage(SILLinkage::PublicExternal); // Ignore body for -Onone and -Odebug. assert((Specialization->isExternalDeclaration() || - convertExtenralDefinitionIntoDeclaration(Specialization)) && + convertExternalDefinitionIntoDeclaration(Specialization)) && "Could not remove body of the found specialization"); - if (!convertExtenralDefinitionIntoDeclaration(Specialization)) { + if (!convertExternalDefinitionIntoDeclaration(Specialization)) { DEBUG( llvm::dbgs() << "Could not remove body of specialization: " << FunctionName << '\n'); @@ -264,7 +264,7 @@ ApplySite swift::trySpecializeApplyOfGeneric(ApplySite Apply, // We do not support partial specialization. if (hasUnboundGenericTypes(InterfaceSubs)) { - DEBUG(llvm::dbgs() << " Can not specialize with interface subs.\n"); + DEBUG(llvm::dbgs() << " Cannot specialize with interface subs.\n"); return ApplySite(); } if (hasDynamicSelfTypes(InterfaceSubs)) { @@ -272,13 +272,13 @@ ApplySite swift::trySpecializeApplyOfGeneric(ApplySite Apply, return ApplySite(); } - llvm::SmallString<64> ClonedName; + std::string ClonedName; { - llvm::raw_svector_ostream buffer(ClonedName); ArrayRef Subs = Apply.getSubstitutions(); - Mangle::Mangler M(buffer); - Mangle::GenericSpecializationMangler Mangler(M, F, Subs); + Mangle::Mangler M; + GenericSpecializationMangler Mangler(M, F, Subs); Mangler.mangle(); + ClonedName = M.finalize(); } DEBUG(llvm::dbgs() << " Specialized function " << ClonedName << '\n'); diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp index a033df5d88ac6..90de914b059d6 100644 --- a/lib/SILOptimizer/Utils/Local.cpp +++ b/lib/SILOptimizer/Utils/Local.cpp @@ -1,14 +1,14 @@ -//===--- Local.cpp - Functions that perform local SIL transformations. ---===// +//===--- Local.cpp - Functions that perform local SIL transformations. ----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" @@ -20,6 +20,7 @@ #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" @@ -171,7 +172,7 @@ void swift::eraseUsesOfInstruction(SILInstruction *Inst, } void swift::eraseUsesOfValue(SILValue V) { - for (auto UI = V.use_begin(), E = V.use_end(); UI != E;) { + for (auto UI = V->use_begin(), E = V->use_end(); UI != E;) { auto *User = UI->getUser(); UI++; @@ -211,7 +212,7 @@ FullApplySite swift::findApplyFromDevirtualizedResult(SILInstruction *I) { if (isa(I) || isa(I) || isa(I)) return findApplyFromDevirtualizedResult( - dyn_cast(I->getOperand(0).getDef())); + dyn_cast(I->getOperand(0))); return FullApplySite(); } @@ -270,7 +271,7 @@ bool swift::computeMayBindDynamicSelf(SILFunction *F) { } /// Find a new position for an ApplyInst's FuncRef so that it dominates its -/// use. Not that FuncionRefInsts may be shared by multiple ApplyInsts. +/// use. Not that FunctionRefInsts may be shared by multiple ApplyInsts. void swift::placeFuncRef(ApplyInst *AI, DominanceInfo *DT) { FunctionRefInst *FuncRef = cast(AI->getCallee()); SILBasicBlock *DomBB = @@ -341,8 +342,8 @@ SILLinkage swift::getSpecializedLinkage(SILFunction *F, SILLinkage L) { // Treat stdlib_binary_only specially. We don't serialize the body of // stdlib_binary_only functions so we can't mark them as Shared (making // their visibility in the dylib hidden). - return F->hasSemanticsString("stdlib_binary_only") ? SILLinkage::Public - : SILLinkage::Shared; + return F->hasSemanticsAttr("stdlib_binary_only") ? SILLinkage::Public + : SILLinkage::Shared; case SILLinkage::Private: case SILLinkage::PrivateExternal: @@ -510,7 +511,7 @@ Optional swift::castValueToABICompatibleType(SILBuilder *B, SILLocatio LoweredOptionalSrcType); // Cast the wrapped value. return castValueToABICompatibleType(B, Loc, WrappedValue, - WrappedValue.getType(), + WrappedValue->getType(), DestTy); } @@ -625,6 +626,20 @@ bool swift::canCastValueToABICompatibleType(SILModule &M, return Result.hasValue(); } +ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *ABI) { + SILBasicBlock::iterator Iter(ABI); + Iter++; + assert(Iter != ABI->getParent()->end() && + "alloc_box cannot be the last instruction of a block"); + SILInstruction *NextInst = &*Iter; + if (auto *PBI = dyn_cast(NextInst)) { + if (PBI->getOperand() == ABI) + return PBI; + } + + SILBuilder B(NextInst); + return B.createProjectBox(ABI->getLoc(), ABI); +} //===----------------------------------------------------------------------===// // String Concatenation Optimizer @@ -684,8 +699,7 @@ bool StringConcatenationOptimizer::extractStringConcatOperands() { if (!Fn) return false; - if (AI->getNumOperands() != 3 || - !Fn->hasSemanticsString("string.concat")) + if (AI->getNumOperands() != 3 || !Fn->hasSemanticsAttr("string.concat")) return false; // Left and right operands of a string concatenation operation. @@ -708,12 +722,9 @@ bool StringConcatenationOptimizer::extractStringConcatOperands() { FRIRightFun->getEffectsKind() >= EffectsKind::ReadWrite) return false; - if (!FRILeftFun->hasDefinedSemantics() || - !FRIRightFun->hasDefinedSemantics()) + if (!FRILeftFun->hasSemanticsAttrs() || !FRIRightFun->hasSemanticsAttrs()) return false; - auto SemanticsLeft = FRILeftFun->getSemanticsString(); - auto SemanticsRight = FRIRightFun->getSemanticsString(); auto AILeftOperandsNum = AILeft->getNumOperands(); auto AIRightOperandsNum = AIRight->getNumOperands(); @@ -721,10 +732,14 @@ bool StringConcatenationOptimizer::extractStringConcatOperands() { // (start: RawPointer, numberOfCodeUnits: Word) // makeUTF8 should have following parameters: // (start: RawPointer, byteSize: Word, isASCII: Int1) - if (!((SemanticsLeft == "string.makeUTF16" && AILeftOperandsNum == 4) || - (SemanticsLeft == "string.makeUTF8" && AILeftOperandsNum == 5) || - (SemanticsRight == "string.makeUTF16" && AIRightOperandsNum == 4) || - (SemanticsRight == "string.makeUTF8" && AIRightOperandsNum == 5))) + if (!((FRILeftFun->hasSemanticsAttr("string.makeUTF16") && + AILeftOperandsNum == 4) || + (FRILeftFun->hasSemanticsAttr("string.makeUTF8") && + AILeftOperandsNum == 5) || + (FRIRightFun->hasSemanticsAttr("string.makeUTF16") && + AIRightOperandsNum == 4) || + (FRIRightFun->hasSemanticsAttr("string.makeUTF8") && + AIRightOperandsNum == 5))) return false; SLILeft = dyn_cast(AILeft->getOperand(1)); @@ -848,13 +863,13 @@ SILInstruction *StringConcatenationOptimizer::optimize() { // Length of the concatenated literal according to its encoding. auto *Len = Builder.createIntegerLiteral( - AI->getLoc(), AILeft->getOperand(2).getType(), getConcatenatedLength()); + AI->getLoc(), AILeft->getOperand(2)->getType(), getConcatenatedLength()); Arguments.push_back(Len); // isAscii flag for UTF8-encoded string literals. if (Encoding == StringLiteralInst::Encoding::UTF8) { bool IsAscii = isAscii(); - auto ILType = AILeft->getOperand(3).getType(); + auto ILType = AILeft->getOperand(3)->getType(); auto *Ascii = Builder.createIntegerLiteral(AI->getLoc(), ILType, intmax_t(IsAscii)); Arguments.push_back(Ascii); @@ -907,12 +922,12 @@ void swift::releasePartialApplyCapturedArg(SILBuilder &Builder, SILLocation Loc, } // If we have a trivial type, we do not need to put in any extra releases. - if (Arg.getType().isTrivial(Builder.getModule())) + if (Arg->getType().isTrivial(Builder.getModule())) return; // Otherwise, we need to destroy the argument. - if (Arg.getType().isObject()) { - if (Arg.getType().hasReferenceSemantics()) { + if (Arg->getType().isObject()) { + if (Arg->getType().hasReferenceSemantics()) { auto U = Builder.emitStrongRelease(Loc, Arg); if (U.isNull()) return; @@ -952,7 +967,7 @@ static void releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *PAI, SILBuilderWithScope Builder(PAI); SILLocation Loc = PAI->getLoc(); CanSILFunctionType PAITy = - dyn_cast(PAI->getCallee().getType().getSwiftType()); + dyn_cast(PAI->getCallee()->getType().getSwiftType()); // Emit a destroy value for each captured closure argument. ArrayRef Params = PAITy->getParameters(); @@ -999,9 +1014,9 @@ bool swift::tryDeleteDeadClosure(SILInstruction *Closure, // Then delete all user instructions. for (auto *User : Tracker.getTrackedUsers()) { - assert(User->getNumTypes() == 0 && "We expect only ARC operations without " - "results. This is true b/c of " - "isARCOperationRemovableIfObjectIsDead"); + assert(!User->hasValue() && "We expect only ARC operations without " + "results. This is true b/c of " + "isARCOperationRemovableIfObjectIsDead"); Callbacks.DeleteInst(User); } @@ -1064,7 +1079,7 @@ bool ValueLifetimeAnalysis::successorHasLiveIn(SILBasicBlock *BB) { SILInstruction *ValueLifetimeAnalysis:: findLastDirectUseInBlock(SILBasicBlock *BB) { for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - assert(DefValue.getDef() != &*II && "Found def before finding use!"); + assert(DefValue != &*II && "Found def before finding use!"); for (auto &Oper : II->getAllOperands()) { if (Oper.get() != DefValue) @@ -1081,7 +1096,7 @@ findLastDirectUseInBlock(SILBasicBlock *BB) { SILInstruction *ValueLifetimeAnalysis:: findLastSpecifiedUseInBlock(SILBasicBlock *BB) { for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - assert(DefValue.getDef() != &*II && "Found def before finding use!"); + assert(DefValue != &*II && "Found def before finding use!"); if (UserSet.count(&*II)) return &*II; @@ -1106,7 +1121,7 @@ ValueLifetime ValueLifetimeAnalysis::computeLastUsers() { // Casts Optimization and Simplification //===----------------------------------------------------------------------===// -/// \brief Get a substitution corresponding to the type witness. +/// \brief Get a substitution corresponding to the type witness. /// Inspired by ProtocolConformance::getTypeWitnessByName. static const Substitution * getTypeWitnessByName(ProtocolConformance *conformance, Identifier name) { @@ -1154,7 +1169,7 @@ static Type getCastFromObjC(SILModule &M, CanType source, CanType target) { } /// Create a call of _forceBridgeFromObjectiveC_bridgeable or -/// _conditionallyBridgeFromObjectiveC_bridgeable which converts an an ObjC +/// _conditionallyBridgeFromObjectiveC_bridgeable which converts an ObjC /// instance into a corresponding Swift type, conforming to /// _ObjectiveCBridgeable. SILInstruction * @@ -1173,7 +1188,7 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, auto Loc = Inst->getLoc(); // The conformance to _BridgedToObjectiveC is statically known. - // Retrieve the bridging operation to be used if a static conformance + // Retrieve the bridging operation to be used if a static conformance // to _BridgedToObjectiveC can be proven. FuncDecl *BridgeFuncDecl = isConditional @@ -1198,10 +1213,10 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, SILValue SrcOp; SILInstruction *NewI = nullptr; - assert(Src.getType().isAddress() && "Source should have an address type"); - assert(Dest.getType().isAddress() && "Source should have an address type"); + assert(Src->getType().isAddress() && "Source should have an address type"); + assert(Dest->getType().isAddress() && "Source should have an address type"); - if (SILBridgedTy != Src.getType()) { + if (SILBridgedTy != Src->getType()) { // Check if we can simplify a cast into: // - ObjCTy to _ObjectiveCBridgeable._ObjectiveCType. // - then convert _ObjectiveCBridgeable._ObjectiveCType to @@ -1219,24 +1234,24 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, if (isConditional) { SILBasicBlock *CastSuccessBB = Inst->getFunction()->createBasicBlock(); CastSuccessBB->createBBArg(SILBridgedTy); - Builder.createBranch(Loc, CastSuccessBB, SILValue(Load,0)); + Builder.createBranch(Loc, CastSuccessBB, SILValue(Load)); Builder.setInsertionPoint(CastSuccessBB); - SrcOp = SILValue(CastSuccessBB->getBBArg(0), 0); + SrcOp = CastSuccessBB->getBBArg(0); } else { SrcOp = Load; } } else if (isConditional) { SILBasicBlock *CastSuccessBB = Inst->getFunction()->createBasicBlock(); CastSuccessBB->createBBArg(SILBridgedTy); - NewI = Builder.createCheckedCastBranch(Loc, false, SILValue(Load, 0), + NewI = Builder.createCheckedCastBranch(Loc, false, Load, SILBridgedTy, CastSuccessBB, FailureBB); Builder.setInsertionPoint(CastSuccessBB); - SrcOp = SILValue(CastSuccessBB->getBBArg(0), 0); + SrcOp = CastSuccessBB->getBBArg(0); } else { - NewI = Builder.createUnconditionalCheckedCast(Loc, SILValue(Load, 0), + NewI = Builder.createUnconditionalCheckedCast(Loc, Load, SILBridgedTy); - SrcOp = SILValue(NewI, 0); + SrcOp = NewI; } } else { SrcOp = Src; @@ -1267,19 +1282,15 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, auto *MetaTyVal = Builder.createMetatype(Loc, SILMetaTy); SmallVector Args; - auto PolyFuncTy = BridgeFuncDecl->getType()->getAs(); - ArrayRef Archetypes = - PolyFuncTy->getGenericParams().getAllArchetypes(); - // Add substitutions SmallVector Subs; - auto Conformances = M.getASTContext().Allocate(1); - Conformances[0] = Conformance; - Subs.push_back(Substitution(Archetypes[0], Target, Conformances)); + auto Conformances = + M.getASTContext().AllocateUninitialized(1); + Conformances[0] = ProtocolConformanceRef(Conformance); + Subs.push_back(Substitution(Target, Conformances)); const Substitution *DepTypeSubst = getTypeWitnessByName( Conformance, M.getASTContext().getIdentifier("_ObjectiveCType")); - Subs.push_back(Substitution(Archetypes[1], DepTypeSubst->getReplacement(), - DepTypeSubst->getConformances())); + Subs.push_back(*DepTypeSubst); auto SILFnTy = FuncRef->getType(); SILType SubstFnTy = SILFnTy.substGenericArgs(M, Subs); SILType ResultTy = SubstFnTy.castTo()->getSILResult(); @@ -1291,13 +1302,13 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, SILValue InOutOptionalParam; if (isConditional) { // Create a temporary - OptionalTy = OptionalType::get(Dest.getType().getSwiftRValueType()) + OptionalTy = OptionalType::get(Dest->getType().getSwiftRValueType()) ->getImplementationType() .getCanonicalTypeOrNull(); OptionalTy.getAnyOptionalObjectType(OTK); Tmp = Builder.createAllocStack(Loc, SILType::getPrimitiveObjectType(OptionalTy)); - InOutOptionalParam = SILValue(Tmp, 1); + InOutOptionalParam = Tmp; } else { InOutOptionalParam = Dest; } @@ -1311,7 +1322,7 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, Args.push_back(InOutOptionalParam); Args.push_back(SrcOp); - Args.push_back(SILValue(MetaTyVal, 0)); + Args.push_back(MetaTyVal); auto *AI = Builder.createApply(Loc, FuncRef, SubstFnTy, ResultTy, Subs, Args, false); @@ -1348,17 +1359,17 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst, Builder.createSwitchEnumAddr(Loc, InOutOptionalParam, ConvSuccessBB, CaseBBs); Builder.setInsertionPoint(FailureBB->begin()); - Builder.createDeallocStack(Loc, SILValue(Tmp, 0)); + Builder.createDeallocStack(Loc, Tmp); Builder.setInsertionPoint(ConvSuccessBB); auto Addr = Builder.createUncheckedTakeEnumDataAddr(Loc, InOutOptionalParam, SomeDecl); - auto LoadFromOptional = Builder.createLoad(Loc, SILValue(Addr, 0)); + auto LoadFromOptional = Builder.createLoad(Loc, Addr); // Store into Dest Builder.createStore(Loc, LoadFromOptional, Dest); - Builder.createDeallocStack(Loc, SILValue(Tmp, 0)); + Builder.createDeallocStack(Loc, Tmp); SmallVector SuccessBBArgs; Builder.createBranch(Loc, SuccessBB, SuccessBBArgs); } @@ -1476,9 +1487,9 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst, SILType ResultTy = SubstFnTy.castTo()->getSILResult(); auto FnRef = Builder.createFunctionRef(Loc, BridgedFunc); - if (Src.getType().isAddress()) { + if (Src->getType().isAddress()) { // Create load - Src = SILValue(Builder.createLoad(Loc, Src), 0); + Src = Builder.createLoad(Loc, Src); } if(ParamTypes[0].getConvention() == ParameterConvention::Direct_Guaranteed) @@ -1496,13 +1507,12 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst, if (Dest) { // If it is addr cast then store the result. auto ConvTy = NewAI->getType(); - auto DestTy = Dest.getType().getObjectType(); + auto DestTy = Dest->getType().getObjectType(); assert((ConvTy == DestTy || DestTy.isSuperclassOf(ConvTy)) && "Destination should have the same type or be a superclass " "of the source operand"); auto CastedValue = SILValue( - (ConvTy == DestTy) ? NewI : Builder.createUpcast(Loc, NewAI, DestTy), - 0); + (ConvTy == DestTy) ? NewI : Builder.createUpcast(Loc, NewAI, DestTy)); NewI = Builder.createStore(Loc, CastedValue, Dest); } @@ -1612,8 +1622,8 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { // Check if we can statically predict the outcome of the cast. auto Feasibility = classifyDynamicCast(Mod.getSwiftModule(), - Src.getType().getSwiftRValueType(), - Dest.getType().getSwiftRValueType(), + Src->getType().getSwiftRValueType(), + Dest->getType().getSwiftRValueType(), isSourceTypeExact, Mod.isWholeModule()); @@ -1623,7 +1633,7 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { if (Feasibility == DynamicCastFeasibility::WillFail) { if (shouldDestroyOnFailure(Inst->getConsumptionKind())) { - auto &srcTL = Builder.getModule().getTypeLowering(Src.getType()); + auto &srcTL = Builder.getModule().getTypeLowering(Src->getType()); srcTL.emitDestroyAddress(Builder, Loc, Src); } auto NewI = Builder.createBranch(Loc, FailureBB); @@ -1637,8 +1647,8 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { // Replace by unconditional_addr_cast, followed by a branch. // The unconditional_addr_cast can be skipped, if the result of a cast // is not used afterwards. - bool ResultNotUsed = isa(Dest.getDef()); - for (auto Use : Dest.getUses()) { + bool ResultNotUsed = isa(Dest); + for (auto Use : Dest->getUses()) { auto *User = Use->getUser(); if (isa(User) || User == Inst) continue; @@ -1659,7 +1669,7 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { if (!BridgedI) { // Since it is an addr cast, only address types are handled here. - if (!Src.getType().isAddress() || !Dest.getType().isAddress()) { + if (!Src->getType().isAddress() || !Dest->getType().isAddress()) { return nullptr; } else if (!emitSuccessfulIndirectUnconditionalCast( Builder, Mod.getSwiftModule(), Loc, @@ -1690,7 +1700,7 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { SILInstruction * CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) { if (Inst->isExact()) { - auto *ARI = dyn_cast(Inst->getOperand().stripUpCasts()); + auto *ARI = dyn_cast(stripUpCasts(Inst->getOperand())); if (!ARI) return nullptr; @@ -1723,7 +1733,7 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) { if (!Inst) return nullptr; - auto LoweredSourceType = Inst->getOperand().getType(); + auto LoweredSourceType = Inst->getOperand()->getType(); auto LoweredTargetType = Inst->getCastType(); auto SourceType = LoweredSourceType.getSwiftRValueType(); auto TargetType = LoweredTargetType.getSwiftRValueType(); @@ -1761,7 +1771,7 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) { // is not used afterwards. bool ResultNotUsed = SuccessBB->getBBArg(0)->use_empty(); SILValue CastedValue; - if (Op.getType() != LoweredTargetType) { + if (Op->getType() != LoweredTargetType) { if (!ResultNotUsed) { auto Src = Inst->getOperand(); auto Dest = SILValue(); @@ -1770,7 +1780,7 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) { TargetType, nullptr, nullptr); if (BridgedI) { - CastedValue = SILValue(BridgedI, 0); + CastedValue = BridgedI; } else { if (!canUseScalarCheckedCastInstructions(Mod, SourceType, TargetType)) return nullptr; @@ -1807,7 +1817,7 @@ optimizeCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { auto *FailureBB = Inst->getFailureBB(); // If there is an unbound generic type involved in the cast, bail. - if (Src.getType().hasArchetype() || Dest.getType().hasArchetype()) + if (Src->getType().hasArchetype() || Dest->getType().hasArchetype()) return nullptr; // %1 = metatype $A.Type @@ -1819,7 +1829,7 @@ optimizeCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { // %1 = metatype $A.Type // %c = checked_cast_br %1 to ... // store %c to %3 (if successful) - if (auto *ASI = dyn_cast(Src.getDef())) { + if (auto *ASI = dyn_cast(Src)) { // Check if the value of this alloc_stack is set only once by a store // instruction, used only by CCABI and then deallocated. bool isLegal = true; @@ -1853,12 +1863,12 @@ optimizeCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) { if (SuccessBB->getSinglePredecessor() && canUseScalarCheckedCastInstructions(Inst->getModule(), MI->getType().getSwiftRValueType(), - Dest.getType().getObjectType().getSwiftRValueType())) { + Dest->getType().getObjectType().getSwiftRValueType())) { SILBuilderWithScope B(Inst); auto NewI = B.createCheckedCastBranch( - Loc, false /*isExact*/, SILValue(MI, 0), - Dest.getType().getObjectType(), SuccessBB, FailureBB); - SuccessBB->createBBArg(Dest.getType().getObjectType(), nullptr); + Loc, false /*isExact*/, MI, + Dest->getType().getObjectType(), SuccessBB, FailureBB); + SuccessBB->createBBArg(Dest->getType().getObjectType(), nullptr); B.setInsertionPoint(SuccessBB->begin()); // Store the result B.createStore(Loc, SuccessBB->getBBArg(0), Dest); @@ -1921,12 +1931,12 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) { // Should be in the same BB. if (ASI->getParent() != EMI->getParent()) return nullptr; - // Check if this alloc_stac is is only initialized once by means of + // Check if this alloc_stack is only initialized once by means of // single init_existential_addr. bool isLegal = true; // init_existential instruction used to initialize this alloc_stack. InitExistentialAddrInst *FoundIEI = nullptr; - for (auto Use: getNonDebugUses(*ASI)) { + for (auto Use: getNonDebugUses(ASI)) { auto *User = Use->getUser(); if (isa(User) || isa(User) || @@ -1982,10 +1992,10 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) { // Should be in the same BB. if (ASRI->getParent() != EMI->getParent()) return nullptr; - // Check if this alloc_stac is is only initialized once by means of - // a single initt_existential_ref. + // Check if this alloc_stack is only initialized once by means of + // a single init_existential_ref. bool isLegal = true; - for (auto Use: getNonDebugUses(*ASRI)) { + for (auto Use: getNonDebugUses(ASRI)) { auto *User = Use->getUser(); if (isa(User) || isa(User)) continue; @@ -2030,7 +2040,7 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) { ValueBase * CastOptimizer:: optimizeUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *Inst) { - auto LoweredSourceType = Inst->getOperand().getType(); + auto LoweredSourceType = Inst->getOperand()->getType(); auto LoweredTargetType = Inst->getType(); auto Loc = Inst->getLoc(); auto Op = Inst->getOperand(); @@ -2099,10 +2109,10 @@ optimizeUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *Inst) { return nullptr; } - ReplaceInstUsesAction(Inst, Result.getDef()); + ReplaceInstUsesAction(Inst, Result); EraseInstAction(Inst); WillSucceedAction(); - return Result.getDef(); + return Result; } return nullptr; @@ -2139,7 +2149,7 @@ optimizeUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *Inst) SILInstruction *NewI = Builder.createBuiltinTrap(Loc); // mem2reg's invariants get unhappy if we don't try to // initialize a loadable result. - auto DestType = Dest.getType(); + auto DestType = Dest->getType(); auto &resultTL = Mod.Types.getTypeLowering(DestType); if (!resultTL.isAddressOnly()) { auto undef = SILValue(SILUndef::get(DestType.getObjectType(), @@ -2156,8 +2166,8 @@ optimizeUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *Inst) if (Feasibility == DynamicCastFeasibility::WillSucceed || Feasibility == DynamicCastFeasibility::MaySucceed) { - bool ResultNotUsed = isa(Dest.getDef()); - for (auto Use : Dest.getUses()) { + bool ResultNotUsed = isa(Dest); + for (auto Use : Dest->getUses()) { auto *User = Use->getUser(); if (isa(User) || User == Inst) continue; @@ -2206,13 +2216,13 @@ bool swift::simplifyUsers(SILInstruction *I) { SILInstruction *User = UI->getUser(); ++UI; - if (User->getNumTypes() != 1) + if (!User->hasValue()) continue; SILValue S = simplifyInstruction(User); if (!S) continue; - SILValue(User).replaceAllUsesWith(S); + User->replaceAllUsesWith(S); User->eraseFromParent(); Changed = true; } @@ -2252,7 +2262,8 @@ swift::analyzeStaticInitializer(SILValue V, return false; while (true) { - Insns.push_back(I); + if (!isa(I)) + Insns.push_back(I); if (auto *SI = dyn_cast(I)) { // If it is not a struct which is a simple type, bail. if (!isSimpleType(SI->getType(), I->getModule())) @@ -2299,9 +2310,9 @@ swift::analyzeStaticInitializer(SILValue V, return false; } -/// Replace load sequence which may contian +/// Replace load sequence which may contain /// a chain of struct_element_addr followed by a load. -/// The sequence is travered inside out, i.e. +/// The sequence is traversed inside out, i.e. /// starting with the innermost struct_element_addr /// Move into utils. void swift::replaceLoadSequence(SILInstruction *I, @@ -2365,3 +2376,53 @@ bool swift::calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl) { return true; } } + +void swift::hoistAddressProjections(Operand &Op, SILInstruction *InsertBefore, + DominanceInfo *DomTree) { + SILValue V = Op.get(); + SILInstruction *Prev = nullptr; + auto *InsertPt = InsertBefore; + while (true) { + SILValue Incoming = stripSinglePredecessorArgs(V); + + // Forward the incoming arg from a single predecessor. + if (V != Incoming) { + if (V == Op.get()) { + // If we are the operand itself set the operand to the incoming + // argument. + Op.set(Incoming); + V = Incoming; + } else { + // Otherwise, set the previous projections operand to the incoming + // argument. + assert(Prev && "Must have seen a projection"); + Prev->setOperand(0, Incoming); + V = Incoming; + } + } + + switch (V->getKind()) { + case ValueKind::StructElementAddrInst: + case ValueKind::TupleElementAddrInst: + case ValueKind::RefElementAddrInst: + case ValueKind::UncheckedTakeEnumDataAddrInst: { + auto *Inst = cast(V); + // We are done once the current projection dominates the insert point. + if (DomTree->dominates(Inst->getParent(), InsertBefore->getParent())) + return; + + // Move the current projection and memorize it for the next iteration. + Prev = Inst; + Inst->moveBefore(InsertPt); + InsertPt = Inst; + V = Inst->getOperand(0); + continue; + } + default: + assert(DomTree->dominates(V->getParentBB(), InsertBefore->getParent()) && + "The projected value must dominate the insertion point"); + return; + } + } +} + diff --git a/lib/SILOptimizer/Utils/LoopUtils.cpp b/lib/SILOptimizer/Utils/LoopUtils.cpp index fe5e3fcfdb9d7..146c6efc5a38b 100644 --- a/lib/SILOptimizer/Utils/LoopUtils.cpp +++ b/lib/SILOptimizer/Utils/LoopUtils.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,33 +23,67 @@ using namespace swift; -static SILBasicBlock *getSingleOutsideLoopPredecessor(SILLoop *L, - SILBasicBlock *BB) { - SmallVector Preds; - for (auto *Pred : BB->getPreds()) - if (!L->contains(Pred)) - Preds.push_back(Pred); - if (Preds.size() != 1) - return nullptr; - return Preds[0]; +static SILBasicBlock *createInitialPreheader(SILBasicBlock *Header) { + auto *Preheader = new (Header->getModule()) + SILBasicBlock(Header->getParent(), &*std::prev(Header->getIterator())); + + // Clone the arguments from header into the pre-header. + llvm::SmallVector Args; + for (auto *HeaderArg : Header->getBBArgs()) { + Args.push_back(Preheader->createBBArg(HeaderArg->getType(), nullptr)); + } + + // Create the branch to the header. + SILBuilder(Preheader) + .createBranch(SILFileLocation(SourceLoc()), Header, Args); + + return Preheader; } -/// \brief Try to create a unique loop preheader. -/// -/// FIXME: We should handle merging multiple loop predecessors. -static SILBasicBlock* insertPreheader(SILLoop *L, DominanceInfo *DT, +/// \brief Create a unique loop preheader. +static SILBasicBlock *insertPreheader(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI) { assert(!L->getLoopPreheader() && "Expect multiple preheaders"); - SILBasicBlock *Header = L->getHeader(); - SILBasicBlock *Preheader = nullptr; - if (auto LoopPred = getSingleOutsideLoopPredecessor(L, Header)) { - if (isa(LoopPred->getTerminator())) { - Preheader = splitIfCriticalEdge(LoopPred, Header, DT, LI); - DEBUG(llvm::dbgs() << "Created preheader for loop: " << *L); - assert(Preheader && "Must have a preheader now"); + + // Before we create the preheader, gather all of the original preds of header. + llvm::SmallVector Preds; + for (auto *Pred : Header->getPreds()) { + if (!L->contains(Pred)) { + Preds.push_back(Pred); + } + } + + // Then create the pre-header and connect it to header. + SILBasicBlock *Preheader = createInitialPreheader(Header); + + // Then change all of the original predecessors to target Preheader instead of + // header. + for (auto *Pred : Preds) { + replaceBranchTarget(Pred->getTerminator(), Header, Preheader, + true /*PreserveArgs*/); + } + + // Update dominance info. + if (DT) { + // Get the dominance node of the header. + auto *HeaderBBDTNode = DT->getNode(Header); + if (HeaderBBDTNode) { + // Make a DTNode for the preheader and make the header's immediate + // dominator, the immediate dominator of the pre-header. + auto *PreheaderDTNode = + DT->addNewBlock(Preheader, HeaderBBDTNode->getIDom()->getBlock()); + // Then change the immediate dominator of the header to be the pre-header. + HeaderBBDTNode->setIDom(PreheaderDTNode); } } + + // Make the pre-header a part of the parent loop of L if L has a parent loop. + if (LI) { + if (auto *PLoop = L->getParentLoop()) + PLoop->addBasicBlockToLoop(Preheader, LI->getBase()); + } + return Preheader; } @@ -197,9 +231,8 @@ static bool canonicalizeLoopExitBlocks(SILLoop *L, DominanceInfo *DT, bool swift::canonicalizeLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI) { bool ChangedCFG = false; if (!L->getLoopPreheader()) { - if (!insertPreheader(L, DT, LI)) - // Skip further simplification with no preheader. - return ChangedCFG; + insertPreheader(L, DT, LI); + assert(L->getLoopPreheader() && "L should have a pre-header now"); ChangedCFG = true; } diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index a43edf4545ec6..3c28dd8b9f34f 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -1,8 +1,8 @@ -//===--- SILInliner.cpp - Inlines SIL functions ----------------------------==// +//===--- SILInliner.cpp - Inlines SIL functions ---------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -112,7 +112,7 @@ bool SILInliner::inlineFunction(FullApplySite AI, ArrayRef Args) { if (ReturnInst *RI = dyn_cast(CalleeEntryBB->getTerminator())) { // Replace all uses of the apply instruction with the operands of the // return instruction, appropriately mapped. - SILValue(nonTryAI).replaceAllUsesWith(remapValue(RI->getOperand())); + nonTryAI->replaceAllUsesWith(remapValue(RI->getOperand())); return true; } } @@ -137,10 +137,10 @@ bool SILInliner::inlineFunction(FullApplySite AI, ArrayRef Args) { SILFunction::iterator(ReturnToBB)); // Create an argument on the return-to BB representing the returned value. - SILValue RetArg = new (F.getModule()) SILArgument(ReturnToBB, - AI.getInstruction()->getType(0)); + auto *RetArg = new (F.getModule()) SILArgument(ReturnToBB, + AI.getInstruction()->getType()); // Replace all uses of the ApplyInst with the new argument. - SILValue(AI.getInstruction()).replaceAllUsesWith(RetArg); + AI.getInstruction()->replaceAllUsesWith(RetArg); } // Now iterate over the callee BBs and fix up the terminators. @@ -228,6 +228,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case ValueKind::FixLifetimeInst: case ValueKind::MarkDependenceInst: case ValueKind::FunctionRefInst: + case ValueKind::AllocGlobalInst: case ValueKind::GlobalAddrInst: return InlineCost::Free; @@ -280,7 +281,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case ValueKind::MetatypeInst: // Thin metatypes are always free. - if (I.getType(0).castTo()->getRepresentation() + if (I.getType().castTo()->getRepresentation() == MetatypeRepresentation::Thin) return InlineCost::Free; // TODO: Thick metatypes are free if they don't require generic or lazy @@ -332,6 +333,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case ValueKind::DestroyAddrInst: case ValueKind::ProjectValueBufferInst: case ValueKind::ProjectBoxInst: + case ValueKind::ProjectExistentialBoxInst: case ValueKind::ReleaseValueInst: case ValueKind::AutoreleaseValueInst: case ValueKind::DynamicMethodBranchInst: diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index ed9989617db85..7d19f9d0f9a14 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -1,8 +1,8 @@ -//===------ SILSSAUpdater.h - Unstructured SSA Update Tool ------*- C++ -*-===// +//===--- SILSSAUpdater.cpp - Unstructured SSA Update Tool -----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -101,7 +101,7 @@ void SILSSAUpdater::RewriteUse(Operand &Op) { "The function_refs need to have the same value"); SILInstruction *User = Op.getUser(); auto *NewFR = FR->clone(User); - Op.set(SILValue(NewFR, Op.get().getResultNumber())); + Op.set(NewFR); return; } else if (auto *IL = dyn_cast(Op.get())) if (areIdentical(getAvailVals(AV))) { @@ -109,7 +109,7 @@ void SILSSAUpdater::RewriteUse(Operand &Op) { // ctlz). SILInstruction *User = Op.getUser(); auto *NewIL = IL->clone(User); - Op.set(SILValue(NewIL, Op.get().getResultNumber())); + Op.set(NewIL); return; } @@ -173,7 +173,15 @@ SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) { SILValue SingularValue; SmallVector, 4> PredVals; bool FirstPred = true; + + // SSAUpdater can modify TerminatorInst and therefore invalidate the + // predecessor iterator. Find all the predecessors before the SSA update. + SmallVector Preds; for (auto *PredBB: BB->getPreds()) { + Preds.push_back(PredBB); + } + + for (auto *PredBB : Preds) { SILValue PredVal = GetValueAtEndOfBlock(PredBB); PredVals.push_back(std::make_pair(PredBB, PredVal)); if (FirstPred) { @@ -196,7 +204,7 @@ SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) { PredVals.end()); for (auto *Arg : BB->getBBArgs()) if (isEquivalentPHI(Arg, ValueMap)) - return SILValue(Arg, 0); + return Arg; } @@ -208,7 +216,7 @@ SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) { if (InsertedPHIs) InsertedPHIs->push_back(PHI); - return SILValue(PHI, 0); + return PHI; } /// SSAUpdaterTraits - Traits for the SSAUpdaterImpl @@ -298,20 +306,20 @@ class SSAUpdaterTraits { static SILValue GetUndefVal(SILBasicBlock *BB, SILSSAUpdater *Updater) { - return SILValue(SILUndef::get(Updater->ValType, &BB->getModule()), 0); + return SILUndef::get(Updater->ValType, &BB->getModule()); } /// Add an Argument to the basic block. static SILValue CreateEmptyPHI(SILBasicBlock *BB, unsigned NumPreds, SILSSAUpdater *Updater) { // Add the argument to the block. - SILValue PHI(new (BB->getModule()) SILArgument(BB, Updater->ValType), 0); + SILValue PHI(new (BB->getModule()) SILArgument(BB, Updater->ValType)); // Mark all predecessor blocks with the sentinel undef value. SmallVector Preds(BB->pred_begin(), BB->pred_end()); for (auto *PredBB: Preds) { TermInst *TI = PredBB->getTerminator(); - addNewEdgeValueToBranch(TI, BB, SILValue(Updater->PHISentinel.get(), 0)); + addNewEdgeValueToBranch(TI, BB, Updater->PHISentinel.get()); } return PHI; } @@ -336,7 +344,7 @@ class SSAUpdaterTraits { /// ValueIsPHI - Check if the instruction that defines the specified register /// is a PHI instruction. static SILArgument *ValueIsPHI(SILValue V, SILSSAUpdater *Updater) { - return InstrIsPHI(V.getDef()); + return InstrIsPHI(V); } /// Like ValueIsPHI but also check if the PHI has no source @@ -356,7 +364,7 @@ class SSAUpdaterTraits { SILValue V = Edges[PhiIdx]; // Check for the 'not set' sentinel. - if (V.getDef() != Updater->PHISentinel.get()) + if (V != Updater->PHISentinel.get()) return nullptr; } return PHI; @@ -365,7 +373,7 @@ class SSAUpdaterTraits { } static SILValue GetPHIValue(SILArgument *PHI) { - return SILValue(PHI, 0); + return PHI; } }; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index bcc2b0c84098d..d806ecc7fb5e1 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,6 +21,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" +#include "swift/Basic/StringExtras.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" @@ -29,7 +30,7 @@ using namespace swift; using namespace constraints; -/// \brief Get a substitution corresponding to the type witness. +/// \brief Get a substitution corresponding to the type witness. /// Inspired by ProtocolConformance::getTypeWitnessByName. const Substitution * getTypeWitnessByName(ProtocolConformance *conformance, @@ -106,7 +107,7 @@ Type Solution::computeSubstitutions( auto currentModule = getConstraintSystem().DC->getParentModule(); ArchetypeType *currentArchetype = nullptr; Type currentReplacement; - SmallVector currentConformances; + SmallVector currentConformances; ArrayRef requirements; if (auto genericFn = origType->getAs()) { @@ -125,34 +126,36 @@ Type Solution::computeSubstitutions( continue; switch (req.getKind()) { - case RequirementKind::Conformance: - // If this is a protocol conformance requirement, get the conformance - // and record it. - if (auto protoType = req.getSecondType()->getAs()) { - assert(firstArchetype == currentArchetype - && "Archetype out-of-sync"); - ProtocolConformance *conformance = nullptr; - Type replacement = currentReplacement; - bool conforms = tc.conformsToProtocol( - replacement, - protoType->getDecl(), - getConstraintSystem().DC, - (ConformanceCheckFlags::InExpression| - ConformanceCheckFlags::Used), - &conformance); - (void)isOpenedAnyObject; - assert((conforms || - firstArchetype->getIsRecursive() || - isOpenedAnyObject(replacement) || - replacement->is()) && - "Constraint system missed a conformance?"); - (void)conforms; - - assert(conformance || replacement->hasDependentProtocolConformances()); - currentConformances.push_back(conformance); + case RequirementKind::Conformance: { + // Get the conformance and record it. + auto protoType = req.getSecondType()->castTo(); + assert(firstArchetype == currentArchetype + && "Archetype out-of-sync"); + ProtocolConformance *conformance = nullptr; + Type replacement = currentReplacement; + bool conforms = tc.conformsToProtocol( + replacement, + protoType->getDecl(), + getConstraintSystem().DC, + (ConformanceCheckFlags::InExpression| + ConformanceCheckFlags::Used), + &conformance); + (void)isOpenedAnyObject; + assert((conforms || + firstArchetype->getIsRecursive() || + isOpenedAnyObject(replacement) || + replacement->is()) && + "Constraint system missed a conformance?"); + (void)conforms; - break; - } + assert(conformance || replacement->hasDependentProtocolConformances()); + currentConformances.push_back( + ProtocolConformanceRef(protoType->getDecl(), conformance)); + break; + } + + case RequirementKind::Superclass: + // Superclass requirements aren't recorded in substitutions. break; case RequirementKind::SameType: @@ -163,7 +166,6 @@ Type Solution::computeSubstitutions( // Flush the current conformances. if (currentArchetype) { substitutions.push_back({ - currentArchetype, currentReplacement, ctx.AllocateCopy(currentConformances) }); @@ -182,7 +184,6 @@ Type Solution::computeSubstitutions( // Flush the final conformances. if (currentArchetype) { substitutions.push_back({ - currentArchetype, currentReplacement, ctx.AllocateCopy(currentConformances), }); @@ -239,7 +240,7 @@ static DeclTy *findNamedWitnessImpl(TypeChecker &tc, DeclContext *dc, Type type, if (!conforms) return nullptr; - // For an type with dependent conformance, just return the requirement from + // For a type with dependent conformance, just return the requirement from // the protocol. There are no protocol conformance tables. if (type->hasDependentProtocolConformances()) { return requirement; @@ -364,7 +365,7 @@ namespace { public: /// \brief Build a reference to the given declaration. - Expr *buildDeclRef(ValueDecl *decl, SourceLoc loc, Type openedType, + Expr *buildDeclRef(ValueDecl *decl, DeclNameLoc loc, Type openedType, ConstraintLocatorBuilder locator, bool specialized, bool implicit, AccessSemantics semantics) { @@ -378,7 +379,8 @@ namespace { auto openedFnType = openedType->castTo(); auto baseTy = simplifyType(openedFnType->getInput()) ->getRValueInstanceType(); - Expr *base = TypeExpr::createImplicitHack(loc, baseTy, ctx); + Expr *base = TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, + ctx); auto result = buildMemberRef(base, openedType, SourceLoc(), decl, loc, openedFnType->getResult(), locator, locator, implicit, semantics, @@ -393,7 +395,7 @@ namespace { // specialized reference to it. if (auto genericFn = decl->getInterfaceType()->getAs()) { - auto dc = decl->getPotentialGenericDeclContext(); + auto dc = decl->getInnermostDeclContext(); SmallVector substitutions; auto type = solution.computeSubstitutions( @@ -410,8 +412,9 @@ namespace { // missing an ampersand in front of the ref. if (auto inoutType = type->getAs()) { auto &tc = cs.getTypeChecker(); - tc.diagnose(loc, diag::missing_address_of, inoutType->getInOutObjectType()) - .fixItInsert(loc, "&"); + tc.diagnose(loc.getBaseNameLoc(), diag::missing_address_of, + inoutType->getInOutObjectType()) + .fixItInsert(loc.getBaseNameLoc(), "&"); return nullptr; } @@ -692,7 +695,7 @@ namespace { /// \brief Build a new member reference with the given base and member. Expr *buildMemberRef(Expr *base, Type openedFullType, SourceLoc dotLoc, - ValueDecl *member, SourceLoc memberLoc, + ValueDecl *member, DeclNameLoc memberLoc, Type openedType, ConstraintLocatorBuilder locator, ConstraintLocatorBuilder memberLocator, bool Implicit, AccessSemantics semantics, @@ -739,7 +742,7 @@ namespace { // Figure out the declaration context where we'll get the generic // parameters. - auto dc = member->getPotentialGenericDeclContext(); + auto dc = member->getInnermostDeclContext(); // Build a reference to the generic member. SmallVector substitutions; @@ -787,12 +790,11 @@ namespace { (cast(func)->hasDynamicSelf() || (openedExistential && cast(func)->hasArchetypeSelf()))) || isPolymorphicConstructor(func)) { - refTy = refTy->replaceCovariantResultType( - containerTy, - func->getNumParamPatterns()); + refTy = refTy->replaceCovariantResultType(containerTy, + func->getNumParameterLists()); dynamicSelfFnType = refTy->replaceCovariantResultType( baseTy, - func->getNumParamPatterns()); + func->getNumParameterLists()); if (openedExistential) { // Replace the covariant result type in the opened type. We need to @@ -803,7 +805,7 @@ namespace { openedType = optObject; openedType = openedType->replaceCovariantResultType( baseTy, - func->getNumParamPatterns()-1); + func->getNumParameterLists()-1); if (optKind != OptionalTypeKind::OTK_None) openedType = OptionalType::get(optKind, openedType); } @@ -941,6 +943,9 @@ namespace { assert((!baseIsInstance || member->isInstanceMember()) && "can't call a static method on an instance"); apply = new (context) DotSyntaxCallExpr(ref, dotLoc, base); + if (Implicit) { + apply->setImplicit(); + } } return finishApply(apply, openedType, nullptr); } @@ -1243,7 +1248,7 @@ namespace { /// \brief Build a new reference to another constructor. Expr *buildOtherConstructorRef(Type openedFullType, - ConstructorDecl *ctor, SourceLoc loc, + ConstructorDecl *ctor, DeclNameLoc loc, ConstraintLocatorBuilder locator, bool implicit) { auto &tc = cs.getTypeChecker(); @@ -1348,13 +1353,13 @@ namespace { if (conformsToBridgedToObjectiveC) { // The conformance to _BridgedToObjectiveC is statically known. - // Retrieve the bridging operation to be used if a static conformance + // Retrieve the bridging operation to be used if a static conformance // to _BridgedToObjectiveC can be proven. fn = conditional ? tc.Context.getConditionallyBridgeFromObjectiveCBridgeable(&tc) : tc.Context.getForceBridgeFromObjectiveCBridgeable(&tc); } else { - // Retrieve the bridging operation to be used if a static conformance + // Retrieve the bridging operation to be used if a static conformance // to _BridgedToObjectiveC cannot be proven. fn = conditional ? tc.Context.getConditionallyBridgeFromObjectiveC(&tc) : tc.Context.getForceBridgeFromObjectiveC(&tc); @@ -1371,20 +1376,18 @@ namespace { // Form a reference to the function. The bridging operations are generic, // so we need to form substitutions and compute the resulting type. auto Conformances = - tc.Context.Allocate(conformance ? 1 : 0); - - if (conformsToBridgedToObjectiveC) - Conformances[0] = conformance; + tc.Context.AllocateUninitialized( + conformance ? 1 : 0); + if (conformsToBridgedToObjectiveC) { + Conformances[0] = ProtocolConformanceRef(bridgedProto, conformance); + } auto fnGenericParams = fn->getGenericSignatureOfContext()->getGenericParams(); - auto firstArchetype - = ArchetypeBuilder::mapTypeIntoContext(fn, fnGenericParams[0]) - ->castTo(); SmallVector Subs; - Substitution sub(firstArchetype, valueType, Conformances); + Substitution sub(valueType, Conformances); Subs.push_back(sub); // Add substitution for the dependent type T._ObjectiveCType. @@ -1393,19 +1396,11 @@ namespace { auto objcAssocType = cast( conformance->getProtocol()->lookupDirect( objcTypeId).front()); - auto objcDepType = DependentMemberType::get(fnGenericParams[0], - objcAssocType, - tc.Context); - auto objcArchetype - = ArchetypeBuilder::mapTypeIntoContext(fn, objcDepType) - ->castTo(); - const Substitution &objcSubst = conformance->getTypeWitness( objcAssocType, &tc); // Create a substitution for the dependent type. Substitution newDepTypeSubst( - objcArchetype, objcSubst.getReplacement(), objcSubst.getConformances()); @@ -1413,7 +1408,8 @@ namespace { } ConcreteDeclRef fnSpecRef(tc.Context, fn, Subs); - Expr *fnRef = new (tc.Context) DeclRefExpr(fnSpecRef, object->getLoc(), + Expr *fnRef = new (tc.Context) DeclRefExpr(fnSpecRef, + DeclNameLoc(object->getLoc()), /*Implicit=*/true); TypeSubstitutionMap subMap; auto genericParam = fnGenericParams[0]; @@ -1432,6 +1428,7 @@ namespace { object->getLoc(), object->getLoc(), MetatypeType::get(valueType)) }; + args[1]->setImplicit(); // Form the argument tuple. Expr *argTuple = TupleExpr::createImplicit(tc.Context, args, {}); @@ -1924,11 +1921,12 @@ namespace { // FIXME: This location info is bogus. auto typeRef = TypeExpr::createImplicitHack(expr->getStartLoc(), type, tc.Context); - Expr *memberRef = new (tc.Context) MemberRefExpr(typeRef, - expr->getStartLoc(), - member, - expr->getStartLoc(), - /*Implicit=*/true); + Expr *memberRef = + new (tc.Context) MemberRefExpr(typeRef, + expr->getStartLoc(), + member, + DeclNameLoc(expr->getStartLoc()), + /*Implicit=*/true); bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC); assert(!failed && "Could not reference string interpolation witness"); (void)failed; @@ -1961,7 +1959,8 @@ namespace { auto memberRef = buildMemberRef( typeRef, choice.openedFullType, segment->getStartLoc(), choice.choice.getDecl(), - segment->getStartLoc(), choice.openedType, + DeclNameLoc(segment->getStartLoc()), + choice.openedType, locator, locator, /*Implicit=*/true, AccessSemantics::Ordinary, /*isDynamic=*/false); @@ -2058,26 +2057,6 @@ namespace { return expr; } - /// \brief Retrieve the type of a reference to the given declaration. - Type getTypeOfDeclReference(ValueDecl *decl, bool isSpecialized) { - if (auto typeDecl = dyn_cast(decl)) { - // Resolve the reference to this type declaration in our - // current context. - auto type = cs.getTypeChecker().resolveTypeInContext(typeDecl, dc, - TR_InExpression, - isSpecialized); - if (!type) - return nullptr; - - // Refer to the metatype of this type. - return MetatypeType::get(type); - } - - return cs.TC.getUnopenedTypeOfReference(decl, Type(), dc, - /*base=*/nullptr, - /*wantInterfaceType=*/true); - } - Expr *visitDeclRefExpr(DeclRefExpr *expr) { auto locator = cs.getConstraintLocator(expr); @@ -2095,10 +2074,10 @@ namespace { // FIXME: Cannibalize the existing DeclRefExpr rather than allocating a // new one? - return buildDeclRef(decl, expr->getLoc(), selected->openedFullType, - locator, expr->isSpecialized(), - expr->isImplicit(), - expr->getAccessSemantics()); + return buildDeclRef(decl, expr->getNameLoc(), selected->openedFullType, + locator, expr->isSpecialized(), + expr->isImplicit(), + expr->getAccessSemantics()); } Expr *visitSuperRefExpr(SuperRefExpr *expr) { @@ -2119,104 +2098,6 @@ namespace { return expr; } - Expr *visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *expr) { - // Resolve the callee to the constructor declaration selected. - auto ctorLocator = cs.getConstraintLocator( - expr, - ConstraintLocator::ConstructorMember); - - auto selected = getOverloadChoiceIfAvailable(ctorLocator); - - // If we didn't form a ConstructorMember constraint, then it - // acts like a normal member reference to '.init'. - if (!selected) { - return applyMemberRefExpr(expr, expr->getSubExpr(), expr->getDotLoc(), - expr->getConstructorLoc(), expr->isImplicit()); - } - - - auto choice = selected->choice; - auto *ctor = cast(choice.getDecl()); - - auto arg = expr->getSubExpr()->getSemanticsProvidingExpr(); - auto &tc = cs.getTypeChecker(); - - // If the subexpression is a metatype, build a direct reference to the - // constructor. - if (arg->getType()->is()) { - return buildMemberRef(expr->getSubExpr(), - selected->openedFullType, - expr->getDotLoc(), - ctor, - expr->getConstructorLoc(), - expr->getType(), - ConstraintLocatorBuilder( - cs.getConstraintLocator(expr)), - ctorLocator, - expr->isImplicit(), - AccessSemantics::Ordinary, - /*isDynamic=*/false); - } - - // The subexpression must be either 'self' or 'super'. - if (!arg->isSuperExpr()) { - // 'super' references have already been fully checked; handle the - // 'self' case below. - bool diagnoseBadInitRef = true; - if (auto dre = dyn_cast(arg)) { - if (dre->getDecl()->getName() == cs.getASTContext().Id_self) { - // We have a reference to 'self'. - diagnoseBadInitRef = false; - - // Make sure the reference to 'self' occurs within an initializer. - if (!dyn_cast_or_null( - cs.DC->getInnermostMethodContext())) { - if (!SuppressDiagnostics) - tc.diagnose(expr->getDotLoc(), - diag::init_delegation_outside_initializer); - return nullptr; - } - } - } - - // If we need to diagnose this as a bad reference to an initializer, - // do so now. - if (diagnoseBadInitRef) { - // Determine whether 'super' would have made sense as a base. - bool hasSuper = false; - if (auto func = cs.DC->getInnermostMethodContext()) { - if (auto nominalType - = func->getDeclContext()->getDeclaredTypeOfContext()) { - if (auto classDecl = nominalType->getClassOrBoundGenericClass()) { - hasSuper = classDecl->hasSuperclass(); - } - } - } - - if (SuppressDiagnostics) - return nullptr; - - tc.diagnose(expr->getDotLoc(), diag::bad_init_ref_base, hasSuper); - } - } - - // Build a partial application of the delegated initializer. - Expr *ctorRef = buildOtherConstructorRef( - selected->openedFullType, - ctor, expr->getConstructorLoc(), - cs.getConstraintLocator( - expr, - ConstraintLocator::ConstructorMember), - expr->isImplicit()); - auto *call - = new (cs.getASTContext()) DotSyntaxCallExpr(ctorRef, - expr->getDotLoc(), - expr->getSubExpr()); - return finishApply(call, expr->getType(), - ConstraintLocatorBuilder( - cs.getConstraintLocator(expr))); - } - Expr *visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) { return simplifyExprType(expr); } @@ -2228,7 +2109,7 @@ namespace { auto choice = selected.choice; auto decl = choice.getDecl(); - return buildDeclRef(decl, expr->getLoc(), selected.openedFullType, + return buildDeclRef(decl, expr->getNameLoc(), selected.openedFullType, locator, expr->isSpecialized(), expr->isImplicit(), AccessSemantics::Ordinary); } @@ -2294,9 +2175,16 @@ namespace { } Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { - // Dig out the type of the base, which will be the result - // type of this expression. + // Dig out the type of the base, which will be the result type of this + // expression. If constraint solving resolved this to an UnresolvedType, + // then we're in an ambiguity tolerant mode used for diagnostic + // generation. Just leave this as an unresolved member reference. Type resultTy = simplifyType(expr->getType()); + if (resultTy->is()) { + expr->setType(resultTy); + return expr; + } + Type baseTy = resultTy->getRValueType(); auto &tc = cs.getTypeChecker(); @@ -2355,17 +2243,108 @@ namespace { /// A list of optional injections that have been diagnosed. llvm::SmallPtrSet DiagnosedOptionalInjections; private: + /// Create a member reference to the given constructor. + Expr *applyCtorRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc, + DeclNameLoc nameLoc, bool implicit, + ConstraintLocator *ctorLocator, + ConstructorDecl *ctor, + Type openedType) { + // If the subexpression is a metatype, build a direct reference to the + // constructor. + if (base->getType()->is()) { + return buildMemberRef(base, openedType, dotLoc, ctor, nameLoc, + expr->getType(), + ConstraintLocatorBuilder( + cs.getConstraintLocator(expr)), + ctorLocator, + implicit, + AccessSemantics::Ordinary, + /*isDynamic=*/false); + } + + // The subexpression must be either 'self' or 'super'. + if (!base->isSuperExpr()) { + // 'super' references have already been fully checked; handle the + // 'self' case below. + auto &tc = cs.getTypeChecker(); + bool diagnoseBadInitRef = true; + auto arg = base->getSemanticsProvidingExpr(); + if (auto dre = dyn_cast(arg)) { + if (dre->getDecl()->getName() == cs.getASTContext().Id_self) { + // We have a reference to 'self'. + diagnoseBadInitRef = false; + + // Make sure the reference to 'self' occurs within an initializer. + if (!dyn_cast_or_null( + cs.DC->getInnermostMethodContext())) { + if (!SuppressDiagnostics) + tc.diagnose(dotLoc, diag::init_delegation_outside_initializer); + return nullptr; + } + } + } + + // If we need to diagnose this as a bad reference to an initializer, + // do so now. + if (diagnoseBadInitRef) { + // Determine whether 'super' would have made sense as a base. + bool hasSuper = false; + if (auto func = cs.DC->getInnermostMethodContext()) { + if (auto nominalType + = func->getDeclContext()->getDeclaredTypeOfContext()) { + if (auto classDecl = nominalType->getClassOrBoundGenericClass()) { + hasSuper = classDecl->hasSuperclass(); + } + } + } + + if (SuppressDiagnostics) + return nullptr; + + tc.diagnose(dotLoc, diag::bad_init_ref_base, hasSuper); + } + } + + // Build a partial application of the delegated initializer. + Expr *ctorRef = buildOtherConstructorRef(openedType, ctor, nameLoc, + ctorLocator, implicit); + auto *call = new (cs.getASTContext()) DotSyntaxCallExpr(ctorRef, dotLoc, + base); + return finishApply(call, expr->getType(), + ConstraintLocatorBuilder( + cs.getConstraintLocator(expr))); + } + + Expr *applyMemberRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc, + DeclNameLoc nameLoc, bool implicit) { + // If we have a constructor member, handle it as a constructor. + auto ctorLocator = cs.getConstraintLocator( + expr, + ConstraintLocator::ConstructorMember); + if (auto selected = getOverloadChoiceIfAvailable(ctorLocator)) { + auto choice = selected->choice; + auto *ctor = cast(choice.getDecl()); + return applyCtorRefExpr(expr, base, dotLoc, nameLoc, implicit, + ctorLocator, ctor, selected->openedFullType); + } - Expr *applyMemberRefExpr(Expr *expr, - Expr *base, - SourceLoc dotLoc, - SourceLoc nameLoc, - bool implicit) { // Determine the declaration selected for this overloaded reference. auto memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::Member); - auto selected = getOverloadChoice(memberLocator); + auto selectedElt = getOverloadChoiceIfAvailable(memberLocator); + + if (!selectedElt) { + // If constraint solving resolved this to an UnresolvedType, then we're + // in an ambiguity tolerant mode used for diagnostic generation. Just + // leave this as whatever type of member reference it already is. + Type resultTy = simplifyType(expr->getType()); + assert(resultTy->hasUnresolvedType() && + "Should have a selected member if we got a type"); + expr->setType(resultTy); + return expr; + } + auto selected = *selectedElt; switch (selected.choice.getKind()) { case OverloadChoiceKind::DeclViaBridge: { // Look through an implicitly unwrapped optional. @@ -2416,16 +2395,14 @@ namespace { case OverloadChoiceKind::TupleIndex: { auto baseTy = base->getType()->getRValueType(); - if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)) { + if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)){ base = coerceImplicitlyUnwrappedOptionalToValue(base, objTy, cs.getConstraintLocator(base)); } - return new (cs.getASTContext()) TupleElementExpr( - base, - dotLoc, + return new (cs.getASTContext()) TupleElementExpr(base, dotLoc, selected.choice.getTupleIndex(), - nameLoc, + nameLoc.getBaseNameLoc(), simplifyType(expr->getType())); } @@ -2440,13 +2417,6 @@ namespace { } public: - Expr *visitUnresolvedSelectorExpr(UnresolvedSelectorExpr *expr) { - return applyMemberRefExpr(expr, expr->getBase(), expr->getDotLoc(), - expr->getNameRange().Start, - expr->isImplicit()); - } - - Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { return applyMemberRefExpr(expr, expr->getBase(), expr->getDotLoc(), expr->getNameLoc(), expr->isImplicit()); @@ -3059,12 +3029,13 @@ namespace { tc.diagnose(expr->getLoc(), diag::forced_downcast_noop, toType) .fixItRemove(SourceRange(expr->getLoc(), expr->getCastTypeLoc().getSourceRange().End)); - return sub; + + } else { + tc.diagnose(expr->getLoc(), diag::forced_downcast_coercion, + sub->getType(), toType) + .fixItReplace(SourceRange(expr->getLoc(), expr->getExclaimLoc()), + "as"); } - tc.diagnose(expr->getLoc(), diag::forced_downcast_coercion, - sub->getType(), toType) - .fixItReplace(SourceRange(expr->getLoc(), expr->getExclaimLoc()), - "as"); // Convert the subexpression. bool failed = tc.convertToType(sub, toType, cs.DC); @@ -3260,7 +3231,7 @@ namespace { tc.diagnose(E->getLoc(), diag::missing_undefined_runtime); return nullptr; } - DeclRefExpr *fnRef = new (ctx) DeclRefExpr(undefinedDecl, SourceLoc(), + DeclRefExpr *fnRef = new (ctx) DeclRefExpr(undefinedDecl, DeclNameLoc(), /*Implicit=*/true); StringRef msg = "attempt to evaluate editor placeholder"; Expr *argExpr = new (ctx) StringLiteralExpr(msg, E->getLoc(), @@ -3270,11 +3241,153 @@ namespace { Expr *callExpr = new (ctx) CallExpr(fnRef, argExpr, /*implicit*/true); bool invalid = tc.typeCheckExpression(callExpr, cs.DC, valueType, CTP_CannotFail); + (void) invalid; assert(!invalid && "conversion cannot fail"); E->setSemanticExpr(callExpr); return E; } + Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) { + // Dig out the reference to a declaration. + Expr *subExpr = E->getSubExpr(); + ValueDecl *foundDecl = nullptr; + while (subExpr) { + // Declaration reference. + if (auto declRef = dyn_cast(subExpr)) { + foundDecl = declRef->getDecl(); + break; + } + + // Constructor reference. + if (auto ctorRef = dyn_cast(subExpr)) { + foundDecl = ctorRef->getDecl(); + break; + } + + // Member reference. + if (auto memberRef = dyn_cast(subExpr)) { + foundDecl = memberRef->getMember().getDecl(); + break; + } + + // Dynamic member reference. + if (auto dynMemberRef = dyn_cast(subExpr)) { + foundDecl = dynMemberRef->getMember().getDecl(); + break; + } + + // Look through parentheses. + if (auto paren = dyn_cast(subExpr)) { + subExpr = paren->getSubExpr(); + continue; + } + + // Look through "a.b" to "b". + if (auto dotSyntax = dyn_cast(subExpr)) { + subExpr = dotSyntax->getRHS(); + continue; + } + + // Look through self-rebind expression. + if (auto rebindSelf = dyn_cast(subExpr)) { + subExpr = rebindSelf->getSubExpr(); + continue; + } + + // Look through optional binding within the monadic "?". + if (auto bind = dyn_cast(subExpr)) { + subExpr = bind->getSubExpr(); + continue; + } + + // Look through optional evaluation of the monadic "?". + if (auto optEval = dyn_cast(subExpr)) { + subExpr = optEval->getSubExpr(); + continue; + } + + // Look through an implicit force-value. + if (auto force = dyn_cast(subExpr)) { + subExpr = force->getSubExpr(); + continue; + } + + // Look through implicit open-existential operations. + if (auto open = dyn_cast(subExpr)) { + if (open->isImplicit()) { + subExpr = open->getSubExpr(); + continue; + } + break; + } + + // Look to the referenced member in a self-application. + if (auto selfApply = dyn_cast(subExpr)) { + subExpr = selfApply->getFn(); + continue; + } + + // Look through implicit conversions. + if (auto conversion = dyn_cast(subExpr)) { + subExpr = conversion->getSubExpr(); + continue; + } + + // Look through explicit coercions. + if (auto coercion = dyn_cast(subExpr)) { + subExpr = coercion->getSubExpr(); + continue; + } + + break; + } + + if (!subExpr) return nullptr; + + // If we didn't find any declaration at all, we're stuck. + auto &tc = cs.getTypeChecker(); + if (!foundDecl) { + tc.diagnose(E->getLoc(), diag::expr_selector_no_declaration) + .highlight(subExpr->getSourceRange()); + return E; + } + + // If the declaration we found was not a method or initializer, + // complain. + auto func = dyn_cast(foundDecl); + if (!func) { + tc.diagnose(E->getLoc(), + isa(foundDecl) + ? diag::expr_selector_property + : diag::expr_selector_not_method_or_init) + .highlight(subExpr->getSourceRange()); + tc.diagnose(foundDecl, diag::decl_declared_here, + foundDecl->getFullName()); + return E; + } + + // The declaration we found must be exposed to Objective-C. + if (!func->isObjC()) { + tc.diagnose(E->getLoc(), diag::expr_selector_not_objc, + isa(func)) + .highlight(subExpr->getSourceRange()); + if (foundDecl->getLoc().isValid()) { + tc.diagnose(foundDecl, + diag::expr_selector_make_objc, + isa(func)) + .fixItInsert(foundDecl->getAttributeInsertionLoc(false), + "@objc "); + } else { + tc.diagnose(foundDecl, diag::decl_declared_here, + foundDecl->getFullName()); + } + return E; + } + + E->setMethod(func); + return E; + } + /// Interface for ExprWalker void walkToExprPre(Expr *expr) { ExprStack.push_back(expr); @@ -3340,6 +3453,107 @@ namespace { }; } + +/// Resolve a locator to the specific declaration it references, if possible. +/// +/// \param cs The constraint system in which the locator will be resolved. +/// +/// \param locator The locator to resolve. +/// +/// \param findOvlChoice A function that searches for the overload choice +/// associated with the given locator, or an empty optional if there is no such +/// overload. +/// +/// \returns the decl to which the locator resolved. +/// +static ConcreteDeclRef +resolveLocatorToDecl(ConstraintSystem &cs, ConstraintLocator *locator, + std::function(ConstraintLocator *)> findOvlChoice, + std::function getConcreteDeclRef) +{ + assert(locator && "Null locator"); + if (!locator->getAnchor()) + return ConcreteDeclRef(); + + auto anchor = locator->getAnchor(); + // Unwrap any specializations, constructor calls, implicit conversions, and + // '.'s. + // FIXME: This is brittle. + do { + if (auto specialize = dyn_cast(anchor)) { + anchor = specialize->getSubExpr(); + continue; + } + + if (auto implicit = dyn_cast(anchor)) { + anchor = implicit->getSubExpr(); + continue; + } + + if (auto identity = dyn_cast(anchor)) { + anchor = identity->getSubExpr(); + continue; + } + + if (auto tryExpr = dyn_cast(anchor)) { + if (isa(tryExpr)) + break; + + anchor = tryExpr->getSubExpr(); + continue; + } + + if (auto selfApply = dyn_cast(anchor)) { + anchor = selfApply->getFn(); + continue; + } + + if (auto dotSyntax = dyn_cast(anchor)) { + anchor = dotSyntax->getRHS(); + continue; + } + break; + } while (true); + + // Simple case: direct reference to a declaration. + if (auto dre = dyn_cast(anchor)) + return dre->getDeclRef(); + + // Simple case: direct reference to a declaration. + if (auto mre = dyn_cast(anchor)) + return mre->getMember(); + + if (auto ctorRef = dyn_cast(anchor)) + return ctorRef->getDeclRef(); + + if (isa(anchor) || + isa(anchor) || + isa(anchor)) { + // Overloaded and unresolved cases: find the resolved overload. + auto anchorLocator = cs.getConstraintLocator(anchor); + if (auto selected = findOvlChoice(anchorLocator)) { + if (selected->choice.isDecl()) + return getConcreteDeclRef(selected->choice.getDecl(), + selected->openedType); + } + } + + if (isa(anchor)) { + // Unresolved member: find the resolved overload. + auto anchorLocator = cs.getConstraintLocator(anchor, + ConstraintLocator::UnresolvedMember); + if (auto selected = findOvlChoice(anchorLocator)) { + if (selected->choice.isDecl()) + return getConcreteDeclRef(selected->choice.getDecl(), + selected->openedType); + } + } + + return ConcreteDeclRef(); +} + + /// \brief Given a constraint locator, find the owner of default arguments for /// that tuple, i.e., a FuncDecl. static ConcreteDeclRef @@ -3400,18 +3614,18 @@ findDefaultArgsOwner(ConstraintSystem &cs, const Solution &solution, }, [&](ValueDecl *decl, Type openedType) -> ConcreteDeclRef { - if (decl->getPotentialGenericDeclContext()->isGenericContext()) { + if (decl->getInnermostDeclContext()->isGenericContext()) { SmallVector subs; solution.computeSubstitutions( decl->getType(), - decl->getPotentialGenericDeclContext(), + decl->getInnermostDeclContext(), openedType, locator, subs); return ConcreteDeclRef(cs.getASTContext(), decl, subs); } return decl; })) { - return resolved.getDecl(); + return resolved; } return nullptr; @@ -3425,7 +3639,7 @@ getCallerDefaultArg(TypeChecker &tc, DeclContext *dc, unsigned index) { auto ownerFn = cast(owner.getDecl()); auto defArg = ownerFn->getDefaultArg(index); - MagicIdentifierLiteralExpr::Kind magicKind; + Expr *init = nullptr; switch (defArg.first) { case DefaultArgumentKind::None: llvm_unreachable("No default argument here?"); @@ -3439,30 +3653,51 @@ getCallerDefaultArg(TypeChecker &tc, DeclContext *dc, return getCallerDefaultArg(tc, dc, loc, owner, index); case DefaultArgumentKind::Column: - magicKind = MagicIdentifierLiteralExpr::Column; + init = new (tc.Context) MagicIdentifierLiteralExpr( + MagicIdentifierLiteralExpr::Column, loc, + /*Implicit=*/true); break; case DefaultArgumentKind::File: - magicKind = MagicIdentifierLiteralExpr::File; + init = new (tc.Context) MagicIdentifierLiteralExpr( + MagicIdentifierLiteralExpr::File, loc, + /*Implicit=*/true); break; case DefaultArgumentKind::Line: - magicKind = MagicIdentifierLiteralExpr::Line; + init = new (tc.Context) MagicIdentifierLiteralExpr( + MagicIdentifierLiteralExpr::Line, loc, + /*Implicit=*/true); break; case DefaultArgumentKind::Function: - magicKind = MagicIdentifierLiteralExpr::Function; + init = new (tc.Context) MagicIdentifierLiteralExpr( + MagicIdentifierLiteralExpr::Function, loc, + /*Implicit=*/true); break; case DefaultArgumentKind::DSOHandle: - magicKind = MagicIdentifierLiteralExpr::DSOHandle; + init = new (tc.Context) MagicIdentifierLiteralExpr( + MagicIdentifierLiteralExpr::DSOHandle, loc, + /*Implicit=*/true); + break; + + case DefaultArgumentKind::Nil: + init = new (tc.Context) NilLiteralExpr(loc, /*Implicit=*/true); + break; + + case DefaultArgumentKind::EmptyArray: + init = ArrayExpr::create(tc.Context, loc, {}, {}, loc); + init->setImplicit(); + break; + + case DefaultArgumentKind::EmptyDictionary: + init = DictionaryExpr::create(tc.Context, loc, {}, loc); + init->setImplicit(); break; } - // Create the default argument, which is a converted magic identifier - // literal expression. - Expr *init = new (tc.Context) MagicIdentifierLiteralExpr(magicKind, loc, - /*Implicit=*/true); + // Convert the literal to the appropriate type. bool invalid = tc.typeCheckExpression(init, dc, defArg.second,CTP_CannotFail); assert(!invalid && "conversion cannot fail"); (void)invalid; @@ -3599,7 +3834,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple, toElt.getDefaultArgKind(), toElt.isVararg())); fromTupleExprFields[sources[i]] = fromElt; - hasInits |= toElt.hasInit(); + hasInits |= toElt.hasDefaultArg(); continue; } @@ -3631,7 +3866,7 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple, fromElt.getName(), fromElt.getDefaultArgKind(), fromElt.isVararg()); - hasInits |= toElt.hasInit(); + hasInits |= toElt.hasDefaultArg(); } // Convert all of the variadic arguments to the destination type. @@ -3760,7 +3995,7 @@ Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple, bool hasInit = false; int i = 0; for (auto &field : toTuple->getElements()) { - if (field.hasInit()) { + if (field.hasDefaultArg()) { hasInit = true; break; } @@ -3812,7 +4047,7 @@ Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple, continue; } - assert(field.hasInit() && "Expected a default argument"); + assert(field.hasDefaultArg() && "Expected a default argument"); ConcreteDeclRef argOwner; // Dig out the owner of the default arguments. @@ -3863,22 +4098,22 @@ Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple, /// because most protocols do not conform to themselves -- however we still /// allow the conversion here, except the ErasureExpr ends up with trivial /// conformances. -static ArrayRef +static ArrayRef collectExistentialConformances(TypeChecker &tc, Type fromType, Type toType, DeclContext *DC) { SmallVector protocols; toType->getAnyExistentialTypeProtocols(protocols); - SmallVector conformances; + SmallVector conformances; for (auto proto : protocols) { - ProtocolConformance *conformance; + ProtocolConformance *concrete; bool conforms = tc.containsProtocol(fromType, proto, DC, (ConformanceCheckFlags::InExpression| ConformanceCheckFlags::Used), - &conformance); + &concrete); assert(conforms && "Type does not conform to protocol?"); (void)conforms; - conformances.push_back(conformance); + conformances.push_back(ProtocolConformanceRef(proto, concrete)); } return tc.Context.AllocateCopy(conformances); @@ -4264,11 +4499,15 @@ Expr *ExprRewriter::coerceCallArguments(Expr *arg, Type paramType, // If the element changed, rebuild a new ParenExpr. assert(fromTupleExpr.size() == 1 && fromTupleExpr[0]); if (fromTupleExpr[0] != argParen->getSubExpr()) { + bool argParenImplicit = argParen->isImplicit(); argParen = new (tc.Context) ParenExpr(argParen->getLParenLoc(), fromTupleExpr[0], argParen->getRParenLoc(), argParen->hasTrailingClosure(), fromTupleExpr[0]->getType()); + if (argParenImplicit) { + argParen->setImplicit(); + } arg = argParen; } else { // coerceToType may have updated the element type of the ParenExpr in @@ -4347,46 +4586,50 @@ ClosureExpr *ExprRewriter::coerceClosureExprToVoid(ClosureExpr *closureExpr) { // Re-write the single-expression closure to return '()' assert(closureExpr->hasSingleExpressionBody()); - auto member = closureExpr->getBody()->getElement(0); - - // A single-expression body contains a single return statement. - auto returnStmt = dyn_cast(member.get()); - auto singleExpr = returnStmt->getResult(); - auto voidExpr = TupleExpr::createEmpty(tc.Context, - singleExpr->getStartLoc(), - singleExpr->getEndLoc(), - /*implicit*/true); - returnStmt->setResult(voidExpr); - - // For l-value types, reset to the object type. This might not be strictly - // necessary any more, but it's probably still a good idea. - if (singleExpr->getType()->getAs()) - singleExpr->setType(singleExpr->getType()->getLValueOrInOutObjectType()); - - tc.checkIgnoredExpr(singleExpr); - - SmallVector elements; - elements.push_back(singleExpr); - elements.push_back(returnStmt); - - auto braceStmt = BraceStmt::create(tc.Context, - closureExpr->getStartLoc(), - elements, - closureExpr->getEndLoc(), - /*implicit*/true); + // Transform the ClosureExpr representation into the "expr + return ()" rep + // if it isn't already. + if (!closureExpr->isVoidConversionClosure()) { + + auto member = closureExpr->getBody()->getElement(0); + + // A single-expression body contains a single return statement. + auto returnStmt = cast(member.get()); + auto singleExpr = returnStmt->getResult(); + auto voidExpr = TupleExpr::createEmpty(tc.Context, + singleExpr->getStartLoc(), + singleExpr->getEndLoc(), + /*implicit*/true); + returnStmt->setResult(voidExpr); + + // For l-value types, reset to the object type. This might not be strictly + // necessary any more, but it's probably still a good idea. + if (singleExpr->getType()->getAs()) + singleExpr->setType(singleExpr->getType()->getLValueOrInOutObjectType()); + + tc.checkIgnoredExpr(singleExpr); + + SmallVector elements; + elements.push_back(singleExpr); + elements.push_back(returnStmt); + + auto braceStmt = BraceStmt::create(tc.Context, + closureExpr->getStartLoc(), + elements, + closureExpr->getEndLoc(), + /*implicit*/true); + + closureExpr->setImplicit(); + closureExpr->setIsVoidConversionClosure(); + closureExpr->setBody(braceStmt, /*isSingleExpression*/true); + } - closureExpr->setImplicit(); - closureExpr->setIsVoidConversionClosure(); - closureExpr->setBody(braceStmt, /*isSingleExpression*/true); - + // Finally, compute the proper type for the closure. auto fnType = closureExpr->getType()->getAs(); Type inputType = fnType->getInput(); - Type resultType = voidExpr->getType(); auto newClosureType = FunctionType::get(inputType, - resultType, + tc.Context.TheEmptyTupleType, fnType->getExtInfo()); closureExpr->setType(newClosureType); - return closureExpr; } @@ -4688,7 +4931,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } tc.validateDecl(fn); ConcreteDeclRef fnDeclRef(fn); - Expr *fnRef = new (tc.Context) DeclRefExpr(fnDeclRef, expr->getLoc(), + Expr *fnRef = new (tc.Context) DeclRefExpr(fnDeclRef, + DeclNameLoc(expr->getLoc()), /*Implicit=*/true); fnRef->setType(fn->getInterfaceType()); Expr *call = new (tc.Context) CallExpr(fnRef, expr, @@ -4696,10 +4940,9 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (tc.typeCheckExpressionShallow(call, dc)) return nullptr; - // The return type of _bridgeErrorTypeToNSError is formally 'AnyObject' to avoid - // stdlib-to-Foundation dependencies, but it's really NSError. + // The return type of _bridgeErrorTypeToNSError is formally 'AnyObject' to + // avoid stdlib-to-Foundation dependencies, but it's really NSError. // Abuse CovariantReturnConversionExpr to fix this. - return new (tc.Context) CovariantReturnConversionExpr(call, toType); } @@ -4836,11 +5079,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, auto discriminator = AutoClosureExpr::InvalidDiscriminator; auto closure = new (tc.Context) AutoClosureExpr(expr, toType, discriminator, dc); - Pattern *pattern = TuplePattern::create(tc.Context, expr->getLoc(), - ArrayRef(), - expr->getLoc()); - pattern->setType(TupleType::getEmpty(tc.Context)); - closure->setParams(pattern); + closure->setParameterList(ParameterList::createEmpty(tc.Context)); // Compute the capture list, now that we have analyzed the expression. tc.ClosuresWithUncomputedCaptures.push_back(closure); @@ -5090,7 +5329,8 @@ Expr *ExprRewriter::convertLiteral(Expr *literal, // If there is no argument to the constructor function, then just pass in // the empty tuple. literal = TupleExpr::createEmpty(tc.Context, literal->getLoc(), - literal->getLoc(), /*implicit*/true); + literal->getLoc(), + /*implicit*/!literal->getLoc().isValid()); } else { // Otherwise, figure out the type of the constructor function and coerce to // it. @@ -5153,7 +5393,7 @@ static bool isNonFinalClass(Type type) { // constructor must be required. bool TypeChecker::diagnoseInvalidDynamicConstructorReferences(Expr *base, - SourceLoc memberRefLoc, + DeclNameLoc memberRefLoc, AnyMetatypeType *metaTy, ConstructorDecl *ctorDecl, bool SuppressDiagnostics) { @@ -5265,10 +5505,22 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, return result; } + // If this is an UnresolvedType in the system, preserve it. + if (fn->getType()->is()) { + apply->setType(fn->getType()); + return apply; + } + // We have a type constructor. auto metaTy = fn->getType()->castTo(); auto ty = metaTy->getInstanceType(); - + + // If this is an UnresolvedType in the system, preserve it. + if (ty->is()) { + apply->setType(ty); + return apply; + } + // If the metatype value isn't a type expression, the user should reference // '.init' explicitly, for clarity. if (!fn->isTypeReference()) { @@ -5302,7 +5554,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, Expr *declRef = buildMemberRef(fn, selected->openedFullType, /*DotLoc=*/SourceLoc(), - decl, fn->getEndLoc(), + decl, DeclNameLoc(fn->getEndLoc()), selected->openedType, locator, ctorLocator, @@ -5459,9 +5711,7 @@ diagnoseArgumentLabelError(Expr *expr, ArrayRef newNames, continue; } - tok newNameKind = - Lexer::kindOfIdentifier(newName.str(), /*inSILMode=*/false); - bool newNameIsReserved = newNameKind != tok::identifier; + bool newNameIsReserved = !canBeArgumentLabel(newName.str()); llvm::SmallString<16> newStr; if (newNameIsReserved) newStr += "`"; @@ -5672,16 +5922,9 @@ namespace { // Coerce the pattern, in case we resolved something. auto fnType = closure->getType()->castTo(); - Pattern *params = closure->getParams(); - TypeResolutionOptions TROptions; - TROptions |= TR_OverrideType; - TROptions |= TR_FromNonInferredPattern; - TROptions |= TR_InExpression; - TROptions |= TR_ImmediateFunctionInput; - if (tc.coercePatternToType(params, closure, fnType->getInput(), - TROptions)) + auto *params = closure->getParameters(); + if (tc.coerceParameterListToType(params, closure, fnType->getInput())) return { false, nullptr }; - closure->setParams(params); // If this is a single-expression closure, convert the expression // in the body to the result type of the closure. @@ -5996,7 +6239,7 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, } while (current); if (fromRawCall) { - TC.diagnose(fromRawRef->getNameLoc(), + TC.diagnose(fromRawRef->getNameLoc().getBaseNameLoc(), diag::migrate_from_raw_to_init) .fixItReplace(SourceRange(fromRawRef->getDotLoc(), fromRawCall->getArg()->getStartLoc()), @@ -6039,7 +6282,7 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, if (toRawCall) { TC.diagnose(toRawRef->getNameLoc(), diag::migrate_to_raw_to_raw_value) - .fixItReplace(SourceRange(toRawRef->getNameLoc(), + .fixItReplace(SourceRange(toRawRef->getNameLoc().getBaseNameLoc(), toRawCall->getArg()->getEndLoc()), "rawValue"); } else { @@ -6056,7 +6299,7 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, do { // We haven't found the reference to allZeros yet, look for it now. if ((allZerosRef = dyn_cast(current))) { - if (allZerosRef->getName().str() == "allZeros") + if (allZerosRef->getName().isSimpleName(TC.Context.Id_allZeros)) break; allZerosRef = nullptr; } @@ -6067,8 +6310,9 @@ bool ConstraintSystem::applySolutionFix(Expr *expr, if (allZerosRef) { TC.diagnose(allZerosRef->getNameLoc(), diag::migrate_from_allZeros) - .fixItReplace(SourceRange(allZerosRef->getDotLoc(), - allZerosRef->getNameLoc()), + .fixItReplace(SourceRange( + allZerosRef->getDotLoc(), + allZerosRef->getNameLoc().getSourceRange().End), "()"); } else { // Diagnostic without Fix-It; we couldn't find what we needed. @@ -6218,10 +6462,9 @@ static bool isVariadicWitness(AbstractFunctionDecl *afd) { if (afd->getExtensionType()) ++index; - auto params = afd->getBodyParamPatterns()[index]; - if (auto *tuple = dyn_cast(params)) { - return tuple->hasAnyEllipsis(); - } + for (auto param : *afd->getParameterList(index)) + if (param->isVariadic()) + return true; return false; } @@ -6293,12 +6536,25 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc, ++i; } + // The tuple should have the source range enclosing its arguments unless + // they are invalid or there are no arguments. + SourceLoc TupleStartLoc = base->getStartLoc(); + SourceLoc TupleEndLoc = base->getEndLoc(); + if (arguments.size() > 0) { + SourceLoc AltStartLoc = arguments.front()->getStartLoc(); + SourceLoc AltEndLoc = arguments.back()->getEndLoc(); + if (AltStartLoc.isValid() && AltEndLoc.isValid()) { + TupleStartLoc = AltStartLoc; + TupleEndLoc = AltEndLoc; + } + } + arg = TupleExpr::create(Context, - base->getStartLoc(), + TupleStartLoc, arguments, names, { }, - base->getEndLoc(), + TupleEndLoc, /*hasTrailingClosure=*/false, /*Implicit=*/true, TupleType::get(elementTypes, Context)); @@ -6326,7 +6582,8 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc, auto memberRef = rewriter.buildMemberRef(base, openedFullType, base->getStartLoc(), - witness, base->getEndLoc(), + witness, + DeclNameLoc(base->getEndLoc()), openedType, locator, locator, /*Implicit=*/true, AccessSemantics::Ordinary, @@ -6408,7 +6665,8 @@ static Expr *convertViaBuiltinProtocol(const Solution &solution, // Form a reference to this member. Expr *memberRef = new (ctx) MemberRefExpr(expr, expr->getStartLoc(), - witness, expr->getEndLoc(), + witness, + DeclNameLoc(expr->getEndLoc()), /*Implicit=*/true); bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC); if (failed) { @@ -6446,7 +6704,8 @@ static Expr *convertViaBuiltinProtocol(const Solution &solution, // Form a reference to the builtin method. Expr *memberRef = new (ctx) MemberRefExpr(expr, SourceLoc(), - builtinMethod, expr->getLoc(), + builtinMethod, + DeclNameLoc(expr->getLoc()), /*Implicit=*/true); bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC); assert(!failed && "Could not reference witness?"); @@ -6498,16 +6757,11 @@ Expr *Solution::convertOptionalToBool(Expr *expr, // Form a reference to the function. This library intrinsic is generic, so we // need to form substitutions and compute the resulting type. auto unwrappedOptionalType = expr->getType()->getOptionalObjectType(); - auto fnGenericParams - = fn->getGenericSignatureOfContext()->getGenericParams(); - auto firstArchetype - = ArchetypeBuilder::mapTypeIntoContext(fn, fnGenericParams[0]) - ->castTo(); - Substitution sub(firstArchetype, unwrappedOptionalType, {}); + Substitution sub(unwrappedOptionalType, {}); ConcreteDeclRef fnSpecRef(ctx, fn, sub); auto *fnRef = - new (ctx) DeclRefExpr(fnSpecRef, SourceLoc(), /*Implicit=*/true); + new (ctx) DeclRefExpr(fnSpecRef, DeclNameLoc(), /*Implicit=*/true); TypeSubstitutionMap subMap; auto genericParam = fn->getGenericSignatureOfContext()->getGenericParams()[0]; diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 143ce5a0ce98e..e0f7c06e37409 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,6 +16,7 @@ #include "ConstraintSystem.h" #include "llvm/Support/SaveAndRestore.h" +#include "swift/AST/ASTWalker.h" using namespace swift; using namespace constraints; @@ -24,41 +25,6 @@ static bool isUnresolvedOrTypeVarType(Type ty) { return ty->is() || ty->is(); } -void Failure::dump(SourceManager *sm) const { - dump(sm, llvm::errs()); -} - -void Failure::dump(SourceManager *sm, raw_ostream &out) const { - out << "("; - if (locator) { - out << "@"; - locator->dump(sm, out); - out << ": "; - } - - switch (getKind()) { - case IsNotBridgedToObjectiveC: - out << getFirstType().getString() << "is not bridged to Objective-C"; - break; - - case IsForbiddenLValue: - out << "disallowed l-value binding of " << getFirstType().getString() - << " and " << getSecondType().getString(); - break; - - case NoPublicInitializers: - out << getFirstType().getString() - << " does not have any public initializers"; - break; - - case IsNotMaterializable: - out << getFirstType().getString() << " is not materializable"; - break; - } - - out << ")\n"; -} - /// Given a subpath of an old locator, compute its summary flags. static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, ArrayRef path) { @@ -240,21 +206,11 @@ void constraints::simplifyLocator(Expr *&anchor, targetAnchor = nullptr; targetPath.clear(); - range = UDE->getNameLoc(); + range = UDE->getNameLoc().getSourceRange(); anchor = UDE->getBase(); path = path.slice(1); continue; } - if (auto USE = dyn_cast(anchor)) { - // No additional target locator information. - targetAnchor = nullptr; - targetPath.clear(); - - range = USE->getNameRange(); - anchor = USE->getBase(); - path = path.slice(1); - continue; - } break; case ConstraintLocator::InterpolationArgument: @@ -333,328 +289,8 @@ static Expr *simplifyLocatorToAnchor(ConstraintSystem &cs, return locator->getAnchor(); } -/// Retrieve the argument pattern for the given declaration. -/// -static Pattern *getParameterPattern(ValueDecl *decl) { - if (auto func = dyn_cast(decl)) - return func->getBodyParamPatterns()[0]; - if (auto constructor = dyn_cast(decl)) - return constructor->getBodyParamPatterns()[1]; - if (auto subscript = dyn_cast(decl)) - return subscript->getIndices(); - - // FIXME: Variables of function type? - return nullptr; -} - -ResolvedLocator constraints::resolveLocatorToDecl( - ConstraintSystem &cs, - ConstraintLocator *locator, - std::function(ConstraintLocator *)> findOvlChoice, - std::function getConcreteDeclRef) -{ - assert(locator && "Null locator"); - if (!locator->getAnchor()) - return ResolvedLocator(); - - ConcreteDeclRef declRef; - auto anchor = locator->getAnchor(); - // Unwrap any specializations, constructor calls, implicit conversions, and - // '.'s. - // FIXME: This is brittle. - do { - if (auto specialize = dyn_cast(anchor)) { - anchor = specialize->getSubExpr(); - continue; - } - - if (auto implicit = dyn_cast(anchor)) { - anchor = implicit->getSubExpr(); - continue; - } - - if (auto identity = dyn_cast(anchor)) { - anchor = identity->getSubExpr(); - continue; - } - - if (auto tryExpr = dyn_cast(anchor)) { - if (isa(tryExpr)) - break; - - anchor = tryExpr->getSubExpr(); - continue; - } - - if (auto selfApply = dyn_cast(anchor)) { - anchor = selfApply->getFn(); - continue; - } - - if (auto dotSyntax = dyn_cast(anchor)) { - anchor = dotSyntax->getRHS(); - continue; - } - break; - } while (true); - - auto getConcreteDeclRefFromOverload - = [&](const SelectedOverload &selected) -> ConcreteDeclRef { - return getConcreteDeclRef(selected.choice.getDecl(), - selected.openedType); - }; - - if (auto dre = dyn_cast(anchor)) { - // Simple case: direct reference to a declaration. - declRef = dre->getDeclRef(); - } else if (auto mre = dyn_cast(anchor)) { - // Simple case: direct reference to a declaration. - declRef = mre->getMember(); - } else if (isa(anchor) || - isa(anchor) || - isa(anchor)) { - // Overloaded and unresolved cases: find the resolved overload. - auto anchorLocator = cs.getConstraintLocator(anchor); - if (auto selected = findOvlChoice(anchorLocator)) { - if (selected->choice.isDecl()) - declRef = getConcreteDeclRefFromOverload(*selected); - } - } else if (isa(anchor)) { - // Unresolved member: find the resolved overload. - auto anchorLocator = cs.getConstraintLocator( - anchor, - ConstraintLocator::UnresolvedMember); - if (auto selected = findOvlChoice(anchorLocator)) { - if (selected->choice.isDecl()) - declRef = getConcreteDeclRefFromOverload(*selected); - } - } else if (auto ctorRef = dyn_cast(anchor)) { - declRef = ctorRef->getDeclRef(); - } - - // If we didn't find the declaration, we're out of luck. - if (!declRef) - return ResolvedLocator(); - - // Use the declaration and the path to produce a more specific result. - // FIXME: This is an egregious hack. We'd be far better off - // FIXME: Perform deeper path resolution? - auto path = locator->getPath(); - Pattern *parameterPattern = nullptr; - bool impliesFullPattern = false; - while (!path.empty()) { - switch (path[0].getKind()) { - case ConstraintLocator::ApplyArgument: - // If we're calling into something that has parameters, dig into the - // actual parameter pattern. - parameterPattern = getParameterPattern(declRef.getDecl()); - if (!parameterPattern) - break; - - impliesFullPattern = true; - path = path.slice(1); - continue; - - case ConstraintLocator::TupleElement: - case ConstraintLocator::NamedTupleElement: - if (parameterPattern) { - unsigned index = path[0].getValue(); - if (auto tuple = dyn_cast( - parameterPattern->getSemanticsProvidingPattern())) { - if (index < tuple->getNumElements()) { - parameterPattern = tuple->getElement(index).getPattern(); - impliesFullPattern = false; - path = path.slice(1); - continue; - } - } - parameterPattern = nullptr; - } - break; - - case ConstraintLocator::ApplyArgToParam: - if (parameterPattern) { - unsigned index = path[0].getValue2(); - if (auto tuple = dyn_cast( - parameterPattern->getSemanticsProvidingPattern())) { - if (index < tuple->getNumElements()) { - parameterPattern = tuple->getElement(index).getPattern(); - impliesFullPattern = false; - path = path.slice(1); - continue; - } - } - parameterPattern = nullptr; - } - break; - - case ConstraintLocator::ScalarToTuple: - continue; - - default: - break; - } - - break; - } - - // If we have a parameter pattern that refers to a parameter, grab it. - if (parameterPattern) { - parameterPattern = parameterPattern->getSemanticsProvidingPattern(); - if (impliesFullPattern) { - if (auto tuple = dyn_cast(parameterPattern)) { - if (tuple->getNumElements() == 1) { - parameterPattern = tuple->getElement(0).getPattern(); - parameterPattern = parameterPattern->getSemanticsProvidingPattern(); - } - } - } - - if (auto named = dyn_cast(parameterPattern)) { - return ResolvedLocator(ResolvedLocator::ForVar, named->getDecl()); - } - } - - // Otherwise, do the best we can with the declaration we found. - if (isa(declRef.getDecl())) - return ResolvedLocator(ResolvedLocator::ForFunction, declRef); - if (isa(declRef.getDecl())) - return ResolvedLocator(ResolvedLocator::ForConstructor, declRef); - - // FIXME: Deal with the other interesting cases here, e.g., - // subscript declarations. - return ResolvedLocator(); -} - -/// Emit a note referring to the target of a diagnostic, e.g., the function -/// or parameter being used. -static void noteTargetOfDiagnostic(ConstraintSystem &cs, - const Failure *failure, - ConstraintLocator *targetLocator) { - // If there's no anchor, there's nothing we can do. - if (!targetLocator->getAnchor()) - return; - - // Try to resolve the locator to a particular declaration. - auto resolved - = resolveLocatorToDecl(cs, targetLocator, - [&](ConstraintLocator *locator) -> Optional { - if (!failure) return None; - for (auto resolved = failure->getResolvedOverloadSets(); - resolved; resolved = resolved->Previous) { - if (resolved->Locator == locator) - return SelectedOverload{resolved->Choice, - resolved->OpenedFullType, - // FIXME: opened type? - Type()}; - } - - return None; - }, - [&](ValueDecl *decl, - Type openedType) -> ConcreteDeclRef { - return decl; - }); - - // We couldn't resolve the locator to a declaration, so we're done. - if (!resolved) - return; - - switch (resolved.getKind()) { - case ResolvedLocatorKind::Unresolved: - // Can't emit any diagnostic here. - return; - - case ResolvedLocatorKind::Function: { - auto name = resolved.getDecl().getDecl()->getName(); - cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(), - name.isOperator()? diag::note_call_to_operator - : diag::note_call_to_func, - resolved.getDecl().getDecl()->getName()); - return; - } - - case ResolvedLocatorKind::Constructor: - // FIXME: Specialize for implicitly-generated constructors. - cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(), - diag::note_call_to_initializer); - return; - - case ResolvedLocatorKind::Parameter: - cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(), - diag::note_init_parameter, - resolved.getDecl().getDecl()->getName()); - return; - } -} - -/// \brief Emit a diagnostic for the given failure. -/// -/// \param cs The constraint system in which the diagnostic was generated. -/// \param failure The failure to emit. -/// \param expr The expression associated with the failure. -/// \param useExprLoc If the failure lacks a location, use the one associated -/// with expr. -/// -/// \returns true if the diagnostic was emitted successfully. -static bool diagnoseFailure(ConstraintSystem &cs, Failure &failure, - Expr *expr, bool useExprLoc) { - ConstraintLocator *cloc; - if (!failure.getLocator() || !failure.getLocator()->getAnchor()) { - if (useExprLoc) - cloc = cs.getConstraintLocator(expr); - else - return false; - } else { - cloc = failure.getLocator(); - } - - SourceRange range; - - ConstraintLocator *targetLocator; - auto locator = simplifyLocator(cs, cloc, range, &targetLocator); - auto &tc = cs.getTypeChecker(); - auto anchor = locator->getAnchor(); - auto loc = anchor->getLoc(); - switch (failure.getKind()) { - case Failure::IsNotBridgedToObjectiveC: - tc.diagnose(loc, diag::type_not_bridged, failure.getFirstType()); - if (targetLocator) - noteTargetOfDiagnostic(cs, &failure, targetLocator); - break; - case Failure::IsForbiddenLValue: - // FIXME: Probably better handled by InOutExpr later. - if (auto iotTy = failure.getSecondType()->getAs()) { - tc.diagnose(loc, diag::reference_non_inout, iotTy->getObjectType()) - .highlight(range); - return true; - } - // FIXME: diagnose other cases - return false; - - case Failure::NoPublicInitializers: { - tc.diagnose(loc, diag::no_accessible_initializers, failure.getFirstType()) - .highlight(range); - if (targetLocator && !useExprLoc) - noteTargetOfDiagnostic(cs, &failure, targetLocator); - break; - } - - case Failure::IsNotMaterializable: { - tc.diagnose(loc, diag::cannot_bind_generic_parameter_to_type, - failure.getFirstType()) - .highlight(range); - if (!useExprLoc) - noteTargetOfDiagnostic(cs, &failure, locator); - break; - } - } - - return true; -} /// \brief Determine the number of distinct overload choices in the /// provided set. @@ -1033,12 +669,16 @@ namespace { enum CandidateCloseness { CC_ExactMatch, ///< This is a perfect match for the arguments. CC_Unavailable, ///< Marked unavailable with @available. + CC_Inaccessible, ///< Not accessible from the current context. CC_NonLValueInOut, ///< First arg is inout but no lvalue present. CC_SelfMismatch, ///< Self argument mismatches. CC_OneArgumentNearMismatch, ///< All arguments except one match, near miss. CC_OneArgumentMismatch, ///< All arguments except one match. + CC_OneGenericArgumentNearMismatch, ///< All arguments except one match, guessing generic binding, near miss. + CC_OneGenericArgumentMismatch, ///< All arguments except one match, guessing generic binding. CC_ArgumentNearMismatch, ///< Argument list mismatch, near miss. CC_ArgumentMismatch, ///< Argument list mismatch. + CC_GenericNonsubstitutableMismatch, ///< Arguments match each other, but generic binding not substitutable. CC_ArgumentLabelMismatch, ///< Argument label mismatch. CC_ArgumentCountMismatch, ///< This candidate has wrong # arguments. CC_GeneralMismatch ///< Something else is wrong. @@ -1052,35 +692,56 @@ namespace { /// Uncurry level of 0 indicates that we're looking at the "a" argument, an /// uncurry level of 1 indicates that we're looking at the "b" argument. /// - /// The declType specifies a specific type to use for this decl that may be - /// more resolved than the decls type. For example, it may have generic + /// entityType specifies a specific type to use for this decl/expr that may be + /// more resolved than the concrete type. For example, it may have generic /// arguments substituted in. + /// struct UncurriedCandidate { - ValueDecl *decl; + PointerUnion declOrExpr; unsigned level; - Type declType; + Type entityType; UncurriedCandidate(ValueDecl *decl, unsigned level) - : decl(decl), level(level), declType(decl->getType()) { + : declOrExpr(decl), level(level), entityType(decl->getType()) { + } + UncurriedCandidate(Expr *expr) + : declOrExpr(expr), level(0), entityType(expr->getType()) { + } + + ValueDecl *getDecl() const { + return declOrExpr.dyn_cast(); } - AnyFunctionType *getUncurriedFunctionType() const { + Expr *getExpr() const { + return declOrExpr.dyn_cast(); + } + + Type getUncurriedType() const { // Start with the known type of the decl. - auto type = declType; + auto type = entityType; // If this is an operator func decl in a type context, the 'self' isn't // actually going to be applied. - if (auto *fd = dyn_cast(decl)) - if (fd->isOperator() && fd->getDeclContext()->isTypeContext()) + if (auto *fd = dyn_cast_or_null(getDecl())) + if (fd->isOperator() && fd->getDeclContext()->isTypeContext()) { + if (type->is()) + return Type(); type = type->castTo()->getResult(); + } for (unsigned i = 0, e = level; i != e; ++i) { auto funcTy = type->getAs(); - if (!funcTy) return nullptr; + if (!funcTy) return Type(); type = funcTy->getResult(); } - return type->getAs(); + return type; + } + + AnyFunctionType *getUncurriedFunctionType() const { + if (auto type = getUncurriedType()) + return type->getAs(); + return nullptr; } /// Given a function candidate with an uncurry level, return the parameter @@ -1102,13 +763,16 @@ namespace { } void dump() const { - decl->dumpRef(llvm::errs()); + if (auto decl = getDecl()) + decl->dumpRef(llvm::errs()); + else + llvm::errs() << "<>"; llvm::errs() << " - uncurry level " << level; if (auto FT = getUncurriedFunctionType()) llvm::errs() << " - type: " << Type(FT) << "\n"; else - llvm::errs() << " - type <>: " << decl->getType() << "\n"; + llvm::errs() << " - type <>: " << entityType << "\n"; } }; @@ -1162,8 +826,7 @@ namespace { } CalleeCandidateInfo(Type baseType, ArrayRef candidates, - unsigned UncurryLevel, bool hasTrailingClosure, - ConstraintSystem *CS); + bool hasTrailingClosure, ConstraintSystem *CS); typedef std::pair ClosenessResultTy; typedef const std::function @@ -1172,6 +835,9 @@ namespace { /// After the candidate list is formed, it can be filtered down to discard /// obviously mismatching candidates and compute a "closeness" for the /// resultant set. + std::pair + evaluateCloseness(Type candArgListType, ArrayRef actualArgs); + void filterList(ArrayRef actualArgs); void filterList(Type actualArgsType) { return filterList(decomposeArgParamType(actualArgsType)); @@ -1195,6 +861,16 @@ namespace { /// argument labels don't match up, diagnose that error and return true. bool diagnoseAnyStructuralArgumentError(Expr *fnExpr, Expr *argExpr); + /// If the candidate set has been narrowed to a single parameter or single + /// archetype that has argument type errors, diagnose that error and + /// return true. + bool diagnoseGenericParameterErrors(Expr *badArgExpr); + + /// Emit a diagnostic and return true if this is an error condition we can + /// handle uniformly. This should be called after filtering the candidate + /// list. + bool diagnoseSimpleErrors(SourceLoc loc); + void dump() const LLVM_ATTRIBUTE_USED; private: @@ -1230,12 +906,29 @@ void CalleeCandidateInfo::filterList(ClosenessPredicate predicate) { for (auto decl : candidates) { auto declCloseness = predicate(decl); - // If this candidate otherwise matched but was marked unavailable, then - // treat it as unavailable, which is a very close failure. - if (declCloseness.first == CC_ExactMatch && - decl.decl->getAttrs().isUnavailable(CS->getASTContext()) && - !CS->TC.getLangOpts().DisableAvailabilityChecking) - declCloseness.first = CC_Unavailable; + // If we have a decl identified, refine the match. + if (auto VD = decl.getDecl()) { + // If this candidate otherwise matched but was marked unavailable, then + // treat it as unavailable, which is a very close failure. + if (declCloseness.first == CC_ExactMatch && + VD->getAttrs().isUnavailable(CS->getASTContext()) && + !CS->TC.getLangOpts().DisableAvailabilityChecking) + declCloseness.first = CC_Unavailable; + + // Likewise, if the candidate is inaccessible from the scope it is being + // accessed from, mark it as inaccessible or a general mismatch. + if (VD->hasAccessibility() && + !VD->isAccessibleFrom(CS->DC)) { + // If this was an exact match, downgrade it to inaccessible, so that + // accessible decls that are also an exact match will take precedence. + // Otherwise consider it to be a general mismatch so we only list it in + // an overload set as a last resort. + if (declCloseness.first == CC_ExactMatch) + declCloseness.first = CC_Inaccessible; + else + declCloseness.first = CC_GeneralMismatch; + } + } closenessList.push_back(declCloseness); closeness = std::min(closeness, closenessList.back().first); @@ -1290,9 +983,9 @@ static bool argumentMismatchIsNearMiss(Type argType, Type paramType) { /// Determine how close an argument list is to an already decomposed argument /// list. If the closeness is a miss by a single argument, then this returns /// information about that failure. -static std::pair -evaluateCloseness(Type candArgListType, ArrayRef actualArgs, - bool argsHaveTrailingClosure) { +std::pair +CalleeCandidateInfo::evaluateCloseness(Type candArgListType, + ArrayRef actualArgs) { auto candArgs = decomposeArgParamType(candArgListType); struct OurListener : public MatchCallArgumentListener { @@ -1320,7 +1013,7 @@ evaluateCloseness(Type candArgListType, ArrayRef actualArgs, // shape) to the specified candidates parameters. This ignores the concrete // types of the arguments, looking only at the argument labels etc. SmallVector paramBindings; - if (matchCallArguments(actualArgs, candArgs, argsHaveTrailingClosure, + if (matchCallArguments(actualArgs, candArgs, hasTrailingClosure, /*allowFixes:*/ true, listener, paramBindings)) // On error, get our closeness from whatever problem the listener saw. @@ -1329,6 +1022,18 @@ evaluateCloseness(Type candArgListType, ArrayRef actualArgs, // If we found a mapping, check to see if the matched up arguments agree in // their type and count the number of mismatched arguments. unsigned mismatchingArgs = 0; + + // Checking of archetypes. + // FIXME: For now just trying to verify applicability of arguments with only + // a single generic variable. Ideally we'd create a ConstraintSystem with + // type variables for all generics and solve it with the given argument types. + Type singleArchetype = nullptr; + Type matchingArgType = nullptr; + + // Number of args of generic archetype which are mismatched because + // isSubstitutableFor() has failed. If all mismatches are of this type, we'll + // return a different closeness for better diagnoses. + unsigned nonSubstitutableArgs = 0; // We classify an argument mismatch as being a "near" miss if it is a very // likely match due to a common sort of problem (e.g. wrong flags on a @@ -1346,19 +1051,61 @@ evaluateCloseness(Type candArgListType, ArrayRef actualArgs, for (auto argNo : bindings) { auto argType = actualArgs[argNo].Ty; + auto rArgType = argType->getRValueType(); // If the argument has an unresolved type, then we're not actually // matching against it. - if (argType->getRValueType()->is()) + if (rArgType->is()) continue; // FIXME: Right now, a "matching" overload is one with a parameter whose - // type is identical to one of the argument types. We can obviously do - // something more sophisticated with this. - // FIXME: Definitely need to handle archetypes for same-type constraints. + // type is identical to the argument type, or substitutable via + // rudimentary handling of functions with a single archetype in one or + // more parameters. + // We can still do something more sophisticated with this. // FIXME: Use TC.isConvertibleTo? - if (argType->getRValueType()->isEqual(paramType)) + if (rArgType->isEqual(paramType)) continue; + if (auto genericParam = paramType->getAs()) + paramType = genericParam->getDecl()->getArchetype(); + if (paramType->is() && !rArgType->hasTypeVariable()) { + if (singleArchetype) { + if (!paramType->isEqual(singleArchetype)) + // Multiple archetypes, too complicated. + return { CC_ArgumentMismatch, {}}; + if (rArgType->isEqual(matchingArgType)) { + if (nonSubstitutableArgs == 0) + continue; + ++nonSubstitutableArgs; + // Fallthrough, this is nonsubstitutable, so mismatches as well. + } else { + if (nonSubstitutableArgs == 0) { + paramType = matchingArgType; + // Fallthrough as mismatched arg, comparing nearness to archetype + // bound type. + } else if (nonSubstitutableArgs == 1) { + // If we have only one nonSubstitutableArg so far, then this different + // type might be the one that we should be substituting for instead. + // Note that failureInfo is already set correctly for that case. + auto archetype = paramType->castTo(); + if (CS->TC.isSubstitutableFor(rArgType, archetype, CS->DC)) { + mismatchesAreNearMisses = argumentMismatchIsNearMiss(matchingArgType, rArgType); + matchingArgType = rArgType; + continue; + } + } + } + } else { + matchingArgType = rArgType; + singleArchetype = paramType; + + auto archetype = paramType->getAs(); + if (CS->TC.isSubstitutableFor(rArgType, archetype, CS->DC)) { + continue; + } + ++nonSubstitutableArgs; + } + } ++mismatchingArgs; @@ -1381,11 +1128,20 @@ evaluateCloseness(Type candArgListType, ArrayRef actualArgs, // If we have exactly one argument mismatching, classify it specially, so that // close matches are prioritized against obviously wrong ones. if (mismatchingArgs == 1) { - auto closeness = mismatchesAreNearMisses ? CC_OneArgumentNearMismatch - : CC_OneArgumentMismatch; + CandidateCloseness closeness; + if (singleArchetype.isNull()) { + closeness = mismatchesAreNearMisses ? CC_OneArgumentNearMismatch + : CC_OneArgumentMismatch; + } else { + closeness = mismatchesAreNearMisses ? CC_OneGenericArgumentNearMismatch + : CC_OneGenericArgumentMismatch; + } // Return information about the single failing argument. return { closeness, failureInfo }; } + + if (nonSubstitutableArgs == mismatchingArgs) + return { CC_GenericNonsubstitutableMismatch, failureInfo }; auto closeness = mismatchesAreNearMisses ? CC_ArgumentNearMismatch : CC_ArgumentMismatch; @@ -1425,17 +1181,18 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) { } if (!candidates.empty()) - declName = candidates[0].decl->getNameStr().str(); + declName = candidates[0].getDecl()->getNameStr().str(); return; } if (auto TE = dyn_cast(fn)) { // It's always a metatype type, so use the instance type name. - auto instanceType =TE->getType()->castTo()->getInstanceType(); + auto instanceType = TE->getInstanceType(); // TODO: figure out right value for isKnownPrivate if (!instanceType->getAs()) { - auto ctors = CS->TC.lookupConstructors(CS->DC, instanceType); + auto ctors = CS->TC.lookupConstructors(CS->DC, instanceType, + NameLookupFlags::IgnoreAccessibility); for (auto ctor : ctors) if (ctor->hasType()) candidates.push_back({ ctor, 1 }); @@ -1469,9 +1226,9 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) { C.level += 1; // Compute a new substituted type if we have a base type to apply. - if (baseType && C.level == 1) - C.declType = baseType->getTypeOfMember(CS->DC->getParentModule(), - C.decl, nullptr); + if (baseType && C.level == 1 && C.getDecl()) + C.entityType = baseType->getTypeOfMember(CS->DC->getParentModule(), + C.getDecl(), nullptr); } return; @@ -1497,7 +1254,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) { // base uncurried by one level, and we refer to the name of the member, not to // the name of any base. if (auto UDE = dyn_cast(fn)) { - declName = UDE->getName().str().str(); + declName = UDE->getName().getBaseName().str().str(); uncurryLevel = 1; // If we actually resolved the member to use, return it. @@ -1506,18 +1263,25 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) { candidates.push_back({ member, uncurryLevel }); return; } - // Otherwise, look for a disjunction constraint explaining what the set is. - } - - // Calls to super.init() are automatically uncurried one level. - if (auto *UCE = dyn_cast(fn)) { - uncurryLevel = 1; - auto selfTy = UCE->getSubExpr()->getType()->getLValueOrInOutObjectType(); - if (selfTy->hasTypeVariable()) - declName = "init"; - else - declName = selfTy.getString() + ".init"; + // If we resolved the constructor member, return it. + auto ctorLoc = CS->getConstraintLocator( + UDE, + ConstraintLocator::ConstructorMember); + if (auto *member = findResolvedMemberRef(ctorLoc, *CS)) { + candidates.push_back({ member, uncurryLevel }); + return; + } + + // If we have useful information about the type we're + // initializing, provide it. + if (UDE->getName().getBaseName() == CS->TC.Context.Id_init) { + auto selfTy = UDE->getBase()->getType()->getLValueOrInOutObjectType(); + if (!selfTy->hasTypeVariable()) + declName = selfTy.getString() + "." + declName; + } + + // Otherwise, look for a disjunction constraint explaining what the set is. } if (isa(fn)) @@ -1542,9 +1306,12 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) { if (candidates.empty()) continue; if (declName.empty()) - declName = candidates[0].decl->getNameStr().str(); + declName = candidates[0].getDecl()->getNameStr().str(); return; } + + // Otherwise, just add the expression as a candidate. + candidates.push_back(fn); } /// After the candidate list is formed, it can be filtered down to discard @@ -1558,7 +1325,7 @@ void CalleeCandidateInfo::filterList(ArrayRef actualArgs) { // If this isn't a function or isn't valid at this uncurry level, treat it // as a general mismatch. if (!inputType) return { CC_GeneralMismatch, {}}; - return evaluateCloseness(inputType, actualArgs, hasTrailingClosure); + return evaluateCloseness(inputType, actualArgs); }); } @@ -1617,7 +1384,6 @@ void CalleeCandidateInfo::filterContextualMemberList(Expr *argExpr) { CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, ArrayRef overloads, - unsigned uncurryLevel, bool hasTrailingClosure, ConstraintSystem *CS) : CS(CS), hasTrailingClosure(hasTrailingClosure) { @@ -1631,18 +1397,26 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, if (!cand.isDecl()) continue; auto decl = cand.getDecl(); + + // If this is a method or enum case member (not a var or subscript), then + // the uncurry level is 1. + unsigned uncurryLevel = 0; + if (!isa(decl) && + decl->getDeclContext()->isTypeContext()) + uncurryLevel = 1; + candidates.push_back({ decl, uncurryLevel }); if (baseType) { auto substType = baseType->getTypeOfMember(CS->DC->getParentModule(), decl, nullptr); if (substType) - candidates.back().declType = substType; + candidates.back().entityType = substType; } } if (!candidates.empty()) - declName = candidates[0].decl->getNameStr().str(); + declName = candidates[0].getDecl()->getNameStr().str(); } @@ -1658,7 +1432,7 @@ suggestPotentialOverloads(SourceLoc loc, bool isResult) { for (auto cand : candidates) { Type type; - if (auto *SD = dyn_cast(cand.decl)) { + if (auto *SD = dyn_cast_or_null(cand.getDecl())) { type = isResult ? SD->getElementType() : SD->getIndicesType(); } else { type = isResult ? cand.getResultType() : cand.getArgumentType(); @@ -1696,9 +1470,24 @@ suggestPotentialOverloads(SourceLoc loc, bool isResult) { /// labels don't match up, diagnose that error and return true. bool CalleeCandidateInfo::diagnoseAnyStructuralArgumentError(Expr *fnExpr, Expr *argExpr) { + // If we are invoking a constructor and there are absolutely no candidates, + // then they must all be private. + if (auto *MTT = fnExpr->getType()->getAs()) { + if (!MTT->getInstanceType()->is() && + (size() == 0 || + (size() == 1 && candidates[0].getDecl() && + isa(candidates[0].getDecl())))) { + CS->TC.diagnose(fnExpr->getLoc(), diag::no_accessible_initializers, + MTT->getInstanceType()); + return true; + } + } + + // TODO: We only handle the situation where there is exactly one candidate // here. - if (size() != 1) return false; + if (size() != 1) + return false; auto args = decomposeArgParamType(argExpr->getType()); @@ -1719,11 +1508,29 @@ bool CalleeCandidateInfo::diagnoseAnyStructuralArgumentError(Expr *fnExpr, // myFoo.doThing(42, b: 19) // // Check for this situation and handle it gracefully. - if (params.size() == 1 && candidates[0].decl->isInstanceMember() && + if (params.size() == 1 && candidates[0].getDecl() && + candidates[0].getDecl()->isInstanceMember() && candidates[0].level == 0) { if (auto UDE = dyn_cast(fnExpr)) if (isa(UDE->getBase())) { auto baseType = candidates[0].getArgumentType(); + + // If the base is an implicit self type reference, and we're in a + // property initializer, then the user wrote something like: + // + // class Foo { let val = initFn() } + // + // which runs in type context, not instance context. Produce a tailored + // diagnostic since this comes up and is otherwise non-obvious what is + // going on. + if (UDE->getBase()->isImplicit() && isa(CS->DC) && + CS->DC->getParent()->getDeclaredTypeOfContext()->isEqual(baseType)){ + CS->TC.diagnose(UDE->getLoc(), diag::instance_member_in_initializer, + UDE->getName()); + return true; + } + + // Otherwise, complain about use of instance value on type. CS->TC.diagnose(UDE->getLoc(), diag::instance_member_use_on_type, baseType, UDE->getName()) .highlight(UDE->getBase()->getSourceRange()); @@ -1780,7 +1587,7 @@ bool CalleeCandidateInfo::diagnoseAnyStructuralArgumentError(Expr *fnExpr, return false; - // If we are missing an parameter, diagnose that. + // If we are missing a parameter, diagnose that. if (missingParamIdx != ~0U) { Identifier name = params[missingParamIdx].Label; auto loc = argExpr->getStartLoc(); @@ -1850,7 +1657,68 @@ bool CalleeCandidateInfo::diagnoseAnyStructuralArgumentError(Expr *fnExpr, return false; } +/// If the candidate set has been narrowed to a single parameter or single +/// archetype that has argument type errors, diagnose that error and +/// return true. +bool CalleeCandidateInfo::diagnoseGenericParameterErrors(Expr *badArgExpr) { + bool foundFailure = false; + Type paramType = failedArgument.parameterType; + Type argType = badArgExpr->getType(); + + if (auto genericParam = paramType->getAs()) + paramType = genericParam->getDecl()->getArchetype(); + + if (paramType->is() && !argType->hasTypeVariable() && + // FIXME: For protocol argument types, could add specific error + // similar to could_not_use_member_on_existential. + !argType->is() && !argType->is()) { + auto archetype = paramType->castTo(); + + // FIXME: Add specific error for not subclass, if the archetype has a superclass? + + for (auto proto : archetype->getConformsTo()) { + if (!CS->TC.conformsToProtocol(argType, proto, CS->DC, ConformanceCheckOptions(TR_InExpression))) { + CS->TC.diagnose(badArgExpr->getLoc(), diag::cannot_convert_argument_value_protocol, + argType, proto->getDeclaredType()); + foundFailure = true; + } + } + } + return foundFailure; +} +/// Emit a diagnostic and return true if this is an error condition we can +/// handle uniformly. This should be called after filtering the candidate +/// list. +bool CalleeCandidateInfo::diagnoseSimpleErrors(SourceLoc loc) { + // Handle symbols marked as explicitly unavailable. + if (closeness == CC_Unavailable) { + auto decl = candidates[0].getDecl(); + assert(decl && "Only decl-based candidates may be marked unavailable"); + return CS->TC.diagnoseExplicitUnavailability(decl, loc, CS->DC); + } + + // Handle symbols that are matches, but are not accessible from the current + // scope. + if (closeness == CC_Inaccessible) { + auto decl = candidates[0].getDecl(); + assert(decl && "Only decl-based candidates may be marked inaccessible"); + if (auto *CD = dyn_cast(decl)) { + CS->TC.diagnose(loc, diag::init_candidate_inaccessible, + CD->getResultType(), decl->getFormalAccess()); + + } else { + CS->TC.diagnose(loc, diag::candidate_inaccessible, decl->getName(), + decl->getFormalAccess()); + } + for (auto cand : candidates) + CS->TC.diagnose(cand.getDecl(),diag::decl_declared_here, decl->getName()); + + return true; + } + + return false; +} @@ -1959,7 +1827,7 @@ class FailureDiagnosis :public ASTVisitor{ /// unviable ones. void diagnoseUnviableLookupResults(MemberLookupResult &lookupResults, Type baseObjTy, Expr *baseExpr, - DeclName memberName, SourceLoc nameLoc, + DeclName memberName, DeclNameLoc nameLoc, SourceLoc loc); /// Produce a diagnostic for a general overload resolution failure @@ -1977,6 +1845,7 @@ class FailureDiagnosis :public ASTVisitor{ bool visitUnresolvedMemberExpr(UnresolvedMemberExpr *E); bool visitArrayExpr(ArrayExpr *E); bool visitDictionaryExpr(DictionaryExpr *E); + bool visitObjectLiteralExpr(ObjectLiteralExpr *E); bool visitForceValueExpr(ForceValueExpr *FVE); bool visitBindOptionalExpr(BindOptionalExpr *BOE); @@ -2168,12 +2037,22 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { // and the source range for y. auto anchor = expr; SourceRange memberRange = anchor->getSourceRange(); - if (auto locator = constraint->getLocator()) { + auto locator = constraint->getLocator(); + if (locator) { locator = simplifyLocator(*CS, locator, memberRange); if (locator->getAnchor()) anchor = locator->getAnchor(); } - + + // Check to see if this is a locator referring to something we cannot or do + // here: in this case, we ignore paths that end on archetypes witnesses, or + // associated types of the expression. + if (locator && !locator->getPath().empty()) { + // TODO: This should only ignore *unresolved* archetypes. For resolved + // archetypes + return false; + } + // Retypecheck the anchor type, which is the base of the member expression. anchor = typeCheckArbitrarySubExprIndependently(anchor, TCC_AllowLValue); if (!anchor) return true; @@ -2199,7 +2078,9 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { // call the function, e.g. in "a.b.c" where they had to write "a.b().c". // Produce a specific diagnostic + fixit for this situation. if (auto baseFTy = baseObjTy->getAs()) { - if (baseFTy->getInput()->isVoid()) { + if (baseFTy->getInput()->isVoid() && + (constraint->getKind() == ConstraintKind::ValueMember || + constraint->getKind() == ConstraintKind::UnresolvedValueMember)) { SourceLoc insertLoc = anchor->getEndLoc(); if (auto *DRE = dyn_cast(anchor)) { @@ -2232,16 +2113,33 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { MemberLookupResult result = CS->performMemberLookup(constraint->getKind(), constraint->getMember(), - baseTy, constraint->getLocator()); + baseTy, constraint->getLocator(), + /*includeInaccessibleMembers*/true); switch (result.OverallResult) { - case MemberLookupResult::Unsolved: + case MemberLookupResult::Unsolved: + // If we couldn't resolve a specific type for the base expression, then we + // cannot produce a specific diagnostic. + return false; + + case MemberLookupResult::ErrorAlreadyDiagnosed: + // If an error was already emitted, then we're done, don't emit anything + // redundant. + return true; + + case MemberLookupResult::HasResults: + break; + } + + // If this is a failing lookup, it has no viable candidates here. + if (result.ViableCandidates.empty()) { // Diagnose 'super.init', which can only appear inside another initializer, // specially. - if (memberName.isSimpleName(CS->TC.Context.Id_init) && + if (result.UnviableCandidates.empty() && + memberName.isSimpleName(CS->TC.Context.Id_init) && !baseObjTy->is()) { - if (auto ctorRef = dyn_cast(anchor)) { - if (isa(ctorRef->getSubExpr())) { + if (auto ctorRef = dyn_cast(expr)) { + if (isa(ctorRef->getBase())) { diagnose(anchor->getLoc(), diag::super_initializer_not_in_initializer); return true; @@ -2249,32 +2147,20 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { // Suggest inserting '.dynamicType' to construct another object of the // same dynamic type. - SourceLoc fixItLoc = ctorRef->getConstructorLoc().getAdvancedLoc(-1); + SourceLoc fixItLoc + = ctorRef->getNameLoc().getBaseNameLoc().getAdvancedLoc(-1); // Place the '.dynamicType' right before the init. diagnose(anchor->getLoc(), diag::init_not_instance_member) - .fixItInsert(fixItLoc, ".dynamicType"); + .fixItInsert(fixItLoc, ".dynamicType"); return true; } } - - // If we couldn't resolve a specific type for the base expression, then we - // cannot produce a specific diagnostic. - return false; - case MemberLookupResult::ErrorAlreadyDiagnosed: - // If an error was already emitted, then we're done, don't emit anything - // redundant. - return true; - - case MemberLookupResult::HasResults: - break; - } - - // If this is a failing lookup, it has no viable candidates here. - if (result.ViableCandidates.empty()) { + // FIXME: Dig out the property DeclNameLoc. diagnoseUnviableLookupResults(result, baseObjTy, anchor, memberName, - memberRange.Start, anchor->getLoc()); + DeclNameLoc(memberRange.Start), + anchor->getLoc()); return true; } @@ -2289,7 +2175,7 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { if (allUnavailable) { auto firstDecl = result.ViableCandidates[0].getDecl(); if (CS->TC.diagnoseExplicitUnavailability(firstDecl, anchor->getLoc(), - CS->DC, nullptr)) + CS->DC)) return true; } @@ -2303,7 +2189,7 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { void FailureDiagnosis:: diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy, Expr *baseExpr, - DeclName memberName, SourceLoc nameLoc, + DeclName memberName, DeclNameLoc nameLoc, SourceLoc loc) { SourceRange baseRange = baseExpr ? baseExpr->getSourceRange() : SourceRange(); @@ -2316,18 +2202,23 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy, } else if (auto MTT = baseObjTy->getAs()) { diagnose(loc, diag::could_not_find_type_member, MTT->getInstanceType(), memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); } else { diagnose(loc, diag::could_not_find_value_member, baseObjTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); + + // Check for a few common cases that can cause missing members. + if (baseObjTy->is() && memberName.isSimpleName("rawValue")) { + auto loc = baseObjTy->castTo()->getDecl()->getNameLoc(); + if (loc.isValid()) + diagnose(loc, diag::did_you_mean_raw_type); + } } return; } - - // Otherwise, we have at least one (and potentially many) viable candidates // sort them out. If all of the candidates have the same problem (commonly // because there is exactly one candidate!) diagnose this. @@ -2347,17 +2238,32 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy, case MemberLookupResult::UR_UnavailableInExistential: diagnose(loc, diag::could_not_use_member_on_existential, instanceTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; case MemberLookupResult::UR_InstanceMemberOnType: + // If the base is an implicit self type reference, and we're in a + // property initializer, then the user wrote something like: + // + // class Foo { let x = 1, y = x } + // + // which runs in type context, not instance context. Produce a tailored + // diagnostic since this comes up and is otherwise non-obvious what is + // going on. + if (baseExpr && baseExpr->isImplicit() && isa(CS->DC) && + CS->DC->getParent()->getDeclaredTypeOfContext()->isEqual(instanceTy)){ + CS->TC.diagnose(nameLoc, diag::instance_member_in_initializer, + memberName); + return; + } + diagnose(loc, diag::could_not_use_instance_member_on_type, instanceTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; case MemberLookupResult::UR_TypeMemberOnInstance: diagnose(loc, diag::could_not_use_type_member_on_instance, baseObjTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; case MemberLookupResult::UR_MutatingMemberOnRValue: @@ -2373,6 +2279,16 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy, diagIDsubelt, diagIDmember); return; } + + case MemberLookupResult::UR_Inaccessible: { + auto decl = result.UnviableCandidates[0].first; + diagnose(nameLoc, diag::candidate_inaccessible, decl->getName(), + decl->getFormalAccess()); + for (auto cand : result.UnviableCandidates) + diagnose(cand.first, diag::decl_declared_here, memberName); + + return; + } } } @@ -2384,11 +2300,11 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy, if (!baseObjTy->isEqual(instanceTy)) diagnose(loc, diag::could_not_use_type_member, instanceTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); else diagnose(loc, diag::could_not_use_value_member, baseObjTy, memberName) - .highlight(baseRange).highlight(nameLoc); + .highlight(baseRange).highlight(nameLoc.getSourceRange()); return; } @@ -2400,11 +2316,7 @@ bool FailureDiagnosis::diagnoseGeneralOverloadFailure(Constraint *constraint) { bindOverload = constraint->getNestedConstraints().front(); auto overloadChoice = bindOverload->getOverloadChoice(); - std::string overloadName = overloadChoice.getDecl()->getNameStr(); - - if (auto *CD = dyn_cast(overloadChoice.getDecl())) - if (auto *SD = CD->getImplicitSelfDecl()) - overloadName = SD->getType()->getInOutObjectType().getString() + ".init"; + auto overloadName = overloadChoice.getDecl()->getFullName(); // Get the referenced expression from the failed constraint. auto anchor = expr; @@ -2480,15 +2392,6 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ fromType = fromType->getRValueType(); auto toType = CS->simplifyType(constraint->getSecondType()); - - // If the second type is a type variable, the expression itself is - // ambiguous. Bail out so the general ambiguity diagnosing logic can handle - // it. - if (isUnresolvedOrTypeVarType(fromType) || - isUnresolvedOrTypeVarType(toType) || - // FIXME: Why reject unbound generic types here? - fromType->is()) - return false; // Try to simplify irrelevant details of function types. For example, if // someone passes a "() -> Float" function to a "() throws -> Int" @@ -2526,19 +2429,70 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ // a failed conversion constraint of "A -> B" to "_ -> C", where the error is // that B isn't convertible to C. if (CS->getContextualTypePurpose() == CTP_CalleeResult) { - if (auto destFT = toType->getAs()) { - auto srcFT = fromType->getAs(); - if (!isUnresolvedOrTypeVarType(srcFT->getResult())) { - // Otherwise, the error is that the result types mismatch. - diagnose(expr->getLoc(), diag::invalid_callee_result_type, - srcFT->getResult(), destFT->getResult()) - .highlight(expr->getSourceRange()); + auto destFT = toType->getAs(); + auto srcFT = fromType->getAs(); + if (destFT && srcFT && !isUnresolvedOrTypeVarType(srcFT->getResult())) { + // Otherwise, the error is that the result types mismatch. + diagnose(expr->getLoc(), diag::invalid_callee_result_type, + srcFT->getResult(), destFT->getResult()) + .highlight(expr->getSourceRange()); + return true; + } + } + + + // If simplification has turned this into the same types, then this isn't the + // broken constraint that we're looking for. + if (fromType->isEqual(toType) && + constraint->getKind() != ConstraintKind::ConformsTo) + return false; + + + // If we have two tuples with mismatching types, produce a tailored + // diagnostic. + if (auto fromTT = fromType->getAs()) + if (auto toTT = toType->getAs()) { + if (fromTT->getNumElements() != toTT->getNumElements()) { + diagnose(anchor->getLoc(), diag::tuple_types_not_convertible_nelts, + fromTT, toTT) + .highlight(anchor->getSourceRange()); + return true; + } + + SmallVector FromElts; + auto voidTy = CS->getASTContext().TheUnresolvedType; + + for (unsigned i = 0, e = fromTT->getNumElements(); i != e; ++i) + FromElts.push_back({ voidTy, fromTT->getElement(i).getName() }); + auto TEType = TupleType::get(FromElts, CS->getASTContext()); + + SmallVector sources; + SmallVector variadicArgs; + + // If the shuffle conversion is invalid (e.g. incorrect element labels), + // then we have a type error. + if (computeTupleShuffle(TEType->castTo()->getElements(), + toTT->getElements(), sources, variadicArgs)) { + diagnose(anchor->getLoc(), diag::tuple_types_not_convertible, + fromTT, toTT) + .highlight(anchor->getSourceRange()); return true; } } - } + + + // If the second type is a type variable, the expression itself is + // ambiguous. Bail out so the general ambiguity diagnosing logic can handle + // it. + if (fromType->hasUnresolvedType() || fromType->hasTypeVariable() || + toType->hasUnresolvedType() || toType->hasTypeVariable() || + // FIXME: Why reject unbound generic types here? + fromType->is()) + return false; + if (auto PT = toType->getAs()) { + // Check for "=" converting to BooleanType. The user probably meant ==. if (auto *AE = dyn_cast(expr->getValueProvidingExpr())) if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::BooleanType)) { @@ -2567,23 +2521,6 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ } return true; } - - // If simplification has turned this into the same types, then this isn't the - // broken constraint that we're looking for. - if (fromType->isEqual(toType)) - return false; - - - // If we have two tuples with mismatching types, produce a tailored - // diagnostic. - if (auto fromTT = fromType->getAs()) - if (auto toTT = toType->getAs()) - if (fromTT->getNumElements() != toTT->getNumElements()) { - diagnose(anchor->getLoc(), diag::tuple_types_not_convertible, - fromTT, toTT) - .highlight(anchor->getSourceRange()); - return true; - } diagnose(anchor->getLoc(), diag::types_not_convertible, constraint->getKind() == ConstraintKind::Subtype, @@ -2611,31 +2548,77 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ } namespace { - class ExprTypeSaver { + class ExprTypeSaverAndEraser { llvm::DenseMap ExprTypes; llvm::DenseMap> TypeLocTypes; llvm::DenseMap PatternTypes; + llvm::DenseMap ParamDeclTypes; + ExprTypeSaverAndEraser(const ExprTypeSaverAndEraser&) = delete; + void operator=(const ExprTypeSaverAndEraser&) = delete; public: - void save(Expr *E) { + ExprTypeSaverAndEraser(Expr *E) { struct TypeSaver : public ASTWalker { - ExprTypeSaver *TS; - TypeSaver(ExprTypeSaver *TS) : TS(TS) {} + ExprTypeSaverAndEraser *TS; + TypeSaver(ExprTypeSaverAndEraser *TS) : TS(TS) {} std::pair walkToExprPre(Expr *expr) override { TS->ExprTypes[expr] = expr->getType(); + + // Preserve module expr type data to prevent further lookups. + if (auto *declRef = dyn_cast(expr)) + if (isa(declRef->getDecl())) + return { false, expr }; + + // Don't strip type info off OtherConstructorDeclRefExpr, because CSGen + // doesn't know how to reconstruct it. + if (isa(expr)) + return { false, expr }; + + // TypeExpr's are relabeled by CSGen. + if (isa(expr)) + return { false, expr }; + + // If a literal has a Builtin.Int or Builtin.FP type on it already, + // then sema has already expanded out a call to + // Init.init() + // and we don't want it to make + // Init.init(Init.init()) + // preserve the type info to prevent this from happening. + if (isa(expr) && + !(expr->getType() && expr->getType()->is())) + return { false, expr }; + + // If a ClosureExpr's parameter list has types on the decls, and the + // types and remove them so that they'll get regenerated from the + // associated TypeLocs or resynthesized as fresh typevars. + if (auto *CE = dyn_cast(expr)) + for (auto P : *CE->getParameters()) + if (P->hasType()) { + TS->ParamDeclTypes[P] = P->getType(); + P->overwriteType(Type()); + } + + expr->setType(nullptr); + expr->clearLValueAccessKind(); + return { true, expr }; } + // If we find a TypeLoc (e.g. in an as? expr), save and erase it. bool walkToTypeLocPre(TypeLoc &TL) override { - if (TL.getTypeRepr() && TL.getType()) + if (TL.getTypeRepr() && TL.getType()) { TS->TypeLocTypes[&TL] = { TL.getType(), TL.wasValidated() }; + TL.setType(Type(), /*was validated*/false); + } return true; } std::pair walkToPatternPre(Pattern *P) override { - if (P->hasType()) + if (P->hasType()) { TS->PatternTypes[P] = P->getType(); + P->setType(Type()); + } return { true, P }; } @@ -2649,7 +2632,7 @@ namespace { E->walk(TypeSaver(this)); } - void restore(Expr *E) { + void restore() { for (auto exprElt : ExprTypes) exprElt.first->setType(exprElt.second); @@ -2660,6 +2643,9 @@ namespace { for (auto patternElt : PatternTypes) patternElt.first->setType(patternElt.second); + for (auto paramDeclElt : ParamDeclTypes) + paramDeclElt.first->overwriteType(paramDeclElt.second); + // Done, don't do redundant work on destruction. ExprTypes.clear(); TypeLocTypes.clear(); @@ -2673,7 +2659,7 @@ namespace { // and if expr-specific diagnostics fail to turn up anything useful to say, // we go digging through failed constraints, and expect their locators to // still be meaningful. - ~ExprTypeSaver() { + ~ExprTypeSaverAndEraser() { for (auto exprElt : ExprTypes) if (!exprElt.first->getType()) exprElt.first->setType(exprElt.second); @@ -2686,72 +2672,15 @@ namespace { for (auto patternElt : PatternTypes) if (!patternElt.first->hasType()) patternElt.first->setType(patternElt.second); - } - }; -} - -/// \brief "Nullify" an expression tree's type data, to make it suitable for -/// re-typecheck operations. -static void eraseTypeData(Expr *expr) { - /// Private class to "cleanse" an expression tree of types. This is done in the - /// case of a typecheck failure, where we may want to re-typecheck partially- - /// typechecked subexpressions in a context-free manner. - class TypeNullifier : public ASTWalker { - public: - std::pair walkToExprPre(Expr *expr) override { - // Preserve module expr type data to prevent further lookups. - if (auto *declRef = dyn_cast(expr)) - if (isa(declRef->getDecl())) - return { false, expr }; - - // Don't strip type info off OtherConstructorDeclRefExpr, because CSGen - // doesn't know how to reconstruct it. - if (isa(expr)) - return { false, expr }; - - // TypeExpr's are relabeled by CSGen. - if (isa(expr)) - return { false, expr }; - - // If a literal has a Builtin.Int or Builtin.FP type on it already, - // then sema has already expanded out a call to - // Init.init() - // and we don't want it to make - // Init.init(Init.init()) - // preserve the type info to prevent this from happening. - if (isa(expr) && - !(expr->getType() && expr->getType()->is())) - return { false, expr }; - expr->setType(nullptr); - expr->clearLValueAccessKind(); - return { true, expr }; - } - - // If we find a TypeLoc (e.g. in an as? expr) with a type variable, rewrite - // it. - bool walkToTypeLocPre(TypeLoc &TL) override { - if (TL.getTypeRepr()) - TL.setType(Type(), /*was validated*/false); - return true; - } - - std::pair walkToPatternPre(Pattern *pattern) override { - pattern->setType(nullptr); - return { true, pattern }; - } - - // Don't walk into statements. This handles the BraceStmt in - // non-single-expr closures, so we don't walk into their body. - std::pair walkToStmtPre(Stmt *S) override { - return { false, S }; + for (auto paramDeclElt : ParamDeclTypes) + if (!paramDeclElt.first->hasType()) + paramDeclElt.first->setType(paramDeclElt.second); + } }; - - expr->walk(TypeNullifier()); } - /// Erase an expression tree's open existentials after a re-typecheck operation. /// /// This is done in the case of a typecheck failure, after we re-typecheck @@ -2823,9 +2752,9 @@ static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) { auto &ctx = ty->getASTContext(); return ty.transform([&](Type type) -> Type { - if (type->is()) - return ctx.TheUnresolvedType; - if (type->is()) + if (type->is() || + type->is() || + type->isTypeParameter()) return ctx.TheUnresolvedType; return type; }); @@ -2863,7 +2792,8 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, if (FT->isAutoClosure()) convertType = FT->getResult(); - if (convertType->hasTypeVariable() || convertType->hasArchetype()) + if (convertType->hasTypeVariable() || convertType->hasArchetype() || + convertType->isTypeParameter()) convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType); // If the conversion type contains no info, drop it. @@ -2877,7 +2807,7 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, // If we have no contextual type information and the subexpr is obviously a // overload set, don't recursively simplify this. The recursive solver will - // sometimes pick one based on arbitrary ranking behavior behavior (e.g. like + // sometimes pick one based on arbitrary ranking behavior (e.g. like // which is the most specialized) even then all the constraints are being // fulfilled by UnresolvedType, which doesn't tell us anything. if (convertTypePurpose == CTP_Unused && @@ -2886,15 +2816,15 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, return subExpr; } - ExprTypeSaver SavedTypeData; - SavedTypeData.save(subExpr); + // Save any existing type data of the subexpr tree, and reset it to null in + // prep for re-type-checking the tree. If things fail, we can revert the + // types back to their original state. + ExprTypeSaverAndEraser SavedTypeData(subExpr); // Store off the sub-expression, in case a new one is provided via the // type check operation. Expr *preCheckedExpr = subExpr; - - eraseTypeData(subExpr); - + // Disable structural checks, because we know that the overall expression // has type constraint problems, and we don't want to know about any // syntactic issues in a well-typed subexpression (which might be because @@ -2937,7 +2867,7 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType, // just pretend as though nothing happened. if (subExpr->getType()->is()) { subExpr = preCheckedExpr; - SavedTypeData.restore(subExpr); + SavedTypeData.restore(); } CS->TC.addExprForDiagnosis(preCheckedExpr, subExpr); @@ -2970,10 +2900,11 @@ typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) { // none of its arguments are type variables. If so, these type variables // would be accessible to name lookup of the subexpression and may thus leak // in. Reset them to UnresolvedTypes for safe measures. - CE->getParams()->forEachVariable([&](VarDecl *VD) { + for (auto param : *CE->getParameters()) { + auto VD = param; if (VD->getType()->hasTypeVariable() || VD->getType()->is()) VD->overwriteType(CS->getASTContext().TheUnresolvedType); - }); + } } // When we're type checking a single-expression closure, we need to reset the @@ -3025,6 +2956,10 @@ bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() { return false; case 1: + // If the callee isn't of function type, then something else has gone wrong. + if (!calleeInfo[0].getResultType()) + return false; + diagnose(expr->getLoc(), diag::candidates_no_match_result_type, calleeInfo.declName, calleeInfo[0].getResultType(), contextualResultType); @@ -3037,6 +2972,28 @@ bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() { } } + +/// Return true if the conversion from fromType to toType is an invalid string +/// index operation. +static bool isIntegerToStringIndexConversion(Type fromType, Type toType, + ConstraintSystem *CS) { + auto integerType = + CS->TC.getProtocol(SourceLoc(), + KnownProtocolKind::IntegerLiteralConvertible); + if (!integerType) return false; + + // If the from type is an integer type, and the to type is + // String.CharacterView.Index, then we found one. + if (CS->TC.conformsToProtocol(fromType, integerType, CS->DC, + ConformanceCheckFlags::InExpression)) { + if (toType->getCanonicalType().getString() == "String.CharacterView.Index") + return true; + } + + return false; +} + + bool FailureDiagnosis::diagnoseContextualConversionError() { // If the constraint system has a contextual type, then we can test to see if // this is the problem that prevents us from solving the system. @@ -3099,7 +3056,8 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { return true; } - if (isUnresolvedOrTypeVarType(exprType)) + if (isUnresolvedOrTypeVarType(exprType) || + exprType->isEqual(contextualType)) return false; // The conversion destination of throw is always ErrorType (at the moment) @@ -3165,9 +3123,10 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { } // If we don't have a type for the expression, then we cannot use it in - // conversion constraint diagnostic generation. - if (isUnresolvedOrTypeVarType(exprType)) { - // We can't do anything smart. + // conversion constraint diagnostic generation. If the types match, then it + // must not be the contextual type that is the problem. + if (isUnresolvedOrTypeVarType(exprType) || + exprType->isEqual(contextualType)) { return false; } @@ -3175,6 +3134,7 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { // probably meant to call the value. if (auto srcFT = exprType->getAs()) { if (srcFT->getInput()->isVoid() && + !isUnresolvedOrTypeVarType(srcFT->getResult()) && CS->TC.isConvertibleTo(srcFT->getResult(), contextualType, CS->DC)) { diagnose(expr->getLoc(), diag::missing_nullary_call, srcFT->getResult()) .highlight(expr->getSourceRange()) @@ -3192,6 +3152,18 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { return true; } + exprType = exprType->getRValueType(); + + // Special case of some common conversions involving Swift.String + // indexes, catching cases where people attempt to index them with an integer. + if (isIntegerToStringIndexConversion(exprType, contextualType, CS)) { + diagnose(expr->getLoc(), diag::string_index_not_integer, + exprType->getRValueType()) + .highlight(expr->getSourceRange()); + diagnose(expr->getLoc(), diag::string_index_not_integer_note); + return true; + } + // When complaining about conversion to a protocol type, complain about // conformance instead of "conversion". if (contextualType->is() || @@ -3220,7 +3192,7 @@ bool FailureDiagnosis::diagnoseContextualConversionError() { diagID = diag::noescape_functiontype_mismatch; } - diagnose(expr->getLoc(), diagID, exprType->getRValueType(), contextualType) + diagnose(expr->getLoc(), diagID, exprType, contextualType) .highlight(expr->getSourceRange()); return true; } @@ -3279,13 +3251,14 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, // If our candidates are instance members at curry level #0, then the argument // being provided is the receiver type for the instance. We produce better // diagnostics when we don't force the self type down. - if (argType && !candidates.empty() && - candidates[0].decl->isInstanceMember() && candidates[0].level == 0 && - !isa(candidates[0].decl)) - argType = Type(); + if (argType && !candidates.empty()) + if (auto decl = candidates[0].getDecl()) + if (decl->isInstanceMember() && candidates[0].level == 0 && + !isa(decl)) + argType = Type(); - // FIXME: This should all just be a matter of getting type type of the + // FIXME: This should all just be a matter of getting the type of the // sub-expression, but this doesn't work well when typeCheckChildIndependently // is over-conservative w.r.t. TupleExprs. auto *TE = dyn_cast(argExpr); @@ -3464,7 +3437,8 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { MemberLookupResult result = CS->performMemberLookup(ConstraintKind::ValueMember, subscriptName, - baseType, locator); + baseType, locator, + /*includeInaccessibleMembers*/true); switch (result.OverallResult) { @@ -3482,14 +3456,14 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { // other problem) we should diagnose the problem. if (result.ViableCandidates.empty()) { diagnoseUnviableLookupResults(result, baseType, /*no base expr*/nullptr, - subscriptName, SE->getLoc(), + subscriptName, DeclNameLoc(SE->getLoc()), SE->getLoc()); return true; } - CalleeCandidateInfo calleeInfo(baseType, result.ViableCandidates, 0, + CalleeCandidateInfo calleeInfo(baseType, result.ViableCandidates, /*FIXME: Subscript trailing closures*/ /*hasTrailingClosure*/false, CS); @@ -3504,7 +3478,7 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { CalleeCandidateInfo::ClosenessResultTy { // Classify how close this match is. Non-subscript decls don't match. - auto *SD = dyn_cast(cand.decl); + auto *SD = dyn_cast_or_null(cand.getDecl()); if (!SD) return { CC_GeneralMismatch, {}}; // Check to make sure the base expr type is convertible to the expected base @@ -3524,8 +3498,7 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { // Explode out multi-index subscripts to find the best match. auto indexResult = - evaluateCloseness(cand.getArgumentType(), decomposedIndexType, - /*FIXME: Subscript trailing closures*/false); + calleeInfo.evaluateCloseness(cand.getArgumentType(), decomposedIndexType); if (selfConstraint > indexResult.first) return {selfConstraint, {}}; return indexResult; @@ -3547,18 +3520,17 @@ bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) { // FIXME: suggestPotentialOverloads should do this. //calleeInfo.suggestPotentialOverloads(SE->getLoc()); for (auto candidate : calleeInfo.candidates) - diagnose(candidate.decl, diag::found_candidate); + if (auto decl = candidate.getDecl()) + diagnose(decl, diag::found_candidate); + else + diagnose(candidate.getExpr()->getLoc(), diag::found_candidate); return true; } - - if (calleeInfo.closeness == CC_Unavailable) { - if (CS->TC.diagnoseExplicitUnavailability(calleeInfo[0].decl, - SE->getLoc(), - CS->DC, nullptr)) - return true; - return false; - } + + // Diagnose some simple and common errors. + if (calleeInfo.diagnoseSimpleErrors(SE->getLoc())) + return true; // If the closest matches all mismatch on self, we either have something that // cannot be subscripted, or an ambiguity. @@ -3594,7 +3566,7 @@ namespace { // If the expression is obviously something that produces a metatype, // then don't put a constraint on it. auto semExpr = expr->getValueProvidingExpr(); - if (isa(semExpr) ||isa(semExpr)) + if (isa(semExpr)) return false; // We're making the expr have a function type, whose result is the same @@ -3729,7 +3701,10 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // as a specific problem of passing something of the wrong type into a // parameter. if ((calleeInfo.closeness == CC_OneArgumentMismatch || - calleeInfo.closeness == CC_OneArgumentNearMismatch) && + calleeInfo.closeness == CC_OneArgumentNearMismatch || + calleeInfo.closeness == CC_OneGenericArgumentMismatch || + calleeInfo.closeness == CC_OneGenericArgumentNearMismatch || + calleeInfo.closeness == CC_GenericNonsubstitutableMismatch) && calleeInfo.failedArgument.isValid()) { // Map the argument number into an argument expression. TCCOptions options = TCC_ForceRecheck; @@ -3752,18 +3727,21 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // Re-type-check the argument with the expected type of the candidate set. // This should produce a specific and tailored diagnostic saying that the // type mismatches with expectations. - if (!typeCheckChildIndependently(badArgExpr, - calleeInfo.failedArgument.parameterType, + Type paramType = calleeInfo.failedArgument.parameterType; + if (!typeCheckChildIndependently(badArgExpr, paramType, CTP_CallArgument, options)) return true; + + // If that fails, it could be that the argument doesn't conform to an archetype. + if (calleeInfo.diagnoseGenericParameterErrors(badArgExpr)) + return true; } - // Handle uses of unavailable symbols. - if (calleeInfo.closeness == CC_Unavailable) - return CS->TC.diagnoseExplicitUnavailability(calleeInfo[0].decl, - callExpr->getLoc(), - CS->DC, nullptr); + // Diagnose some simple and common errors. + if (calleeInfo.diagnoseSimpleErrors(callExpr->getLoc())) + return true; + // A common error is to apply an operator that only has inout forms (e.g. +=) // to non-lvalues (e.g. a local let). Produce a nice diagnostic for this @@ -3881,6 +3859,10 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { return true; } + if (argExpr->getType()->hasUnresolvedType()) + return false; + + std::string argString = getTypeListString(argExpr->getType()); // If we couldn't get the name of the callee, then it must be something of a @@ -3969,6 +3951,15 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) { destType->getRValueType(), CTP_AssignSource); if (!srcExpr) return true; + + // If we are assigning to _ and have unresolved types on the RHS, then we have + // an ambiguity problem. + if (isa(destExpr->getSemanticsProvidingExpr()) && + srcExpr->getType()->hasUnresolvedType()) { + diagnoseAmbiguity(srcExpr); + return true; + } + return false; } @@ -4176,19 +4167,17 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { CS->getContextualType()->is()) { auto fnType = CS->getContextualType()->castTo(); - Pattern *params = CE->getParams(); + auto *params = CE->getParameters(); Type inferredArgType = fnType->getInput(); // It is very common for a contextual type to disagree with the argument // list built into the closure expr. This can be because the closure expr - // had an explicitly specified pattern, ala: + // had an explicitly specified pattern, a la: // { a,b in ... } // or could be because the closure has an implicitly generated one: // { $0 + $1 } // in either case, we want to produce nice and clear diagnostics. - unsigned actualArgCount = 1; - if (auto *TP = dyn_cast(params)) - actualArgCount = TP->getNumElements(); + unsigned actualArgCount = params->size(); unsigned inferredArgCount = 1; if (auto *argTupleTy = inferredArgType->getAs()) inferredArgCount = argTupleTy->getNumElements(); @@ -4231,15 +4220,9 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { fnType, inferredArgCount, actualArgCount); return true; } - - TypeResolutionOptions TROptions; - TROptions |= TR_OverrideType; - TROptions |= TR_FromNonInferredPattern; - TROptions |= TR_InExpression; - TROptions |= TR_ImmediateFunctionInput; - if (CS->TC.coercePatternToType(params, CE, inferredArgType, TROptions)) + + if (CS->TC.coerceParameterListToType(params, CE, inferredArgType)) return true; - CE->setParams(params); expectedResultType = fnType->getResult(); } else { @@ -4250,10 +4233,10 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { // lookups against the parameter decls. // // Handle this by rewriting the arguments to UnresolvedType(). - CE->getParams()->forEachVariable([&](VarDecl *VD) { + for (auto VD : *CE->getParameters()) { if (VD->getType()->hasTypeVariable() || VD->getType()->is()) VD->overwriteType(CS->getASTContext().TheUnresolvedType); - }); + } } // If this is a complex leaf closure, there is nothing more we can do. @@ -4356,10 +4339,20 @@ bool FailureDiagnosis::visitArrayExpr(ArrayExpr *E) { } if (!foundConformance) { + // If the contextual type conforms to DictionaryLiteralConvertible and + // this is an empty array, then they meant "[:]". + if (E->getNumElements() == 0 && + isDictionaryLiteralCompatible(contextualType, CS, E->getLoc())) { + diagnose(E->getStartLoc(), diag::should_use_empty_dictionary_literal) + .fixItInsert(E->getEndLoc(), ":"); + return true; + } + + diagnose(E->getStartLoc(), diag::type_is_not_array, contextualType) .highlight(E->getSourceRange()); - // If the contextual type conforms to DicitonaryLiteralConvertible, then + // If the contextual type conforms to DictionaryLiteralConvertible, then // they wrote "x = [1,2]" but probably meant "x = [1:2]". if ((E->getElements().size() & 1) == 0 && !E->getElements().empty() && isDictionaryLiteralCompatible(contextualType, CS, E->getLoc())) { @@ -4468,6 +4461,77 @@ bool FailureDiagnosis::visitDictionaryExpr(DictionaryExpr *E) { return false; } +/// When an object literal fails to typecheck because its protocol's +/// corresponding default type has not been set in the global namespace (e.g. +/// _ColorLiteralType), suggest that the user import the appropriate module for +/// the target. +bool FailureDiagnosis::visitObjectLiteralExpr(ObjectLiteralExpr *E) { + auto &TC = CS->getTypeChecker(); + + // Type check the argument first. + auto protocol = TC.getLiteralProtocol(E); + if (!protocol) + return false; + DeclName constrName = TC.getObjectLiteralConstructorName(E); + assert(constrName); + ArrayRef constrs = protocol->lookupDirect(constrName); + if (constrs.size() != 1 || !isa(constrs.front())) + return false; + auto *constr = cast(constrs.front()); + if (!typeCheckChildIndependently( + E->getArg(), constr->getArgumentType(), CTP_CallArgument)) + return true; + + // Conditions for showing this diagnostic: + // * The object literal protocol's default type is unimplemented + if (TC.getDefaultType(protocol, CS->DC)) + return false; + // * The object literal has no contextual type + if (CS->getContextualType()) + return false; + + // Figure out what import to suggest. + auto &Ctx = CS->getASTContext(); + const auto &target = Ctx.LangOpts.Target; + StringRef plainName = E->getName().str(); + StringRef importModule; + StringRef importDefaultTypeName; + if (protocol == Ctx.getProtocol(KnownProtocolKind::ColorLiteralConvertible)) { + plainName = "color"; + if (target.isMacOSX()) { + importModule = "AppKit"; + importDefaultTypeName = "NSColor"; + } else if (target.isiOS() || target.isTvOS()) { + importModule = "UIKit"; + importDefaultTypeName = "UIColor"; + } + } else if (protocol == Ctx.getProtocol( + KnownProtocolKind::ImageLiteralConvertible)) { + plainName = "image"; + if (target.isMacOSX()) { + importModule = "AppKit"; + importDefaultTypeName = "NSImage"; + } else if (target.isiOS() || target.isTvOS()) { + importModule = "UIKit"; + importDefaultTypeName = "UIImage"; + } + } else if (protocol == Ctx.getProtocol( + KnownProtocolKind::FileReferenceLiteralConvertible)) { + plainName = "file reference"; + importModule = "Foundation"; + importDefaultTypeName = Ctx.getSwiftName(KnownFoundationEntity::NSURL); + } + + // Emit the diagnostic. + TC.diagnose(E->getLoc(), diag::object_literal_default_type_missing, + plainName); + if (!importModule.empty()) { + TC.diagnose(E->getLoc(), diag::object_literal_resolve_import, + importModule, importDefaultTypeName, plainName); + } + return true; +} + bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { // If we have no contextual type, there is no way to resolve this. Just // diagnose this as an ambiguity. @@ -4508,7 +4572,8 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { MemberLookupResult result = CS->performMemberLookup(memberConstraint->getKind(), memberConstraint->getMember(), - baseObjTy, memberConstraint->getLocator()); + baseObjTy, memberConstraint->getLocator(), + /*includeInaccessibleMembers*/true); switch (result.OverallResult) { case MemberLookupResult::Unsolved: @@ -4534,9 +4599,8 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { bool hasTrailingClosure = callArgHasTrailingClosure(E->getArgument()); - // Dump all of our viable candidates into a CalleeCandidateInfo (with an - // uncurry level of 1 to represent the contextual type) and sort it out. - CalleeCandidateInfo candidateInfo(baseObjTy, result.ViableCandidates, 1, + // Dump all of our viable candidates into a CalleeCandidateInfo & sort it out. + CalleeCandidateInfo candidateInfo(baseObjTy, result.ViableCandidates, hasTrailingClosure, CS); // Filter the candidate list based on the argument we may or may not have. @@ -4547,9 +4611,9 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { SourceRange argRange; if (auto arg = E->getArgument()) argRange = arg->getSourceRange(); diagnose(E->getNameLoc(), diag::ambiguous_member_overload_set, - E->getName().str()) + E->getName()) .highlight(argRange); - candidateInfo.suggestPotentialOverloads(E->getNameLoc()); + candidateInfo.suggestPotentialOverloads(E->getNameLoc().getBaseNameLoc()); return true; } @@ -4560,6 +4624,9 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { case CC_NonLValueInOut: // First argument is inout but no lvalue present. case CC_OneArgumentMismatch: // All arguments except one match. case CC_OneArgumentNearMismatch: + case CC_OneGenericArgumentMismatch: + case CC_OneGenericArgumentNearMismatch: + case CC_GenericNonsubstitutableMismatch: case CC_SelfMismatch: // Self argument mismatches. case CC_ArgumentNearMismatch:// Argument list mismatch. case CC_ArgumentMismatch: // Argument list mismatch. @@ -4567,24 +4634,39 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { return false; case CC_ExactMatch: { // This is a perfect match for the arguments. - // If we have an exact match, then we must have an argument list. - // If we didn't have an argument or an arg type, the expr would be valid. - if (!argumentTy) { - assert(!E->getArgument() && "Not an exact match"); - // If this is an exact match, return false to diagnose this as an - // ambiguity. It must be some other problem, such as failing to infer a - // generic argument on the enum type. - return false; + + // If we have an exact match, then we must have an argument list, check it. + if (argumentTy) { + assert(E->getArgument() && "Exact match without argument?"); + if (!typeCheckArgumentChildIndependently(E->getArgument(), argumentTy, + candidateInfo)) + return true; } - assert(E->getArgument() && argumentTy && "Exact match without argument?"); - return !typeCheckArgumentChildIndependently(E->getArgument(), argumentTy, - candidateInfo); + // If the argument is a match, then check the result type. We might have + // looked up a contextual member whose result type disagrees with the + // expected result type. + auto resultTy = candidateInfo[0].getResultType(); + if (!resultTy) + resultTy = candidateInfo[0].getUncurriedType(); + + if (resultTy && !CS->getContextualType()->is() && + !CS->TC.isConvertibleTo(resultTy, CS->getContextualType(), CS->DC)) { + diagnose(E->getNameLoc(), diag::expected_result_in_contextual_member, + E->getName(), resultTy, CS->getContextualType()); + return true; + } + + // Otherwise, this is an exact match, return false to diagnose this as an + // ambiguity. It must be some other problem, such as failing to infer a + // generic argument on the enum type. + return false; } case CC_Unavailable: - if (CS->TC.diagnoseExplicitUnavailability(candidateInfo[0].decl, - E->getLoc(), CS->DC, nullptr)) + case CC_Inaccessible: + // Diagnose some simple and common errors. + if (candidateInfo.diagnoseSimpleErrors(E->getLoc())) return true; return false; @@ -4817,20 +4899,96 @@ void ConstraintSystem::diagnoseFailureForExpr(Expr *expr) { if (diagnosis.diagnoseConstraintFailure()) return; - // If the expression-order diagnostics didn't find any diagnosable problems, - // try the unavoidable failures list again, with locator substitutions in - // place. To make sure we emit the error if we have a failure recorded. - for (auto failure : unavoidableFailures) { - if (diagnoseFailure(*this, *failure, expr, true)) - return; - } - // If no one could find a problem with this expression or constraint system, // then it must be well-formed... but is ambiguous. Handle this by diagnosic // various cases that come up. diagnosis.diagnoseAmbiguity(expr); } + +/// Emit an error message about an unbound generic parameter existing, and +/// emit notes referring to the target of a diagnostic, e.g., the function +/// or parameter being used. +static void diagnoseUnboundArchetype(Expr *overallExpr, + ArchetypeType *archetype, + ConstraintLocator *targetLocator, + ConstraintSystem &cs) { + auto &tc = cs.getTypeChecker(); + auto anchor = targetLocator->getAnchor(); + + // The archetype may come from the explicit type in a cast expression. + if (auto *ECE = dyn_cast_or_null(anchor)) { + tc.diagnose(ECE->getLoc(), diag::unbound_generic_parameter_cast, + archetype, ECE->getCastTypeLoc().getType()) + .highlight(ECE->getCastTypeLoc().getSourceRange()); + + // Emit a note specifying where this came from, if we can find it. + if (auto *ND = ECE->getCastTypeLoc().getType() + ->getNominalOrBoundGenericNominal()) + tc.diagnose(ND, diag::archetype_declared_in_type, archetype, + ND->getDeclaredType()); + return; + } + + // Otherwise, emit an error message on the expr we have, and emit a note + // about where the archetype came from. + tc.diagnose(overallExpr->getLoc(), diag::unbound_generic_parameter, + archetype); + + // If we have an anchor, drill into it to emit a + // "note: archetype declared here". + if (!anchor) return; + + + if (auto TE = dyn_cast(anchor)) { + if (auto *ND = TE->getInstanceType()->getNominalOrBoundGenericNominal()) + tc.diagnose(ND, diag::archetype_declared_in_type, archetype, + ND->getDeclaredType()); + return; + } + + ConcreteDeclRef resolved; + + // Simple case: direct reference to a declaration. + if (auto dre = dyn_cast(anchor)) + resolved = dre->getDeclRef(); + + // Simple case: direct reference to a declaration. + if (auto MRE = dyn_cast(anchor)) + resolved = MRE->getMember(); + + if (auto OCDRE = dyn_cast(anchor)) + resolved = OCDRE->getDeclRef(); + + + // We couldn't resolve the locator to a declaration, so we're done. + if (!resolved) + return; + + auto decl = resolved.getDecl(); + if (isa(decl)) { + auto name = decl->getName(); + auto diagID = name.isOperator() ? diag::note_call_to_operator + : diag::note_call_to_func; + tc.diagnose(decl, diagID, name); + return; + } + + // FIXME: Specialize for implicitly-generated constructors. + if (isa(decl)) { + tc.diagnose(decl, diag::note_call_to_initializer); + return; + } + + if (isa(decl)) { + tc.diagnose(decl, diag::note_init_parameter, decl->getName()); + return; + } + + // FIXME: Other decl types too. +} + + /// Emit an ambiguity diagnostic about the specified expression. void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { @@ -4848,10 +5006,7 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { // Only diagnose archetypes that don't have a parent, i.e., ones // that correspond to generic parameters. if (archetype && !archetype->getParent()) { - diagnose(expr->getLoc(), diag::unbound_generic_parameter, archetype); - - // Emit a "note, archetype declared here" sort of thing. - noteTargetOfDiagnostic(*CS, nullptr, tv->getImpl().getLocator()); + diagnoseUnboundArchetype(expr, archetype, tv->getImpl().getLocator(),*CS); return; } continue; @@ -4884,22 +5039,52 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { return; } + // Diagnose ".foo" expressions that lack context specifically. + if (auto UME = + dyn_cast(E->getSemanticsProvidingExpr())) { + if (!CS->getContextualType()) { + diagnose(E->getLoc(), diag::unresolved_member_no_inference,UME->getName()) + .highlight(SourceRange(UME->getDotLoc(), + UME->getNameLoc().getSourceRange().End)); + return; + } + } + + // Diagnose empty collection literals that lack context specifically. + if (auto CE = dyn_cast(E->getSemanticsProvidingExpr())) { + if (CE->getNumElements() == 0) { + diagnose(E->getLoc(), diag::unresolved_collection_literal) + .highlight(E->getSourceRange()); + return; + } + } - // Attempt to re-type-check the entire expression, while allowing ambiguity. - auto exprType = getTypeOfTypeCheckedChildIndependently(expr); - // If it failed and diagnosed something, then we're done. - if (!exprType) return; - - // If we were able to find something more specific than "unknown" (perhaps - // something like "[_:_]" for a dictionary literal), include it in the - // diagnostic. - if (!isUnresolvedOrTypeVarType(exprType)) { - diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous, - exprType) + // Diagnose 'nil' without a contextual type. + if (isa(E->getSemanticsProvidingExpr())) { + diagnose(E->getLoc(), diag::unresolved_nil_literal) .highlight(E->getSourceRange()); return; } + + // Attempt to re-type-check the entire expression, allowing ambiguity, but + // ignoring a contextual type. + if (expr == E) { + auto exprType = getTypeOfTypeCheckedChildIndependently(expr); + // If it failed and diagnosed something, then we're done. + if (!exprType) return; + + // If we were able to find something more specific than "unknown" (perhaps + // something like "[_:_]" for a dictionary literal), include it in the + // diagnostic. + if (!isUnresolvedOrTypeVarType(exprType)) { + diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous, + exprType) + .highlight(E->getSourceRange()); + return; + } + } + // If there are no posted constraints or failures, then there was // not enough contextual information available to infer a type for the // expression. @@ -4908,23 +5093,17 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) { } bool ConstraintSystem::salvage(SmallVectorImpl &viable, Expr *expr) { - // If there were any unavoidable failures, emit the first one we can. - if (!unavoidableFailures.empty()) { - for (auto failure : unavoidableFailures) { - if (diagnoseFailure(*this, *failure, expr, false)) - return true; - } - } + // Attempt to solve again, capturing all states that come from our attempts to + // select overloads or bind type variables. + // + // FIXME: can this be removed? We need to arrange for recordFixes to be + // eliminated. + viable.clear(); - // There were no unavoidable failures, so attempt to solve again, capturing - // any failures that come from our attempts to select overloads or bind - // type variables. { - viable.clear(); - // Set up solver state. SolverState state(*this); - state.recordFailures = true; + state.recordFixes = true; this->solverState = &state; // Solve the system. diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 3a0aced8679c2..e51defa4fd8f3 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" #include "swift/AST/Expr.h" +#include "swift/AST/ParameterList.h" #include "swift/Sema/CodeCompletionTypeChecking.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/APInt.h" @@ -34,7 +35,7 @@ static Expr *skipImplicitConversions(Expr *expr) { } /// \brief Find the declaration directly referenced by this expression. -static ValueDecl *findReferencedDecl(Expr *expr, SourceLoc &loc) { +static ValueDecl *findReferencedDecl(Expr *expr, DeclNameLoc &loc) { do { expr = expr->getSemanticsProvidingExpr(); @@ -44,7 +45,7 @@ static ValueDecl *findReferencedDecl(Expr *expr, SourceLoc &loc) { } if (auto dre = dyn_cast(expr)) { - loc = dre->getLoc(); + loc = dre->getNameLoc(); return dre->getDecl(); } @@ -60,6 +61,15 @@ static bool isDelayedOperatorDecl(ValueDecl *vd) { return vd && (vd->getName().str() == "=="); } +static bool isArithmeticOperatorDecl(ValueDecl *vd) { + return vd && + ( vd->getName().str() == "+" || + vd->getName().str() == "-" || + vd->getName().str() == "*" || + vd->getName().str() == "/" || + vd->getName().str() == "%" ); +} + namespace { /// Internal struct for tracking information about types within a series @@ -70,12 +80,27 @@ namespace { uint haveStringLiteral : 1; llvm::SmallSet collectedTypes; + + llvm::SmallVector intLiteralTyvars; + llvm::SmallVector floatLiteralTyvars; + llvm::SmallVector stringLiteralTyvars; + + llvm::SmallVector closureExprs; + llvm::SmallVector binaryExprs; + + // TODO: manage as a set of lists, to speed up addition of binding + // constraints. + llvm::SmallVector anonClosureParams; LinkedTypeInfo() { haveIntLiteral = false; haveFloatLiteral = false; haveStringLiteral = false; } + + bool haveLiteral() { + return haveIntLiteral || haveFloatLiteral || haveStringLiteral; + } }; /// Walks an expression sub-tree, and collects information about expressions @@ -95,7 +120,15 @@ namespace { if (isa(expr) || // Literal exprs are contextually typed, so store them off as well. - isa(expr)) { + isa(expr) || + + // We'd like to take a look at implicit closure params, so store + // them. + isa(expr) || + + // We'd like to look at the elements of arrays and dictionaries. + isa(expr) || + isa(expr)) { LinkedExprs.push_back(expr); return {false, expr}; } @@ -133,40 +166,115 @@ namespace { if (isa(expr)) { LTI.haveIntLiteral = true; - return {false, expr}; + auto tyvar = expr->getType()->getAs(); + + if (tyvar) { + LTI.intLiteralTyvars.push_back(tyvar); + } + + return { false, expr }; } if (isa(expr)) { LTI.haveFloatLiteral = true; - return {false, expr}; + auto tyvar = expr->getType()->getAs(); + + if (tyvar) { + LTI.floatLiteralTyvars.push_back(tyvar); + } + + return { false, expr }; } if (isa(expr)) { LTI.haveStringLiteral = true; - return {false, expr}; + auto tyvar = expr->getType()->getAs(); + + if (tyvar) { + LTI.stringLiteralTyvars.push_back(tyvar); + } + + return { false, expr }; } if (auto UDE = dyn_cast(expr)) { - if (UDE->getType() && - !isa(UDE->getType().getPointer())) + if (UDE->getType()) LTI.collectedTypes.insert(UDE->getType().getPointer()); // Don't recurse into the base expression. - return {false, expr}; + return { false, expr }; } - - if (auto favoredType = CS.getFavoredType(expr)) { - LTI.collectedTypes.insert(favoredType); - return {false, expr}; + + + if (auto CE = dyn_cast(expr)) { + if (!(LTI.closureExprs.size() || *LTI.closureExprs.end() == CE)) { + LTI.closureExprs.push_back(CE); + return { true, expr }; + } else { + CS.optimizeConstraints(expr); + return { false, expr }; + } } - + + if (auto DRE = dyn_cast(expr)) { + if (auto varDecl = dyn_cast(DRE->getDecl())) { + if (varDecl->isAnonClosureParam()) { + LTI.anonClosureParams.push_back(DRE); + } else if (DRE->getType()) { + LTI.collectedTypes.insert(DRE->getType().getPointer()); + } + return { false, expr }; + } + } + // In the case of a function application, we would have already captured // the return type during constraint generation, so there's no use in // looking any further. if (isa(expr) && !(isa(expr) || isa(expr) || - isa(expr))) { + isa(expr))) { + return { false, expr }; + } + + if (isa(expr)) { + LTI.binaryExprs.push_back(dyn_cast(expr)); + } + + if (auto favoredType = CS.getFavoredType(expr)) { + LTI.collectedTypes.insert(favoredType); + + // If we're analyzing a nested closure, continue to recurse, so we can + //make further connections amongst the arguments. + return { false, expr }; + } + + // TODO: The systems that we need to solve for interpolated string expressions + // require bespoke logic that don't currently work with this approach. + if (isa(expr)) { + return { false, expr }; + } + + // For exprs of a structural type that are not modeling argument lists, + // avoid merging the type variables. (We need to allow for cases like + // (Int, Int32).) + if (isa(expr) && !isa(Parent.getAsExpr())) { + return { false, expr }; + } + + // Coercion exprs have a rigid type, so there's no use in gathering info + // about them. + if (isa(expr)) { + LTI.collectedTypes.insert(expr->getType().getPointer()); + + return { false, expr }; + } + + // Don't walk into subscript expressions - to do so would risk factoring + // the index expression into edge contraction. (We don't want to do this + // if the index expression is a literal type that differs from the return + // type of the subscript operation.) + if (isa(expr) || isa(expr)) { return { false, expr }; } @@ -174,6 +282,13 @@ namespace { } Expr *walkToExprPost(Expr *expr) override { + + if (auto CE = dyn_cast(expr)) { + if (LTI.closureExprs.size() && *LTI.closureExprs.end() == CE) { + LTI.closureExprs.pop_back(); + } + } + return expr; } @@ -192,19 +307,157 @@ namespace { LinkedTypeInfo lti; expr->walk(LinkedExprAnalyzer(lti, CS)); - - if (!lti.collectedTypes.empty()) { + + // Link anonymous closure params of the same index. + // TODO: As stated above, we should bucket these whilst collecting the + // exprs to avoid quadratic behavior. + for (auto acp1 : lti.anonClosureParams) { + for (auto acp2 : lti.anonClosureParams) { + if (acp1 == acp2) + continue; + + if (acp1->getDecl()->getName().str() == + acp2->getDecl()->getName().str()) { + + auto tyvar1 = acp1->getType()->getAs(); + auto tyvar2 = acp2->getType()->getAs(); + + if (tyvar1 && tyvar2) { + auto rep1 = CS.getRepresentative(tyvar1); + auto rep2 = CS.getRepresentative(tyvar2); + + if (rep1 != rep2) { + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); + } + } + } + } + } + + // Link integer literal tyvars. + if (lti.intLiteralTyvars.size() > 1) { + auto rep1 = CS.getRepresentative(lti.intLiteralTyvars[0]); + + for (size_t i = 1; i < lti.intLiteralTyvars.size(); i++) { + auto rep2 = CS.getRepresentative(lti.intLiteralTyvars[i]); + + if (rep1 != rep2) + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); + } + } + + // Link float literal tyvars. + if (lti.floatLiteralTyvars.size() > 1) { + auto rep1 = CS.getRepresentative(lti.floatLiteralTyvars[0]); + + for (size_t i = 1; i < lti.floatLiteralTyvars.size(); i++) { + auto rep2 = CS.getRepresentative(lti.floatLiteralTyvars[i]); + + if (rep1 != rep2) + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); + } + } + + // Link string literal tyvars. + if (lti.stringLiteralTyvars.size() > 1) { + auto rep1 = CS.getRepresentative(lti.stringLiteralTyvars[0]); + + for (size_t i = 1; i < lti.stringLiteralTyvars.size(); i++) { + auto rep2 = CS.getRepresentative(lti.stringLiteralTyvars[i]); + + if (rep1 != rep2) + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); + } + } + + if (lti.collectedTypes.size() == 1) { // TODO: Compute the BCT. - CS.setFavoredType(expr, *lti.collectedTypes.begin()); + + auto favoredTy = (*lti.collectedTypes.begin())->getLValueOrInOutObjectType(); + + CS.setFavoredType(expr, favoredTy.getPointer()); + + // If we have a chain of identical binop expressions with homogeneous + // argument types, we can directly simplify the associated constraint + // graph. + auto simplifyBinOpExprTyVars = [&]() { + if (!lti.haveLiteral()) { + for (auto binExp1 : lti.binaryExprs) { + for (auto binExp2 : lti.binaryExprs) { + if (binExp1 == binExp2) + continue; + + auto fnTy1 = binExp1->getType()->getAs(); + auto fnTy2 = binExp2->getType()->getAs(); + + if (!(fnTy1 && fnTy2)) + return; + + auto ODR1 = dyn_cast(binExp1->getFn()); + auto ODR2 = dyn_cast(binExp2->getFn()); + + if (!(ODR1 && ODR2)) + return; + + // TODO: We currently limit this optimization to known arithmetic + // operators, but we should be able to broaden this out to + // logical operators as well. + if (!isArithmeticOperatorDecl(ODR1->getDecls()[0])) + return; + + if (ODR1->getDecls()[0]->getName().str() != + ODR2->getDecls()[0]->getName().str()) + return; + + // All things equal, we can merge the tyvars for the function + // types. + auto rep1 = CS.getRepresentative(fnTy1); + auto rep2 = CS.getRepresentative(fnTy2); + + if (rep1 != rep2) { + CS.mergeEquivalenceClasses(rep1, rep2, + /*updateWorkList*/ false); + + // Since we're merging argument constraints, make sure that + // the representative tyvar is properly bound to the argument + // type. + CS.addConstraint(ConstraintKind::Bind, + rep1, + favoredTy, + CS.getConstraintLocator(binExp1)); + } + + auto odTy1 = ODR1->getType()->getAs(); + auto odTy2 = ODR2->getType()->getAs(); + + if (odTy1 && odTy2) { + auto odRep1 = CS.getRepresentative(odTy1); + auto odRep2 = CS.getRepresentative(odTy2); + + // Since we'll be choosing the same overload, we can merge + // the overload tyvar as well. + if (odRep1 != odRep2) + CS.mergeEquivalenceClasses(odRep1, odRep2, + /*updateWorkList*/ false); + } + } + } + } + }; + + simplifyBinOpExprTyVars(); + return true; - } + } if (lti.haveFloatLiteral) { if (auto floatProto = CS.TC.Context.getProtocol( KnownProtocolKind::FloatLiteralConvertible)) { if (auto defaultType = CS.TC.getDefaultType(floatProto, CS.DC)) { - CS.setFavoredType(expr, defaultType.getPointer()); + if (!CS.getFavoredType(expr)) { + CS.setFavoredType(expr, defaultType.getPointer()); + } return true; } } @@ -215,7 +468,9 @@ namespace { CS.TC.Context.getProtocol( KnownProtocolKind::IntegerLiteralConvertible)) { if (auto defaultType = CS.TC.getDefaultType(intProto, CS.DC)) { - CS.setFavoredType(expr, defaultType.getPointer()); + if (!CS.getFavoredType(expr)) { + CS.setFavoredType(expr, defaultType.getPointer()); + } return true; } } @@ -226,7 +481,9 @@ namespace { CS.TC.Context.getProtocol( KnownProtocolKind::StringLiteralConvertible)) { if (auto defaultType = CS.TC.getDefaultType(stringProto, CS.DC)) { - CS.setFavoredType(expr, defaultType.getPointer()); + if (!CS.getFavoredType(expr)) { + CS.setFavoredType(expr, defaultType.getPointer()); + } return true; } } @@ -550,9 +807,7 @@ namespace { /// Return a pair, containing the total parameter count of a function, coupled /// with the number of non-default parameters. std::pair getParamCount(ValueDecl *VD) { - auto fty = VD->getType()->getAs(); - assert(fty && "attempting to count parameters of a non-function type"); auto t = fty->getInput(); @@ -560,13 +815,10 @@ namespace { size_t nNoDefault = 0; if (auto AFD = dyn_cast(VD)) { - for (auto pattern : AFD->getBodyParamPatterns()) { - - if (auto tuplePattern = dyn_cast(pattern)) { - for (auto elt : tuplePattern->getElements()) { - if (elt.getDefaultArgKind() == DefaultArgumentKind::None) - nNoDefault++; - } + for (auto params : AFD->getParameterLists()) { + for (auto param : *params) { + if (!param->isDefaultArgument()) + nNoDefault++; } } } else { @@ -710,33 +962,7 @@ namespace { auto argTupleTy = argTy->castTo(); auto argTupleExpr = dyn_cast(expr->getArg()); Type firstArgTy = getInnerParenType(argTupleTy->getElement(0).getType()); - Type secondArgTy = - getInnerParenType(argTupleTy->getElement(1).getType()); - - auto firstFavoredTy = CS.getFavoredType(argTupleExpr->getElement(0)); - auto secondFavoredTy = CS.getFavoredType(argTupleExpr->getElement(1)); - - auto favoredExprTy = CS.getFavoredType(expr); - - // If the parent has been favored on the way down, propagate that - // information to its children. - if (!firstFavoredTy) { - CS.setFavoredType(argTupleExpr->getElement(0), favoredExprTy); - firstFavoredTy = favoredExprTy; - } - - if (!secondFavoredTy) { - CS.setFavoredType(argTupleExpr->getElement(1), favoredExprTy); - secondFavoredTy = favoredExprTy; - } - - if (firstFavoredTy && firstArgTy->getAs()) { - firstArgTy = firstFavoredTy; - } - - if (secondFavoredTy && secondArgTy->getAs()) { - secondArgTy = secondFavoredTy; - } + Type secondArgTy = getInnerParenType(argTupleTy->getElement(1).getType()); // Determine whether the given declaration is favored. auto isFavoredDecl = [&](ValueDecl *value) -> bool { @@ -745,6 +971,34 @@ namespace { auto fnTy = valueTy->getAs(); if (!fnTy) return false; + + auto firstFavoredTy = CS.getFavoredType(argTupleExpr->getElement(0)); + auto secondFavoredTy = CS.getFavoredType(argTupleExpr->getElement(1)); + + auto favoredExprTy = CS.getFavoredType(expr); + + if (isArithmeticOperatorDecl(value)) { + // If the parent has been favored on the way down, propagate that + // information to its children. + // TODO: This is only valid for arithmetic expressions. + if (!firstFavoredTy) { + CS.setFavoredType(argTupleExpr->getElement(0), favoredExprTy); + firstFavoredTy = favoredExprTy; + } + + if (!secondFavoredTy) { + CS.setFavoredType(argTupleExpr->getElement(1), favoredExprTy); + secondFavoredTy = favoredExprTy; + } + + if (firstFavoredTy && firstArgTy->getAs()) { + firstArgTy = firstFavoredTy; + } + + if (secondFavoredTy && secondArgTy->getAs()) { + secondArgTy = secondFavoredTy; + } + } // Figure out the parameter type. if (value->getDeclContext()->isTypeContext()) { @@ -765,7 +1019,7 @@ namespace { return (isFavoredParamAndArg(CS, firstParamTy, firstArgTy, secondArgTy) || isFavoredParamAndArg(CS, secondParamTy, secondArgTy, firstArgTy)) && - firstParamTy->isEqual(secondParamTy) && + firstParamTy->isEqual(secondParamTy) && (!contextualTy || contextualTy->isEqual(resultTy)); }; @@ -1209,44 +1463,6 @@ namespace { return MetatypeType::get(type); } - Type visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *expr) { - ASTContext &C = CS.getASTContext(); - - // Open a member constraint for constructor delegations on the subexpr - // type. - if (CS.TC.getSelfForInitDelegationInConstructor(CS.DC, expr)){ - auto baseTy = expr->getSubExpr()->getType() - ->getLValueOrInOutObjectType(); - // 'self' or 'super' will reference an instance, but the constructor - // is semantically a member of the metatype. This: - // self.init() - // super.init() - // is really more like: - // self = Self.init() - // self.super = Super.init() - baseTy = MetatypeType::get(baseTy, CS.getASTContext()); - - auto argsTy = CS.createTypeVariable( - CS.getConstraintLocator(expr), - TVO_CanBindToLValue|TVO_PrefersSubtypeBinding); - auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr), - /*options=*/0); - auto methodTy = FunctionType::get(argsTy, resultTy); - CS.addValueMemberConstraint(baseTy, C.Id_init, - methodTy, - CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); - - // The result of the expression is the partial application of the - // constructor to the subexpression. - return methodTy; - } - - // If we aren't delegating from within an initializer, then 'x.init' is - // just a reference to the constructor as a member of the metatype value - // 'x'. - return addMemberRefConstraints(expr, expr->getSubExpr(), C.Id_init); - } - Type visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) { llvm_unreachable("Already type-checked"); } @@ -1391,10 +1607,36 @@ namespace { } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { - return addMemberRefConstraints(expr, expr->getBase(), expr->getName()); - } - - Type visitUnresolvedSelectorExpr(UnresolvedSelectorExpr *expr) { + // Open a member constraint for constructor delegations on the + // subexpr type. + if (CS.TC.getSelfForInitDelegationInConstructor(CS.DC, expr)){ + auto baseTy = expr->getBase()->getType() + ->getLValueOrInOutObjectType(); + + // 'self' or 'super' will reference an instance, but the constructor + // is semantically a member of the metatype. This: + // self.init() + // super.init() + // is really more like: + // self = Self.init() + // self.super = Super.init() + baseTy = MetatypeType::get(baseTy, CS.getASTContext()); + + auto argsTy = CS.createTypeVariable( + CS.getConstraintLocator(expr), + TVO_CanBindToLValue|TVO_PrefersSubtypeBinding); + auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr), + /*options=*/0); + auto methodTy = FunctionType::get(argsTy, resultTy); + CS.addValueMemberConstraint(baseTy, expr->getName(), + methodTy, + CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); + + // The result of the expression is the partial application of the + // constructor to the subexpression. + return methodTy; + } + return addMemberRefConstraints(expr, expr->getBase(), expr->getName()); } @@ -1681,21 +1923,44 @@ namespace { return addMemberRefConstraints(expr, expr->getBase(), name); } + /// Give each parameter in a ClosureExpr a fresh type variable if parameter + /// types were not specified, and return the eventual function type. + Type getTypeForParameterList(ParameterList *params, + ConstraintLocatorBuilder locator) { + for (auto param : *params) { + // If a type was explicitly specified, use its opened type. + if (auto type = param->getTypeLoc().getType()) { + // FIXME: Need a better locator for a pattern as a base. + Type openedType = CS.openType(type, locator); + param->overwriteType(openedType); + continue; + } + + // Otherwise, create a fresh type variable. + Type ty = CS.createTypeVariable(CS.getConstraintLocator(locator), + /*options=*/0); + + param->overwriteType(ty); + } + + return params->getType(CS.getASTContext()); + } + + /// \brief Produces a type for the given pattern, filling in any missing /// type information with fresh type variables. /// /// \param pattern The pattern. - Type getTypeForPattern(Pattern *pattern, bool forFunctionParam, - ConstraintLocatorBuilder locator) { + Type getTypeForPattern(Pattern *pattern, ConstraintLocatorBuilder locator) { switch (pattern->getKind()) { case PatternKind::Paren: // Parentheses don't affect the type. return getTypeForPattern(cast(pattern)->getSubPattern(), - forFunctionParam, locator); + locator); case PatternKind::Var: // Var doesn't affect the type. return getTypeForPattern(cast(pattern)->getSubPattern(), - forFunctionParam, locator); + locator); case PatternKind::Any: // For a pattern of unknown type, create a new type variable. return CS.createTypeVariable(CS.getConstraintLocator(locator), @@ -1726,20 +1991,11 @@ namespace { // For weak variables, use Optional. if (auto *OA = var->getAttrs().getAttribute()) - if (!forFunctionParam && OA->get() == Ownership::Weak) { + if (OA->get() == Ownership::Weak) { ty = CS.getTypeChecker().getOptionalType(var->getLoc(), ty); if (!ty) return Type(); } - // We want to set the variable's type here when type-checking - // a function's parameter clauses because we're going to - // type-check the entire function body within the context of - // the constraint system. In contrast, when type-checking a - // variable binding, we really don't want to set the - // variable's type because it can easily escape the constraint - // system and become a dangling type reference. - if (forFunctionParam) - var->overwriteType(ty); return ty; } @@ -1761,15 +2017,10 @@ namespace { tupleTypeElts.reserve(tuplePat->getNumElements()); for (unsigned i = 0, e = tuplePat->getNumElements(); i != e; ++i) { auto &tupleElt = tuplePat->getElement(i); - bool hasEllipsis = tupleElt.hasEllipsis(); - Type eltTy = getTypeForPattern(tupleElt.getPattern(),forFunctionParam, + Type eltTy = getTypeForPattern(tupleElt.getPattern(), locator.withPathElement( LocatorPathElt::getTupleElement(i))); - - Type varArgBaseTy; - tupleTypeElts.push_back(TupleTypeElt(eltTy, tupleElt.getLabel(), - tupleElt.getDefaultArgKind(), - hasEllipsis)); + tupleTypeElts.push_back(TupleTypeElt(eltTy, tupleElt.getLabel())); } return TupleType::get(tupleTypeElts, CS.getASTContext()); } @@ -2011,6 +2262,7 @@ namespace { if (expr->hasExplicitResultType() && expr->getExplicitResultTypeLoc().getType()) { funcTy = expr->getExplicitResultTypeLoc().getType(); + CS.setFavoredType(expr, funcTy.getPointer()); } else if (!crt.isNull()) { funcTy = crt; } else{ @@ -2030,12 +2282,10 @@ namespace { } } - // Walk through the patterns in the func expression, backwards, - // computing the type of each pattern (which may involve fresh type - // variables where parameter types where no provided) and building the - // eventual function type. - auto paramTy = getTypeForPattern( - expr->getParams(), /*forFunctionParam*/ true, + // Give each parameter in a ClosureExpr a fresh type variable if parameter + // types were not specified, and return the eventual function type. + auto paramTy = getTypeForParameterList( + expr->getParameters(), CS.getConstraintLocator( expr, LocatorPathElt::getTupleElement(0))); @@ -2101,7 +2351,7 @@ namespace { outputTy = fnType->getResult(); } } else if (auto TE = dyn_cast(fnExpr)) { - outputTy = TE->getType()->getAs()->getInstanceType(); + outputTy = TE->getInstanceType(); NominalTypeDecl *NTD = nullptr; if (auto nominalType = outputTy->getAs()) { @@ -2488,6 +2738,26 @@ namespace { // case we return the null type. return E->getType(); } + + Type visitObjCSelectorExpr(ObjCSelectorExpr *E) { + // #selector only makes sense when we have the Objective-C + // runtime. + auto &tc = CS.getTypeChecker(); + if (!tc.Context.LangOpts.EnableObjCInterop) { + tc.diagnose(E->getLoc(), diag::expr_selector_no_objc_runtime); + return nullptr; + } + + // Make sure we can reference ObjectiveC.Selector. + // FIXME: Fix-It to add the import? + auto type = CS.getTypeChecker().getObjCSelectorType(CS.DC); + if (!type) { + tc.diagnose(E->getLoc(), diag::expr_selector_module_missing); + return nullptr; + } + + return type; + } }; /// \brief AST walker that "sanitizes" an expression for the @@ -2515,7 +2785,7 @@ namespace { // A DotSyntaxCallExpr is a member reference that has already been // type-checked down to a call; turn it back into an overloaded // member reference expression. - SourceLoc memberLoc; + DeclNameLoc memberLoc; if (auto member = findReferencedDecl(dotCall->getFn(), memberLoc)) { auto base = skipImplicitConversions(dotCall->getArg()); auto members @@ -2531,7 +2801,7 @@ namespace { // already been type-checked down to a call where the argument doesn't // actually matter; turn it back into an overloaded member reference // expression. - SourceLoc memberLoc; + DeclNameLoc memberLoc; if (auto member = findReferencedDecl(dotIgnored->getRHS(), memberLoc)) { auto base = skipImplicitConversions(dotIgnored->getLHS()); auto members @@ -2586,6 +2856,7 @@ namespace { // return type. auto resultTy = closure->getResultType(); auto bodyTy = closure->getSingleExpressionBody()->getType(); + CG.getConstraintSystem().setFavoredType(expr, bodyTy.getPointer()); CG.getConstraintSystem() .addConstraint(ConstraintKind::Conversion, bodyTy, resultTy, @@ -2716,7 +2987,7 @@ Expr *ConstraintSystem::generateConstraintsShallow(Expr *expr) { Type ConstraintSystem::generateConstraints(Pattern *pattern, ConstraintLocatorBuilder locator) { ConstraintGenerator cg(*this); - return cg.getTypeForPattern(pattern, /*forFunctionParam*/ false, locator); + return cg.getTypeForPattern(pattern, locator); } void ConstraintSystem::optimizeConstraints(Expr *e) { @@ -2880,7 +3151,8 @@ bool swift::isExtensionApplied(DeclContext &DC, Type BaseTy, SmallVector Scratch; auto genericArgs = BaseTy->getAllGenericArgs(Scratch); TypeSubstitutionMap substitutions; - auto genericParams = BaseTy->getNominalOrBoundGenericNominal()->getGenericParamTypes(); + auto genericParams = BaseTy->getNominalOrBoundGenericNominal() + ->getInnermostGenericParamTypes(); assert(genericParams.size() == genericArgs.size()); for (unsigned i = 0, n = genericParams.size(); i != n; ++i) { auto gp = genericParams[i]->getCanonicalType()->castTo(); @@ -2908,10 +3180,13 @@ bool swift::isExtensionApplied(DeclContext &DC, Type BaseTy, case RequirementKind::Conformance: createMemberConstraint(Req, ConstraintKind::ConformsTo); break; + case RequirementKind::Superclass: + createMemberConstraint(Req, ConstraintKind::Subtype); + break; case RequirementKind::SameType: createMemberConstraint(Req, ConstraintKind::Equal); break; - default: + case RequirementKind::WitnessMarker: break; } } diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index f293e37a29a5d..f2837c587e38e 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,9 +21,9 @@ using namespace swift; using namespace constraints; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Statistics -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #define DEBUG_TYPE "Constraint solver overall" STATISTIC(NumDiscardedSolutions, "# of solutions discarded"); @@ -226,25 +226,6 @@ static Comparison compareWitnessAndRequirement(TypeChecker &tc, DeclContext *dc, return proto1? Comparison::Worse : Comparison::Better; } -namespace { - /// Dependent type opener that maps from a dependent type to its corresponding - /// archetype in the given context. - class ArchetypeOpener : public constraints::DependentTypeOpener { - DeclContext *DC; - - public: - explicit ArchetypeOpener(DeclContext *dc) : DC(dc) { } - - virtual Type mapGenericTypeParamType(GenericTypeParamType *param) { - return ArchetypeBuilder::mapTypeIntoContext(DC, param); - } - - virtual Type mapDependentMemberType(DependentMemberType *memberType) { - return ArchetypeBuilder::mapTypeIntoContext(DC, memberType); - } - }; -} - namespace { /// Describes the relationship between the context types for two declarations. enum class SelfTypeRelationship { @@ -336,12 +317,12 @@ static Type addCurriedSelfType(ASTContext &ctx, Type type, DeclContext *dc) { if (!dc->isTypeContext()) return type; - auto nominal = dc->getDeclaredTypeOfContext()->getAnyNominal(); + auto nominal = dc->isNominalTypeOrNominalTypeExtensionContext(); auto selfTy = nominal->getInterfaceType()->castTo() ->getInstanceType(); - if (nominal->isGenericContext()) - return GenericFunctionType::get(nominal->getGenericSignature(), - selfTy, type, AnyFunctionType::ExtInfo()); + if (auto sig = nominal->getGenericSignatureOfContext()) + return GenericFunctionType::get(sig, selfTy, type, + AnyFunctionType::ExtInfo()); return FunctionType::get(selfTy, type); } @@ -388,27 +369,23 @@ static bool isDeclMoreConstrainedThan(ValueDecl *decl1, ValueDecl *decl2) { return false; } -static TypeBase* getTypeAtIndex(TypeBase* containerType, size_t index) { +static Type getTypeAtIndex(const ParameterList *params, size_t index) { + if (params->size() == 0) + return nullptr; + + if (index < params->size()) { + auto param = params->get(index); + if (param->isVariadic()) + return param->getVarargBaseTy(); - if (auto parenType = dyn_cast(containerType)) { - if (!index) { - return parenType->getDesugaredType(); - } + return param->getType(); } - if (auto tupleType = containerType->getAs()) { - auto elements = tupleType->getElements(); - - if (!elements.empty()) { - if (index < elements.size()) { - if (elements[index].isVararg()) { - return elements[index].getVarargBaseTy().getPointer(); - } - return elements[index].getType().getPointer(); - } else if (elements.back().isVararg()) { - return elements.back().getVarargBaseTy().getPointer(); - } - } + /// FIXME: This looks completely wrong for varargs within a parameter list. + if (params->size() != 0) { + auto lastParam = params->getArray().back(); + if (lastParam->isVariadic()) + return lastParam->getVarargBaseTy(); } return nullptr; @@ -419,36 +396,26 @@ static TypeBase* getTypeAtIndex(TypeBase* containerType, size_t index) { /// against a non-existential parameter at the same position of the first decl. /// This is used to disambiguate function overloads that would otherwise be /// identical after opening their parameter types. -static bool hasEmptyExistenialParameterMismatch(ValueDecl *decl1, - ValueDecl *decl2) { - +static bool hasEmptyExistentialParameterMismatch(ValueDecl *decl1, + ValueDecl *decl2) { auto func1 = dyn_cast(decl1); auto func2 = dyn_cast(decl2); - - if (func1 && func2) { - - auto pp1 = func1->getBodyParamPatterns(); - auto pp2 = func2->getBodyParamPatterns(); + if (!func1 || !func2) return false; - if (pp1.empty() || pp2.empty()) + auto pl1 = func1->getParameterLists(); + auto pl2 = func2->getParameterLists(); + + auto pc = std::min(pl1.size(), pl2.size()); + + for (size_t i = 0; i < pc; i++) { + auto t1 = getTypeAtIndex(pl1[i], i); + auto t2 = getTypeAtIndex(pl2[i], i); + if (!t1 || !t2) return false; - auto pc = std::min(pp1.size(), pp2.size()); - - for (size_t i = 0; i < pc; i++) { - - auto t1 = getTypeAtIndex(pp1[i]->getType().getPointer(), i); - auto t2 = getTypeAtIndex(pp2[i]->getType().getPointer(), i); - - if (!t1 || !t2) - break; - - if (t2->isAnyExistentialType() && !t1->isAnyExistentialType()) { - return t2->isEmptyExistentialComposition(); - } - } + if (t2->isAnyExistentialType() && !t1->isAnyExistentialType()) + return t2->isEmptyExistentialComposition(); } - return false; } @@ -485,7 +452,7 @@ static bool isProtocolExtensionAsSpecializedAs(TypeChecker &tc, llvm::DenseMap replacements; cs.openGeneric(dc2, sig2->getGenericParams(), sig2->getRequirements(), false, dc2->getGenericTypeContextDepth(), - nullptr, ConstraintLocatorBuilder(nullptr), + ConstraintLocatorBuilder(nullptr), replacements); // Bind the 'Self' type from the first extension to the type parameter from @@ -504,14 +471,11 @@ static bool isProtocolExtensionAsSpecializedAs(TypeChecker &tc, /// Count the number of default arguments in the primary clause. static unsigned countDefaultArguments(AbstractFunctionDecl *func) { - auto pattern - = func->getBodyParamPatterns()[func->getImplicitSelfDecl() != 0]; - auto tuple = dyn_cast(pattern); - if (!tuple) return 0; + auto paramList = func->getParameterList(func->getImplicitSelfDecl() != 0); unsigned count = 0; - for (const auto &elt : tuple->getElements()) { - if (elt.getDefaultArgKind() != DefaultArgumentKind::None) + for (auto elt : *paramList) { + if (elt->isDefaultArgument()) ++count; } @@ -524,192 +488,225 @@ static unsigned countDefaultArguments(AbstractFunctionDecl *func) { /// "Specialized" is essentially a form of subtyping, defined below. static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2) { - // If the kinds are different, there's nothing we can do. - // FIXME: This is wrong for type declarations, which we're skipping - // entirely. - if (decl1->getKind() != decl2->getKind() || isa(decl1)) - return false; - // A non-generic declaration is more specialized than a generic declaration. - if (auto func1 = dyn_cast(decl1)) { - auto func2 = cast(decl2); - if (static_cast(func1->getGenericParams()) != - static_cast(func2->getGenericParams())) - return func2->getGenericParams(); + if (tc.getLangOpts().DebugConstraintSolver) { + auto &log = tc.Context.TypeCheckerDebug->getStream(); + log << "Comparing declarations\n"; + decl1->print(log); + log << "\nand\n"; + decl2->print(log); + log << "\n"; } - // A witness is always more specialized than the requirement it satisfies. - switch (compareWitnessAndRequirement(tc, dc, decl1, decl2)) { - case Comparison::Unordered: - break; + if (!tc.specializedOverloadComparisonCache.count({decl1, decl2})) { + + auto compareSpecializations = [&] () -> bool { + // If the kinds are different, there's nothing we can do. + // FIXME: This is wrong for type declarations, which we're skipping + // entirely. + if (decl1->getKind() != decl2->getKind() || isa(decl1)) + return false; + + // A non-generic declaration is more specialized than a generic declaration. + if (auto func1 = dyn_cast(decl1)) { + auto func2 = cast(decl2); + if (static_cast(func1->getGenericParams()) != + static_cast(func2->getGenericParams())) + return func2->getGenericParams(); + } - case Comparison::Better: - return true; + // A witness is always more specialized than the requirement it satisfies. + switch (compareWitnessAndRequirement(tc, dc, decl1, decl2)) { + case Comparison::Unordered: + break; - case Comparison::Worse: - return false; - } + case Comparison::Better: + return true; - // Members of protocol extensions have special overloading rules. - ProtocolDecl *inProtocolExtension1 = decl1->getDeclContext() - ->isProtocolExtensionContext(); - ProtocolDecl *inProtocolExtension2 = decl2->getDeclContext() - ->isProtocolExtensionContext(); - if (inProtocolExtension1 && inProtocolExtension2) { - // Both members are in protocol extensions. - // Determine whether the 'Self' type from the first protocol extension - // satisfies all of the requirements of the second protocol extension. - DeclContext *dc1 = decl1->getDeclContext(); - DeclContext *dc2 = decl2->getDeclContext(); - bool better1 = isProtocolExtensionAsSpecializedAs(tc, dc1, dc2); - bool better2 = isProtocolExtensionAsSpecializedAs(tc, dc2, dc1); - if (better1 != better2) { - return better1; - } - } else if (inProtocolExtension1 || inProtocolExtension2) { - // One member is in a protocol extension, the other is in a concrete type. - // Prefer the member in the concrete type. - return inProtocolExtension2; - } + case Comparison::Worse: + return false; + } - Type type1 = decl1->getInterfaceType(); - Type type2 = decl2->getInterfaceType(); - - /// What part of the type should we check? - enum { - CheckAll, - CheckInput, - } checkKind; - if (isa(decl1) || isa(decl1)) { - // Nothing to do: these have the curried 'self' already. - if (auto elt = dyn_cast(decl1)) { - checkKind = elt->hasArgumentType() ? CheckInput : CheckAll; - } else { - checkKind = CheckInput; - } - } else { - // Add a curried 'self' type. - assert(!type1->is() && "Odd generic function type?"); - assert(!type2->is() && "Odd generic function type?"); - type1 = addCurriedSelfType(tc.Context, type1, decl1->getDeclContext()); - type2 = addCurriedSelfType(tc.Context, type2, decl2->getDeclContext()); - - // For a subscript declaration, only look at the input type (i.e., the - // indices). - if (isa(decl1)) - checkKind = CheckInput; - else - checkKind = CheckAll; - } + // Members of protocol extensions have special overloading rules. + ProtocolDecl *inProtocolExtension1 = decl1->getDeclContext() + ->isProtocolExtensionContext(); + ProtocolDecl *inProtocolExtension2 = decl2->getDeclContext() + ->isProtocolExtensionContext(); + if (inProtocolExtension1 && inProtocolExtension2) { + // Both members are in protocol extensions. + // Determine whether the 'Self' type from the first protocol extension + // satisfies all of the requirements of the second protocol extension. + DeclContext *dc1 = decl1->getDeclContext(); + DeclContext *dc2 = decl2->getDeclContext(); + bool better1 = isProtocolExtensionAsSpecializedAs(tc, dc1, dc2); + bool better2 = isProtocolExtensionAsSpecializedAs(tc, dc2, dc1); + if (better1 != better2) { + return better1; + } + } else if (inProtocolExtension1 || inProtocolExtension2) { + // One member is in a protocol extension, the other is in a concrete type. + // Prefer the member in the concrete type. + return inProtocolExtension2; + } - // Construct a constraint system to compare the two declarations. - ConstraintSystem cs(tc, dc, ConstraintSystemOptions()); - - auto locator = cs.getConstraintLocator(nullptr); - // FIXME: Locator when anchored on a declaration. - // Get the type of a reference to the second declaration. - Type openedType2 = cs.openType(type2, locator, - decl2->getPotentialGenericDeclContext()); - - // Get the type of a reference to the first declaration, swapping in - // archetypes for the dependent types. - ArchetypeOpener opener(decl1->getPotentialGenericDeclContext()); - Type openedType1 = cs.openType(type1, locator, - decl1->getPotentialGenericDeclContext(), - &opener); - - // Extract the self types from the declarations, if they have them. - Type selfTy1; - Type selfTy2; - if (decl1->getDeclContext()->isTypeContext()) { - auto funcTy1 = openedType1->castTo(); - selfTy1 = funcTy1->getInput()->getRValueInstanceType(); - openedType1 = funcTy1->getResult(); - } - if (decl2->getDeclContext()->isTypeContext()) { - auto funcTy2 = openedType2->castTo(); - selfTy2 = funcTy2->getInput()->getRValueInstanceType(); - openedType2 = funcTy2->getResult(); - } - - // Determine the relationship between the 'self' types and add the - // appropriate constraints. The constraints themselves never fail, but - // they help deduce type variables that were opened. - switch (computeSelfTypeRelationship(tc, dc, decl1->getDeclContext(), - decl2->getDeclContext())) { - case SelfTypeRelationship::Unrelated: - // Skip the self types parameter entirely. - break; - - case SelfTypeRelationship::Equivalent: - cs.addConstraint(ConstraintKind::Equal, selfTy1, selfTy2, locator); - break; - - case SelfTypeRelationship::Subclass: - cs.addConstraint(ConstraintKind::Subtype, selfTy1, selfTy2, locator); - break; - - case SelfTypeRelationship::Superclass: - cs.addConstraint(ConstraintKind::Subtype, selfTy2, selfTy1, locator); - break; - - case SelfTypeRelationship::ConformsTo: - cs.addConstraint(ConstraintKind::ConformsTo, selfTy1, selfTy2, locator); - break; - - case SelfTypeRelationship::ConformedToBy: - cs.addConstraint(ConstraintKind::ConformsTo, selfTy2, selfTy1, locator); - break; - } + Type type1 = decl1->getInterfaceType(); + Type type2 = decl2->getInterfaceType(); + + /// What part of the type should we check? + enum { + CheckAll, + CheckInput, + } checkKind; + if (isa(decl1) || isa(decl1)) { + // Nothing to do: these have the curried 'self' already. + if (auto elt = dyn_cast(decl1)) { + checkKind = elt->hasArgumentType() ? CheckInput : CheckAll; + } else { + checkKind = CheckInput; + } + } else { + // Add a curried 'self' type. + assert(!type1->is() && "Odd generic function type?"); + assert(!type2->is() && "Odd generic function type?"); + type1 = addCurriedSelfType(tc.Context, type1, decl1->getDeclContext()); + type2 = addCurriedSelfType(tc.Context, type2, decl2->getDeclContext()); + + // For a subscript declaration, only look at the input type (i.e., the + // indices). + if (isa(decl1)) + checkKind = CheckInput; + else + checkKind = CheckAll; + } - switch (checkKind) { - case CheckAll: - // Check whether the first type is a subtype of the second. - cs.addConstraint(ConstraintKind::Subtype, - openedType1, - openedType2, - locator); - break; - - case CheckInput: { - // Check whether the first function type's input is a subtype of the second - // type's inputs, i.e., can we forward the arguments? - auto funcTy1 = openedType1->castTo(); - auto funcTy2 = openedType2->castTo(); - cs.addConstraint(ConstraintKind::Subtype, - funcTy1->getInput(), - funcTy2->getInput(), - locator); - break; - } - } + // Construct a constraint system to compare the two declarations. + ConstraintSystem cs(tc, dc, ConstraintSystemOptions()); + + auto locator = cs.getConstraintLocator(nullptr); + // FIXME: Locator when anchored on a declaration. + // Get the type of a reference to the second declaration. + Type openedType2 = cs.openType(type2, locator, + decl2->getInnermostDeclContext()); + + // Get the type of a reference to the first declaration, swapping in + // archetypes for the dependent types. + llvm::DenseMap replacements; + auto dc1 = decl1->getInnermostDeclContext(); + Type openedType1 = cs.openType(type1, locator, replacements, dc1); + for (const auto &replacement : replacements) { + if (auto mapped = + ArchetypeBuilder::mapTypeIntoContext(dc1, + replacement.first)) { + cs.addConstraint(ConstraintKind::Bind, replacement.second, mapped, + locator); + } + } - // Solve the system. - auto solution = cs.solveSingle(FreeTypeVariableBinding::Allow); + // Extract the self types from the declarations, if they have them. + Type selfTy1; + Type selfTy2; + if (decl1->getDeclContext()->isTypeContext()) { + auto funcTy1 = openedType1->castTo(); + selfTy1 = funcTy1->getInput()->getRValueInstanceType(); + openedType1 = funcTy1->getResult(); + } + if (decl2->getDeclContext()->isTypeContext()) { + auto funcTy2 = openedType2->castTo(); + selfTy2 = funcTy2->getInput()->getRValueInstanceType(); + openedType2 = funcTy2->getResult(); + } + + // Determine the relationship between the 'self' types and add the + // appropriate constraints. The constraints themselves never fail, but + // they help deduce type variables that were opened. + switch (computeSelfTypeRelationship(tc, dc, decl1->getDeclContext(), + decl2->getDeclContext())) { + case SelfTypeRelationship::Unrelated: + // Skip the self types parameter entirely. + break; + case SelfTypeRelationship::Equivalent: + cs.addConstraint(ConstraintKind::Equal, selfTy1, selfTy2, locator); + break; - // Ban value-to-optional conversions. - if (solution && solution->getFixedScore().Data[SK_ValueToOptional] == 0) - return true; + case SelfTypeRelationship::Subclass: + cs.addConstraint(ConstraintKind::Subtype, selfTy1, selfTy2, locator); + break; - // Between two imported functions/methods, prefer one with fewer defaulted - // arguments. - // - // FIXME: This is a total hack; we should be comparing based on the number of - // default arguments at were actually used. It's only safe to do this because - // the count will be zero except when under the experimental - // InferDefaultArguments mode of the Clang importer. - if (isa(decl1) && isa(decl2) && - decl1->getClangDecl() && decl2->getClangDecl()) { - unsigned defArgsIn1 - = countDefaultArguments(cast(decl1)); - unsigned defArgsIn2 - = countDefaultArguments(cast(decl2)); - if (defArgsIn1 < defArgsIn2) - return true; + case SelfTypeRelationship::Superclass: + cs.addConstraint(ConstraintKind::Subtype, selfTy2, selfTy1, locator); + break; + + case SelfTypeRelationship::ConformsTo: + cs.addConstraint(ConstraintKind::ConformsTo, selfTy1, selfTy2, locator); + break; + + case SelfTypeRelationship::ConformedToBy: + cs.addConstraint(ConstraintKind::ConformsTo, selfTy2, selfTy1, locator); + break; + } + + switch (checkKind) { + case CheckAll: + // Check whether the first type is a subtype of the second. + cs.addConstraint(ConstraintKind::Subtype, + openedType1, + openedType2, + locator); + break; + + case CheckInput: { + // Check whether the first function type's input is a subtype of the + // second type's inputs, i.e., can we forward the arguments? + auto funcTy1 = openedType1->castTo(); + auto funcTy2 = openedType2->castTo(); + cs.addConstraint(ConstraintKind::Subtype, + funcTy1->getInput(), + funcTy2->getInput(), + locator); + break; + } + } + + // Solve the system. + auto solution = cs.solveSingle(FreeTypeVariableBinding::Allow); + + + // Ban value-to-optional conversions. + if (solution && solution->getFixedScore().Data[SK_ValueToOptional] == 0) + return true; + + // Between two imported functions/methods, prefer one with fewer + // defaulted arguments. + // + // FIXME: This is a total hack; we should be comparing based on the + // number of default arguments at were actually used. It's only safe to + // do this because the count will be zero except when under the + // experimental InferDefaultArguments mode of the Clang importer. + if (isa(decl1) && + isa(decl2) && + decl1->getClangDecl() && + decl2->getClangDecl()) { + unsigned defArgsIn1 + = countDefaultArguments(cast(decl1)); + unsigned defArgsIn2 + = countDefaultArguments(cast(decl2)); + if (defArgsIn1 < defArgsIn2) + return true; + } + + return false; + }; + + tc.specializedOverloadComparisonCache[{decl1, decl2}] = + compareSpecializations(); + } else if (tc.getLangOpts().DebugConstraintSolver) { + auto &log = tc.Context.TypeCheckerDebug->getStream(); + log << "Found cached comparison: " + << tc.specializedOverloadComparisonCache[{decl1, decl2}] << "\n"; } - return false; + return tc.specializedOverloadComparisonCache[{decl1, decl2}]; } Comparison TypeChecker::compareDeclarations(DeclContext *dc, @@ -729,6 +726,13 @@ ConstraintSystem::compareSolutions(ConstraintSystem &cs, ArrayRef solutions, const SolutionDiff &diff, unsigned idx1, unsigned idx2) { + + if (cs.TC.getLangOpts().DebugConstraintSolver) { + auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); + log.indent(cs.solverState->depth * 2) + << "comparing solutions " << idx1 << " and " << idx2 <<"\n"; + } + // Whether the solutions are identical. bool identical = true; @@ -922,11 +926,11 @@ ConstraintSystem::compareSolutions(ConstraintSystem &cs, // wise comparison between an empty existential collection and a non- // existential type. if (!(foundRefinement1 && foundRefinement2)) { - if (hasEmptyExistenialParameterMismatch(decl1, decl2)) { + if (hasEmptyExistentialParameterMismatch(decl1, decl2)) { foundRefinement1 = true; } - if (hasEmptyExistenialParameterMismatch(decl2, decl1)) { + if (hasEmptyExistentialParameterMismatch(decl2, decl1)) { foundRefinement2 = true; } } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 170d9d718ed8b..f836914a62ab2 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -542,6 +542,14 @@ matchCallArguments(ConstraintSystem &cs, TypeMatchKind kind, if (argType->is()) { return ConstraintSystem::SolutionKind::Error; } + // If the param type is an empty existential composition, the function can + // only have one argument. Check if exactly one argument was passed to this + // function, otherwise we obviously have a mismatch + if (auto tupleArgType = argType->getAs()) { + if (tupleArgType->getNumElements() != 1) { + return ConstraintSystem::SolutionKind::Error; + } + } return ConstraintSystem::SolutionKind::Solved; } @@ -582,7 +590,7 @@ matchCallArguments(ConstraintSystem &cs, TypeMatchKind kind, case TypeMatchKind::SameType: case TypeMatchKind::ConformsTo: case TypeMatchKind::Subtype: - llvm_unreachable("Not an call argument constraint"); + llvm_unreachable("Not a call argument constraint"); } auto haveOneNonUserConversion = @@ -691,7 +699,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, // If the names don't match, we may have a conflict. if (elt1.getName() != elt2.getName()) { // Same-type requirements require exact name matches. - if (kind == TypeMatchKind::SameType) + if (kind <= TypeMatchKind::SameType) return SolutionKind::Error; // For subtyping constraints, just make sure that this name isn't @@ -932,23 +940,10 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, return SolutionKind::Error; // Result type can be covariant (or equal). - switch (matchTypes(func1->getResult(), func2->getResult(), subKind, + return matchTypes(func1->getResult(), func2->getResult(), subKind, subFlags, locator.withPathElement( - ConstraintLocator::FunctionResult))) { - case SolutionKind::Error: - return SolutionKind::Error; - - case SolutionKind::Solved: - result = SolutionKind::Solved; - break; - - case SolutionKind::Unsolved: - result = SolutionKind::Unsolved; - break; - } - - return result; + ConstraintLocator::FunctionResult)); } ConstraintSystem::SolutionKind @@ -1145,17 +1140,22 @@ static bool isArrayDictionarySetOrString(const ASTContext &ctx, Type type) { return false; } -/// Return the number of elements of parameter tuple type 'tupleTy' that must -/// be matched to arguments, as opposed to being varargs or having default -/// values. -static unsigned tupleTypeRequiredArgCount(TupleType *tupleTy) { - auto argIsRequired = [&](const TupleTypeElt &elt) { - return !elt.isVararg() && - elt.getDefaultArgKind() == DefaultArgumentKind::None; - }; - return std::count_if( - tupleTy->getElements().begin(), tupleTy->getElements().end(), - argIsRequired); +/// Given that 'tupleTy' is the argument type of a function that's being +/// invoked with a single unlabeled argument, return the type of the parameter +/// that matches that argument, or the null type if such a match is impossible. +static Type getTupleElementTypeForSingleArgument(TupleType *tupleTy) { + Type result; + for (auto ¶m : tupleTy->getElements()) { + bool mustClaimArg = !param.isVararg() && + param.getDefaultArgKind() == DefaultArgumentKind::None; + bool canClaimArg = !param.hasName(); + if (!result && canClaimArg) { + result = param.isVararg() ? param.getVarargBaseTy() : param.getType(); + } else if (mustClaimArg) { + return Type(); + } + } + return result; } ConstraintSystem::SolutionKind @@ -1234,31 +1234,19 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, // If the left-hand type variable cannot bind to an lvalue, // but we still have an lvalue, fail. - if (!typeVar1->getImpl().canBindToLValue()) { - if (type2->isLValueType()) { - if (shouldRecordFailures()) { - recordFailure(getConstraintLocator(locator), - Failure::IsForbiddenLValue, type1, type2); - } - return SolutionKind::Error; - } + if (!typeVar1->getImpl().canBindToLValue() && + type2->isLValueType()) + return SolutionKind::Error; - // Okay. Bind below. - } + // Okay. Bind below. // Check whether the type variable must be bound to a materializable // type. if (typeVar1->getImpl().mustBeMaterializable()) { - if (!type2->isMaterializable()) { - if (shouldRecordFailures()) { - // TODO: customize error message for closure vs. generic param - recordFailure(getConstraintLocator(locator), - Failure::IsNotMaterializable, type2); - } + if (!type2->isMaterializable()) return SolutionKind::Error; - } else { - setMustBeMaterializableRecursive(type2); - } + + setMustBeMaterializableRecursive(type2); } // A constraint that binds any pointer to a void pointer is @@ -1285,14 +1273,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, if (wantRvalue) type1 = type1->getRValueType(); - if (!typeVar2->getImpl().canBindToLValue()) { - if (type1->isLValueType()) { - if (shouldRecordFailures()) { - recordFailure(getConstraintLocator(locator), - Failure::IsForbiddenLValue, type1, type2); - } - return SolutionKind::Error; - } + if (!typeVar2->getImpl().canBindToLValue() && + type1->isLValueType()) { + return SolutionKind::Error; // Okay. Bind below. } @@ -1316,6 +1299,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, assignFixedType(typeVar1, type2); } return SolutionKind::Solved; + } else if (typeVar1 && typeVar2) { + auto rep1 = getRepresentative(typeVar1); + auto rep2 = getRepresentative(typeVar2); + if (rep1 == rep2) { + return SolutionKind::Solved; + } } return SolutionKind::Unsolved; } @@ -1332,28 +1321,29 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, case TypeMatchKind::ArgumentTupleConversion: if (typeVar1 && !typeVar1->getImpl().literalConformanceProto && - kind == TypeMatchKind::ArgumentTupleConversion && (flags & TMF_GenerateConstraints) && - dyn_cast(type1.getPointer())) { - - auto tupleTy = type2->getAs(); + isa(type1.getPointer())) { - if (tupleTy && - !tupleTy->getElements().empty() && - (tupleTy->hasAnyDefaultValues() || - tupleTy->getElement(0).isVararg()) && - !tupleTy->getElement(0).hasName() && - tupleTypeRequiredArgCount(tupleTy) <= 1) { - - // Look through vararg types, if necessary. - auto tupleElt = tupleTy->getElement(0); - auto tupleEltTy = tupleElt.isVararg() ? - tupleElt.getVarargBaseTy() : tupleElt.getType(); - - addConstraint(getConstraintKind(kind), - typeVar1, - tupleEltTy, - getConstraintLocator(locator)); + if (auto tupleTy = type2->getAs()) { + if (auto tupleEltTy = getTupleElementTypeForSingleArgument(tupleTy)) { + addConstraint(getConstraintKind(kind), + typeVar1, + tupleEltTy, + getConstraintLocator(locator)); + return SolutionKind::Solved; + } + } + + } + SWIFT_FALLTHROUGH; + + case TypeMatchKind::Conversion: + if (typeVar1 && typeVar2) { + auto rep1 = getRepresentative(typeVar1); + auto rep2 = getRepresentative(typeVar2); + if (rep1 == rep2) { + // We already merged these two types, so this constraint is + // trivially solved. return SolutionKind::Solved; } } @@ -1361,7 +1351,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, case TypeMatchKind::ConformsTo: case TypeMatchKind::Subtype: - case TypeMatchKind::Conversion: case TypeMatchKind::ExplicitConversion: case TypeMatchKind::ArgumentConversion: case TypeMatchKind::OperatorArgumentTupleConversion: @@ -1534,11 +1523,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, break; case TypeKind::LValue: - if (kind == TypeMatchKind::BindParamType) { - recordFailure(getConstraintLocator(locator), - Failure::IsForbiddenLValue, type1, type2); + if (kind == TypeMatchKind::BindParamType) return SolutionKind::Error; - } return matchTypes(cast(desugar1)->getObjectType(), cast(desugar2)->getObjectType(), TypeMatchKind::SameType, subFlags, @@ -1548,12 +1534,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, case TypeKind::InOut: // If the RHS is an inout type, the LHS must be an @lvalue type. if (kind == TypeMatchKind::BindParamType || - kind >= TypeMatchKind::OperatorArgumentConversion) { - if (shouldRecordFailures()) - recordFailure(getConstraintLocator(locator), - Failure::IsForbiddenLValue, type1, type2); + kind >= TypeMatchKind::OperatorArgumentConversion) return SolutionKind::Error; - } + return matchTypes(cast(desugar1)->getObjectType(), cast(desugar2)->getObjectType(), TypeMatchKind::SameType, subFlags, @@ -1599,12 +1582,16 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, // containing a single element if the scalar type is a subtype of // the type of that tuple's element. // - // A scalar type can be converted to a tuple so long as there is at - // most one non-defaulted element. + // A scalar type can be converted to an argument tuple so long as + // there is at most one non-defaulted element. + // For non-argument tuples, we can do the same conversion but not + // to a tuple with varargs. if ((tuple2->getNumElements() == 1 && !tuple2->getElement(0).isVararg()) || (kind >= TypeMatchKind::Conversion && - tuple2->getElementForScalarInit() >= 0)) { + tuple2->getElementForScalarInit() >= 0 && + (isArgumentTupleConversion || + !tuple2->getVarArgsBaseType()))) { conversionsOrFixes.push_back( ConversionRestrictionKind::ScalarToTuple); @@ -2208,14 +2195,8 @@ ConstraintSystem::simplifyConstructionConstraint(Type valueType, if (isa(DC)) lookupOptions |= NameLookupFlags::KnownPrivate; auto ctors = TC.lookupConstructors(DC, valueType, lookupOptions); - if (!ctors) { - // If we are supposed to record failures, do so. - if (shouldRecordFailures()) { - recordFailure(locator, Failure::NoPublicInitializers, valueType); - } - + if (!ctors) return SolutionKind::Error; - } auto &context = getASTContext(); auto name = context.Id_init; @@ -2568,7 +2549,7 @@ static bool isUnavailableInExistential(TypeChecker &tc, ValueDecl *decl) { // Allow functions to return Self, but not have Self anywhere in // their argument types. - for (unsigned i = 1, n = afd->getNumParamPatterns(); i != n; ++i) { + for (unsigned i = 1, n = afd->getNumParameterLists(); i != n; ++i) { // Check whether the input type contains Self anywhere. auto fnType = type->castTo(); if (containsProtocolSelf(fnType->getInput())) @@ -2690,10 +2671,14 @@ getArgumentLabels(ConstraintSystem &cs, ConstraintLocatorBuilder locator) { /// perform a lookup into the specified base type to find a candidate list. /// The list returned includes the viable candidates as well as the unviable /// ones (along with reasons why they aren't viable). +/// +/// If includeInaccessibleMembers is set to true, this burns compile time to +/// try to identify and classify inaccessible members that may be being +/// referenced. MemberLookupResult ConstraintSystem:: -performMemberLookup(ConstraintKind constraintKind, - DeclName memberName, Type baseTy, - ConstraintLocator *memberLocator) { +performMemberLookup(ConstraintKind constraintKind, DeclName memberName, + Type baseTy, ConstraintLocator *memberLocator, + bool includeInaccessibleMembers) { Type baseObjTy = baseTy->getRValueType(); // Dig out the instance type and figure out what members of the instance type @@ -2824,6 +2809,12 @@ performMemberLookup(ConstraintKind constraintKind, NameLookupOptions lookupOptions = defaultConstructorLookupOptions; if (isa(DC)) lookupOptions |= NameLookupFlags::KnownPrivate; + + // If we're doing a lookup for diagnostics, include inaccessible members, + // the diagnostics machinery will sort it out. + if (includeInaccessibleMembers) + lookupOptions |= NameLookupFlags::IgnoreAccessibility; + LookupResult ctors = TC.lookupConstructors(DC, baseObjTy, lookupOptions); if (!ctors) return result; // No result. @@ -2923,6 +2914,12 @@ performMemberLookup(ConstraintKind constraintKind, NameLookupOptions lookupOptions = defaultMemberTypeLookupOptions; if (isa(DC)) lookupOptions |= NameLookupFlags::KnownPrivate; + + // If we're doing a lookup for diagnostics, include inaccessible members, + // the diagnostics machinery will sort it out. + if (includeInaccessibleMembers) + lookupOptions |= NameLookupFlags::IgnoreAccessibility; + auto lookup = TC.lookupMemberType(DC, baseObjTy, memberName.getBaseName(), lookupOptions); // Form the overload set. @@ -3115,6 +3112,33 @@ performMemberLookup(ConstraintKind constraintKind, goto retry_after_fail; } + // If we have no viable or unviable candidates, and we're generating, + // diagnostics, rerun the query with inaccessible members included, so we can + // include them in the unviable candidates list. + if (result.ViableCandidates.empty() && result.UnviableCandidates.empty() && + includeInaccessibleMembers) { + NameLookupOptions lookupOptions = defaultMemberLookupOptions; + + // Ignore accessibility so we get candidates that might have been missed + // before. + lookupOptions |= NameLookupFlags::IgnoreAccessibility; + // This is only used for diagnostics, so always use KnownPrivate. + lookupOptions |= NameLookupFlags::KnownPrivate; + + auto lookup = TC.lookupMember(DC, baseObjTy->getCanonicalType(), + memberName, lookupOptions); + for (auto cand : lookup) { + // If the result is invalid, skip it. + TC.validateDecl(cand, true); + if (cand->isInvalid()) { + result.markErrorAlreadyDiagnosed(); + return result; + } + + result.addUnviable(cand, MemberLookupResult::UR_Inaccessible); + } + } + return result; } @@ -3140,7 +3164,8 @@ ConstraintSystem::simplifyMemberConstraint(const Constraint &constraint) { MemberLookupResult result = performMemberLookup(constraint.getKind(), constraint.getMember(), - baseTy, constraint.getLocator()); + baseTy, constraint.getLocator(), + /*includeInaccessibleMembers*/false); DeclName name = constraint.getMember(); Type memberTy = constraint.getSecondType(); @@ -3236,7 +3261,7 @@ ConstraintSystem::simplifyMemberConstraint(const Constraint &constraint) { return SolutionKind::Solved; } - if (shouldAttemptFixes() && name.isSimpleName("allZeros") && + if (shouldAttemptFixes() && name.isSimpleName(getASTContext().Id_allZeros) && (rawValueType = getRawRepresentableValueType(TC, DC, instanceTy))) { // Replace a reference to "X.allZeros" with a reference to X(). // FIXME: This is temporary. @@ -3337,11 +3362,6 @@ ConstraintSystem::simplifyBridgedToObjectiveCConstraint( increaseScore(SK_UserConversion); return SolutionKind::Solved; } - - // Record this failure. - recordFailure(constraint.getLocator(), - Failure::IsNotBridgedToObjectiveC, - baseTy); return SolutionKind::Error; } diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index c0764ab7a7786..652aeb120cf2f 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,9 +23,9 @@ using namespace swift; using namespace constraints; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Constraint solver statistics -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #define DEBUG_TYPE "Constraint solver overall" #define JOIN(X,Y) JOIN2(X,Y) #define JOIN2(X,Y) X##Y @@ -336,6 +336,8 @@ bool ConstraintSystem::simplify(bool ContinueAfterFailures) { if (solverState) solverState->retiredConstraints.push_front(constraint); + else + CG.removeConstraint(constraint); break; @@ -819,6 +821,15 @@ static PotentialBindings getPotentialBindings(ConstraintSystem &cs, auto first = cs.simplifyType(constraint->getFirstType()); auto second = cs.simplifyType(constraint->getSecondType()); + if (auto firstTyvar = first->getAs()) { + if (auto secondTyvar = second->getAs()) { + if (cs.getRepresentative(firstTyvar) == + cs.getRepresentative(secondTyvar)) { + break; + } + } + } + Type type; AllowedBindingKind kind; if (first->getAs() == typeVar) { @@ -1018,6 +1029,7 @@ static bool tryTypeVariableBindings( FreeTypeVariableBinding allowFreeTypeVariables) { bool anySolved = false; llvm::SmallPtrSet exploredTypes; + llvm::SmallPtrSet boundTypes; SmallVector storedBindings; auto &tc = cs.getTypeChecker(); @@ -1036,6 +1048,19 @@ static bool tryTypeVariableBindings( // Try each of the bindings in turn. ++cs.solverState->NumTypeVariableBindings; bool sawFirstLiteralConstraint = false; + + if (tc.getLangOpts().DebugConstraintSolver) { + auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); + log.indent(depth * 2) << "Active bindings: "; + + for (auto binding : bindings) { + log << typeVar->getString() << " := " + << binding.BindingType->getString() << " "; + } + + log <<"\n"; + } + for (auto binding : bindings) { auto type = binding.BindingType; @@ -1047,11 +1072,38 @@ static bool tryTypeVariableBindings( // Remove parentheses. They're insignificant here. type = type->getWithoutParens(); + // If we've already tried this binding, move on. + if (!boundTypes.insert(type.getPointer()).second) + continue; + + // Prevent against checking against the same bound generic type + // over and over again. Doing so means redundant work in the best + // case. In the worst case, we'll produce lots of duplicate solutions + // for this constraint system, which is problematic for overload + // resolution. + if (type->hasTypeVariable()) { + auto triedBinding = false; + if (auto BGT = type->getAs()) { + for (auto bt : boundTypes) { + if (auto BBGT = bt->getAs()) { + if (BGT != BBGT && + BGT->getDecl() == BBGT->getDecl()) { + triedBinding = true; + break; + } + } + } + } + + if (triedBinding) + continue; + } + if (tc.getLangOpts().DebugConstraintSolver) { auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); log.indent(depth * 2) - << "(trying " << typeVar->getString() - << " := " << type->getString() << "\n"; + << "(trying " << typeVar->getString() << " := " << type->getString() + << "\n"; } // Try to solve the system with typeVar := type @@ -1092,9 +1144,11 @@ static bool tryTypeVariableBindings( // Enumerate the supertypes of each of the types we tried. for (auto binding : bindings) { - auto type = binding.BindingType; + const auto type = binding.BindingType; + if (type->is()) + continue; - // After our first pass, note that that we've explored these + // After our first pass, note that we've explored these // types. if (tryCount == 0) exploredTypes.insert(type->getCanonicalType()); @@ -1190,7 +1244,8 @@ bool ConstraintSystem::solve(SmallVectorImpl &solutions, // If there is more than one viable system, attempt to pick the best // solution. - if (solutions.size() > 1) { + auto size = solutions.size(); + if (size > 1) { if (auto best = findBestSolution(solutions, /*minimize=*/false)) { if (*best != 0) solutions[0] = std::move(solutions[*best]); @@ -1238,6 +1293,9 @@ bool ConstraintSystem::solveRec(SmallVectorImpl &solutions, return false; } + // Contract the edges of the constraint graph. + CG.optimize(); + // Compute the connected components of the constraint graph. // FIXME: We're seeding typeVars with TypeVariables so that the // connected-components algorithm only considers those type variables within @@ -1370,7 +1428,7 @@ bool ConstraintSystem::solveRec(SmallVectorImpl &solutions, // ready for the next component. TypeVariables = std::move(allTypeVariables); - // For each of the partial solutions, substract off the current score. + // For each of the partial solutions, subtract off the current score. // It doesn't contribute. for (auto &solution : partialSolutions[component]) solution.getFixedScore() -= CurrentScore; @@ -1558,22 +1616,26 @@ bool ConstraintSystem::solveSimplified( // constraints that could show up here? if (allowFreeTypeVariables != FreeTypeVariableBinding::Disallow && hasFreeTypeVariables()) { + + // If this solution is worse than the best solution we've seen so far, + // skip it. + if (worseThanBestSolution()) + return true; + bool anyNonConformanceConstraints = false; for (auto &constraint : InactiveConstraints) { - if (constraint.getKind() == ConstraintKind::ConformsTo || - constraint.getKind() == ConstraintKind::SelfObjectOfProtocol || - constraint.getKind() == ConstraintKind::TypeMember) + switch (constraint.getClassification()) { + case ConstraintClassification::Relational: + case ConstraintClassification::Member: continue; + default: + break; + } anyNonConformanceConstraints = true; break; } - // If this solution is worse than the best solution we've seen so far, - // skip it. - if (worseThanBestSolution()) - return true; - if (!anyNonConformanceConstraints) { auto solution = finalize(allowFreeTypeVariables); if (TC.getLangOpts().DebugConstraintSolver) { @@ -1632,7 +1694,7 @@ bool ConstraintSystem::solveSimplified( ++solverState->NumDisjunctionTerms; if (TC.getLangOpts().DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); - log.indent(solverState->depth * 2) + log.indent(solverState->depth) << "(assuming "; constraint->print(log, &TC.Context.SourceMgr); log << '\n'; @@ -1698,7 +1760,7 @@ bool ConstraintSystem::solveSimplified( if (TC.getLangOpts().DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); - log.indent(solverState->depth * 2) << ")\n"; + log.indent(solverState->depth) << ")\n"; } } diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 807f5d46a3f3b..7688a16c60400 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1,8 +1,8 @@ -//===--- TypeCheckDecl.cpp - Type Checking for Declarations ---------------===// +//===--- CodeSynthesis.cpp - Type Checking for Declarations ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,6 +22,7 @@ #include "swift/AST/Attr.h" #include "swift/AST/Availability.h" #include "swift/AST/Expr.h" +#include "swift/AST/ParameterList.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" using namespace swift; @@ -32,78 +33,47 @@ const bool IsImplicit = true; /// decl is specified, the new decl is inserted next to the hint. static void addMemberToContextIfNeeded(Decl *D, DeclContext *DC, Decl *Hint = nullptr) { - if (auto *ntd = dyn_cast(DC)) + if (auto *ntd = dyn_cast(DC)) { ntd->addMember(D, Hint); - else if (auto *ed = dyn_cast(DC)) + } else if (auto *ed = dyn_cast(DC)) { ed->addMember(D, Hint); - else + } else if (isa(DC)) { + auto *mod = DC->getParentModule(); + mod->getDerivedFileUnit().addDerivedDecl(cast(D)); + } else { assert((isa(DC) || isa(DC)) && "Unknown declcontext"); -} - -static VarDecl *getParamDeclAtIndex(FuncDecl *fn, unsigned index) { - TuplePatternElt singleParam; - Pattern *paramPattern = fn->getBodyParamPatterns().back(); - ArrayRef params; - if (auto paramTuple = dyn_cast(paramPattern)) { - params = paramTuple->getElements(); - } else { - singleParam = TuplePatternElt( - cast(paramPattern)->getSubPattern()); - params = singleParam; } +} - auto firstParamPattern = params[index].getPattern(); - return firstParamPattern->getSingleVar(); +static ParamDecl *getParamDeclAtIndex(FuncDecl *fn, unsigned index) { + return fn->getParameterLists().back()->get(index); } static VarDecl *getFirstParamDecl(FuncDecl *fn) { return getParamDeclAtIndex(fn, 0); }; -/// \brief Build an implicit 'self' parameter for the specified DeclContext. -static Pattern *buildImplicitSelfParameter(SourceLoc Loc, DeclContext *DC) { - ASTContext &Ctx = DC->getASTContext(); - auto *SelfDecl = new (Ctx) ParamDecl(/*IsLet*/ true, Loc, Identifier(), - Loc, Ctx.Id_self, Type(), DC); - SelfDecl->setImplicit(); - Pattern *P = new (Ctx) NamedPattern(SelfDecl, /*Implicit=*/true); - return new (Ctx) TypedPattern(P, TypeLoc()); -} -static TuplePatternElt buildArgumentPattern(SourceLoc loc, DeclContext *DC, - StringRef name, Type type, - bool isLet, - VarDecl **paramDecl, - ASTContext &Context) { - auto *param = new (Context) ParamDecl(isLet, SourceLoc(), Identifier(), - loc, Context.getIdentifier(name), - Type(), DC); - if (paramDecl) *paramDecl = param; +static ParamDecl *buildArgument(SourceLoc loc, DeclContext *DC, + StringRef name, Type type, bool isLet) { + auto &context = DC->getASTContext(); + auto *param = new (context) ParamDecl(isLet, SourceLoc(), SourceLoc(), + Identifier(), loc, + context.getIdentifier(name),Type(), DC); param->setImplicit(); - - Pattern *valuePattern - = new (Context) TypedPattern(new (Context) NamedPattern(param, true), - TypeLoc::withoutLoc(type)); - valuePattern->setImplicit(); - - return TuplePatternElt(valuePattern); + param->getTypeLoc().setType(type); + return param; } -static TuplePatternElt buildLetArgumentPattern(SourceLoc loc, DeclContext *DC, - StringRef name, Type type, - VarDecl **paramDecl, - ASTContext &ctx) { - return buildArgumentPattern(loc, DC, name, type, - /*isLet*/ true, paramDecl, ctx); +static ParamDecl *buildLetArgument(SourceLoc loc, DeclContext *DC, + StringRef name, Type type) { + return buildArgument(loc, DC, name, type, /*isLet*/ true); } -static TuplePatternElt buildInOutArgumentPattern(SourceLoc loc, DeclContext *DC, - StringRef name, Type type, - VarDecl **paramDecl, - ASTContext &ctx) { - return buildArgumentPattern(loc, DC, name, InOutType::get(type), - /*isLet*/ false, paramDecl, ctx); +static ParamDecl *buildInOutArgument(SourceLoc loc, DeclContext *DC, + StringRef name, Type type) { + return buildArgument(loc, DC, name, InOutType::get(type), /*isLet*/ false); } static Type getTypeOfStorage(AbstractStorageDecl *storage, @@ -118,62 +88,35 @@ static Type getTypeOfStorage(AbstractStorageDecl *storage, } } -static TuplePatternElt -buildSetterValueArgumentPattern(AbstractStorageDecl *storage, - VarDecl **valueDecl, TypeChecker &TC) { - auto storageType = getTypeOfStorage(storage, TC); - return buildLetArgumentPattern(storage->getLoc(), - storage->getDeclContext(), - "value", storageType, valueDecl, TC.Context); -} - -/// Build a pattern which can forward the formal index parameters of a +/// Build a parameter list which can forward the formal index parameters of a /// declaration. /// /// \param prefix optional arguments to be prefixed onto the index -/// forwarding pattern -static Pattern *buildIndexForwardingPattern(AbstractStorageDecl *storage, - MutableArrayRef prefix, - TypeChecker &TC) { +/// forwarding pattern. +static ParameterList * +buildIndexForwardingParamList(AbstractStorageDecl *storage, + ArrayRef prefix) { + auto &context = storage->getASTContext(); auto subscript = dyn_cast(storage); - // Fast path: if this isn't a subscript, and we have a first - // pattern, we can just use that. - if (!subscript) { - auto tuple = TuplePattern::createSimple(TC.Context, SourceLoc(), prefix, - SourceLoc()); - tuple->setImplicit(); - return tuple; - } + // Fast path: if this isn't a subscript, just use whatever we have. + if (!subscript) + return ParameterList::create(context, prefix); - // Otherwise, we need to build up a new TuplePattern. - SmallVector elements; + // Clone the parameter list over for a new decl, so we get new ParamDecls. + auto indices = subscript->getIndices()->clone(context, + ParameterList::Implicit); + if (prefix.empty()) + return indices; + + + // Otherwise, we need to build up a new parameter list. + SmallVector elements; - // Start with the fields from the first pattern, if there are any. + // Start with the fields we were given, if there are any. elements.append(prefix.begin(), prefix.end()); - - // Clone index patterns in a manner that allows them to be - // perfectly forwarded. - DeclContext *DC = storage->getDeclContext(); - auto addVarPatternFor = [&](Pattern *P, Identifier label = Identifier()) { - Pattern *vp = P->cloneForwardable(TC.Context, DC, Pattern::Implicit); - elements.push_back(TuplePatternElt(vp)); - elements.back().setLabel(label, SourceLoc()); - }; - - // This is the same breakdown the parser does. - auto indices = subscript->getIndices(); - if (auto pp = dyn_cast(indices)) { - addVarPatternFor(pp); - } else { - auto tp = cast(indices); - for (auto &element : tp->getElements()) { - addVarPatternFor(element.getPattern(), element.getLabel()); - } - } - - return TuplePattern::createSimple(TC.Context, SourceLoc(), elements, - SourceLoc()); + elements.append(indices->begin(), indices->end()); + return ParameterList::create(context, elements); } static FuncDecl *createGetterPrototype(AbstractStorageDecl *storage, @@ -181,15 +124,16 @@ static FuncDecl *createGetterPrototype(AbstractStorageDecl *storage, SourceLoc loc = storage->getLoc(); // Create the parameter list for the getter. - SmallVector getterParams; + SmallVector getterParams; // The implicit 'self' argument if in a type context. if (storage->getDeclContext()->isTypeContext()) - getterParams.push_back( - buildImplicitSelfParameter(loc, storage->getDeclContext())); + getterParams.push_back(ParameterList::createSelf(loc, + storage->getDeclContext(), + /*isStatic*/false)); // Add an index-forwarding clause. - getterParams.push_back(buildIndexForwardingPattern(storage, {}, TC)); + getterParams.push_back(buildIndexForwardingParamList(storage, {})); SourceLoc staticLoc; if (auto var = dyn_cast(storage)) { @@ -219,23 +163,26 @@ static FuncDecl *createGetterPrototype(AbstractStorageDecl *storage, } static FuncDecl *createSetterPrototype(AbstractStorageDecl *storage, - VarDecl *&valueDecl, + ParamDecl *&valueDecl, TypeChecker &TC) { SourceLoc loc = storage->getLoc(); // Create the parameter list for the setter. - SmallVector params; + SmallVector params; // The implicit 'self' argument if in a type context. if (storage->getDeclContext()->isTypeContext()) { - params.push_back( - buildImplicitSelfParameter(loc, storage->getDeclContext())); + params.push_back(ParameterList::createSelf(loc, + storage->getDeclContext(), + /*isStatic*/false)); } - - // Add a "(value : T, indices...)" pattern. - TuplePatternElt valuePattern = - buildSetterValueArgumentPattern(storage, &valueDecl, TC); - params.push_back(buildIndexForwardingPattern(storage, valuePattern, TC)); + + // Add a "(value : T, indices...)" argument list. + auto storageType = getTypeOfStorage(storage, TC); + valueDecl = buildLetArgument(storage->getLoc(), + storage->getDeclContext(), "value", + storageType); + params.push_back(buildIndexForwardingParamList(storage, valueDecl)); Type setterRetTy = TupleType::getEmpty(TC.Context); FuncDecl *setter = FuncDecl::create( @@ -346,30 +293,26 @@ static Type createMaterializeForSetReturnType(AbstractStorageDecl *storage, } static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage, - VarDecl *&bufferParamDecl, TypeChecker &TC) { auto &ctx = storage->getASTContext(); SourceLoc loc = storage->getLoc(); // Create the parameter list: - SmallVector params; + SmallVector params; // - The implicit 'self' argument if in a type context. auto DC = storage->getDeclContext(); if (DC->isTypeContext()) - params.push_back(buildImplicitSelfParameter(loc, DC)); + params.push_back(ParameterList::createSelf(loc, DC, /*isStatic*/false)); // - The buffer parameter, (buffer: Builtin.RawPointer, // inout storage: Builtin.UnsafeValueBuffer, // indices...). - TuplePatternElt bufferElements[] = { - buildLetArgumentPattern(loc, DC, "buffer", ctx.TheRawPointerType, - &bufferParamDecl, TC.Context), - buildInOutArgumentPattern(loc, DC, "callbackStorage", - ctx.TheUnsafeValueBufferType, - nullptr, TC.Context), + ParamDecl *bufferElements[] = { + buildLetArgument(loc, DC, "buffer", ctx.TheRawPointerType), + buildInOutArgument(loc, DC, "callbackStorage", ctx.TheUnsafeValueBufferType) }; - params.push_back(buildIndexForwardingPattern(storage, bufferElements, TC)); + params.push_back(buildIndexForwardingParamList(storage, bufferElements)); // The accessor returns (Builtin.RawPointer, (@convention(thin) (...) -> ())?), // where the first pointer is the materialized address and the @@ -384,7 +327,16 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage, // materializeForSet is mutating and static if the setter is. auto setter = storage->getSetter(); - materializeForSet->setMutating(setter->isMutating()); + + // Open-code the setMutating() calculation since we might run before + // the setter has been type checked. Also as a hack, always mark the + // setter mutating if we're inside a protocol, because it seems some + // things break otherwise -- the root cause should be fixed eventually. + materializeForSet->setMutating( + setter->getDeclContext()->isProtocolOrProtocolExtensionContext() || + (!setter->getAttrs().hasAttribute() && + !storage->isSetterNonMutating())); + materializeForSet->setStatic(setter->isStatic()); // materializeForSet is final if the storage is. @@ -415,7 +367,7 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage, // If the property came from ObjC, we need to register this as an external // definition to be compiled. if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(materializeForSet); + TC.Context.addExternalDecl(materializeForSet); return materializeForSet; } @@ -435,58 +387,52 @@ void swift::convertStoredVarInProtocolToComputed(VarDecl *VD, TypeChecker &TC) { TC.typeCheckDecl(VD->getGetter(), false); } -/// Build a tuple around the given arguments. -static Expr *buildTupleExpr(ASTContext &ctx, ArrayRef args) { - if (args.size() == 1) { - return args[0]; - } - SmallVector labels(args.size()); - SmallVector labelLocs(args.size()); - return TupleExpr::create(ctx, SourceLoc(), args, labels, labelLocs, - SourceLoc(), false, IsImplicit); -} - - -static Expr *buildTupleForwardingRefExpr(ASTContext &ctx, - ArrayRef params, - ArrayRef formalIndexTypes) { - assert(params.size() == formalIndexTypes.size()); +/// Build an expression that evaluates the specified parameter list as a tuple +/// or paren expr, suitable for use in an applyexpr. +/// +/// NOTE: This returns null if a varargs parameter exists in the list, as it +/// cannot be forwarded correctly yet. +/// +static Expr *buildArgumentForwardingExpr(ArrayRef params, + ASTContext &ctx) { SmallVector labels; SmallVector labelLocs; SmallVector args; - - for (unsigned i = 0, e = params.size(); i != e; ++i) { - const Pattern *param = params[i].getPattern(); - args.push_back(param->buildForwardingRefExpr(ctx)); - labels.push_back(formalIndexTypes[i].getName()); + + for (auto param : params) { + // We cannot express how to forward variadic parameters yet. + if (param->isVariadic()) + return nullptr; + + Expr *ref = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true); + if (param->getType()->is()) + ref = new (ctx) InOutExpr(SourceLoc(), ref, Type(), /*implicit=*/true); + args.push_back(ref); + + labels.push_back(param->getArgumentName()); labelLocs.push_back(SourceLoc()); } - + // A single unlabelled value is not a tuple. if (args.size() == 1 && labels[0].empty()) return args[0]; - + return TupleExpr::create(ctx, SourceLoc(), args, labels, labelLocs, SourceLoc(), false, IsImplicit); } -/// Build a reference to the subscript index variables for this -/// subscript accessor. + + + + +/// Build a reference to the subscript index variables for this subscript +/// accessor. static Expr *buildSubscriptIndexReference(ASTContext &ctx, FuncDecl *accessor) { // Pull out the body parameters, which we should have cloned // previously to be forwardable. Drop the initial buffer/value // parameter in accessors that have one. - TuplePatternElt singleParam; - Pattern *paramPattern = accessor->getBodyParamPatterns().back(); - ArrayRef params; - if (auto paramTuple = dyn_cast(paramPattern)) { - params = paramTuple->getElements(); - } else { - singleParam = TuplePatternElt( - cast(paramPattern)->getSubPattern()); - params = singleParam; - } + auto params = accessor->getParameterLists().back()->getArray(); auto accessorKind = accessor->getAccessorKind(); // Ignore the value/buffer parameter. @@ -496,15 +442,11 @@ static Expr *buildSubscriptIndexReference(ASTContext &ctx, FuncDecl *accessor) { // Ignore the materializeForSet callback storage parameter. if (accessorKind == AccessorKind::IsMaterializeForSet) params = params.slice(1); - - // Look for formal subscript labels. - auto subscript = cast(accessor->getAccessorStorageDecl()); - auto indexType = subscript->getIndicesType(); - if (auto indexTuple = indexType->getAs()) { - return buildTupleForwardingRefExpr(ctx, params, indexTuple->getElements()); - } else { - return buildTupleForwardingRefExpr(ctx, params, TupleTypeElt(indexType)); - } + + // Okay, everything else should be forwarded, build the expression. + auto result = buildArgumentForwardingExpr(params, ctx); + assert(result && "FIXME: Cannot forward varargs"); + return result; } enum class SelfAccessKind { @@ -523,7 +465,7 @@ static Expr *buildSelfReference(VarDecl *selfDecl, TypeChecker &TC) { switch (selfAccessKind) { case SelfAccessKind::Peer: - return new (TC.Context) DeclRefExpr(selfDecl, SourceLoc(), IsImplicit); + return new (TC.Context) DeclRefExpr(selfDecl, DeclNameLoc(), IsImplicit); case SelfAccessKind::Super: return new (TC.Context) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit); @@ -577,7 +519,7 @@ static Expr *buildStorageReference( VarDecl *selfDecl = referenceContext.getSelfDecl(); if (!selfDecl) { - return new (ctx) DeclRefExpr(storage, SourceLoc(), IsImplicit, semantics); + return new (ctx) DeclRefExpr(storage, DeclNameLoc(), IsImplicit, semantics); } // If we should use a super access if applicable, and we have an @@ -603,7 +545,7 @@ static Expr *buildStorageReference( // however, it shouldn't be problematic because any overrides // should also redefine materializeForSet. return new (ctx) MemberRefExpr(selfDRE, SourceLoc(), storage, - SourceLoc(), IsImplicit, semantics); + DeclNameLoc(), IsImplicit, semantics); } static Expr *buildStorageReference(FuncDecl *accessor, @@ -636,7 +578,7 @@ static ProtocolDecl *getNSCopyingProtocol(TypeChecker &TC, SmallVector results; DC->lookupQualified(ModuleType::get(foundation), - ctx.getIdentifier("NSCopying"), + ctx.getSwiftId(KnownFoundationEntity::NSCopying), NL_QualifiedDefault | NL_KnownNonCascadingDependency, /*resolver=*/nullptr, results); @@ -690,7 +632,7 @@ static Expr *synthesizeCopyWithZoneCall(Expr *Val, VarDecl *VD, // (nil_literal_expr type='')))) auto UDE = new (Ctx) UnresolvedDotExpr(Val, SourceLoc(), Ctx.getIdentifier("copyWithZone"), - SourceLoc(), /*implicit*/true); + DeclNameLoc(), /*implicit*/true); Expr *Nil = new (Ctx) NilLiteralExpr(SourceLoc(), /*implicit*/true); Nil = new (Ctx) ParenExpr(SourceLoc(), Nil, SourceLoc(), false); @@ -752,19 +694,21 @@ static void createPropertyStoreOrCallSuperclassSetter(FuncDecl *accessor, /// accessor as transparent, since in this case we just want it for abstraction /// purposes (i.e., to make access to the variable uniform and to be able to /// put the getter in a vtable). +/// +/// If the storage is for a global stored property or a stored property of a +/// resilient type, we are synthesizing accessors to present a resilient +/// interface to the storage and they should not be transparent. static void maybeMarkTransparent(FuncDecl *accessor, AbstractStorageDecl *storage, TypeChecker &TC) { - auto *NTD = storage->getDeclContext() + auto *nominal = storage->getDeclContext() ->isNominalTypeOrNominalTypeExtensionContext(); - - // FIXME: resilient global variables - if (!NTD || NTD->hasFixedLayout()) + if (nominal && nominal->hasFixedLayout()) accessor->getAttrs().add(new (TC.Context) TransparentAttr(IsImplicit)); } /// Synthesize the body of a trivial getter. For a non-member vardecl or one -/// which is not an override of a base class property, it performs a a direct +/// which is not an override of a base class property, it performs a direct /// storage load. For an override of a base member property, it chains up to /// super. static void synthesizeTrivialGetter(FuncDecl *getter, @@ -782,7 +726,7 @@ static void synthesizeTrivialGetter(FuncDecl *getter, // Register the accessor as an external decl if the storage was imported. if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(getter); + TC.Context.addExternalDecl(getter); } /// Synthesize the body of a trivial setter. @@ -795,7 +739,7 @@ static void synthesizeTrivialSetter(FuncDecl *setter, auto &ctx = TC.Context; SourceLoc loc = storage->getLoc(); - auto *valueDRE = new (ctx) DeclRefExpr(valueVar, SourceLoc(), IsImplicit); + auto *valueDRE = new (ctx) DeclRefExpr(valueVar, DeclNameLoc(), IsImplicit); SmallVector setterBody; createPropertyStoreOrCallSuperclassSetter(setter, valueDRE, storage, setterBody, TC); @@ -805,62 +749,7 @@ static void synthesizeTrivialSetter(FuncDecl *setter, // Register the accessor as an external decl if the storage was imported. if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(setter); -} - -/// Build the result expression of a materializeForSet accessor. -/// -/// \param address an expression yielding the address to return -/// \param callbackFn an optional closure expression for the callback -static Expr *buildMaterializeForSetResult(ASTContext &ctx, Expr *address, - Expr *callbackFn) { - if (!callbackFn) { - callbackFn = new (ctx) NilLiteralExpr(SourceLoc(), IsImplicit); - } - - return TupleExpr::create(ctx, SourceLoc(), { address, callbackFn }, - { Identifier(), Identifier() }, - { SourceLoc(), SourceLoc() }, - SourceLoc(), false, IsImplicit); -} - -/// Create a call to the builtin function with the given name. -static Expr *buildCallToBuiltin(ASTContext &ctx, StringRef builtinName, - ArrayRef args) { - auto builtin = getBuiltinValueDecl(ctx, ctx.getIdentifier(builtinName)); - Expr *builtinDRE = new (ctx) DeclRefExpr(builtin, SourceLoc(), IsImplicit); - Expr *arg = buildTupleExpr(ctx, args); - return new (ctx) CallExpr(builtinDRE, arg, IsImplicit); -} - -/// Synthesize the body of a materializeForSet accessor for a stored -/// property. -static void synthesizeStoredMaterializeForSet(FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - VarDecl *bufferDecl, - TypeChecker &TC) { - ASTContext &ctx = TC.Context; - - // return (Builtin.addressof(&self.property), nil) - Expr *result = buildStorageReference(materializeForSet, storage, - AccessSemantics::DirectToStorage, - SelfAccessKind::Peer, TC); - result = new (ctx) InOutExpr(SourceLoc(), result, Type(), IsImplicit); - result = buildCallToBuiltin(ctx, "addressof", result); - result = buildMaterializeForSetResult(ctx, result, /*callback*/ nullptr); - - ASTNode returnStmt = new (ctx) ReturnStmt(SourceLoc(), result, IsImplicit); - - SourceLoc loc = storage->getLoc(); - materializeForSet->setBody(BraceStmt::create(ctx, loc, returnStmt, loc,true)); - - maybeMarkTransparent(materializeForSet, storage, TC); - - TC.typeCheckDecl(materializeForSet, true); - - // Register the accessor as an external decl if the storage was imported. - if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(materializeForSet); + TC.Context.addExternalDecl(setter); } /// Does a storage decl currently lacking accessor functions require a @@ -894,9 +783,7 @@ static bool doesStorageNeedSetter(AbstractStorageDecl *storage) { /// Add a materializeForSet accessor to the given declaration. static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage, TypeChecker &TC) { - VarDecl *bufferDecl; - auto materializeForSet = - createMaterializeForSetPrototype(storage, bufferDecl, TC); + auto materializeForSet = createMaterializeForSetPrototype(storage, TC); addMemberToContextIfNeeded(materializeForSet, storage->getDeclContext(), storage->getSetter()); storage->setMaterializeForSetFunc(materializeForSet); @@ -918,7 +805,7 @@ void swift::addTrivialAccessorsToStorage(AbstractStorageDecl *storage, // Create the setter. FuncDecl *setter = nullptr; - VarDecl *setterValueParam = nullptr; + ParamDecl *setterValueParam = nullptr; if (doesStorageNeedSetter(storage)) { setter = createSetterPrototype(storage, setterValueParam, TC); } @@ -945,20 +832,23 @@ void swift::addTrivialAccessorsToStorage(AbstractStorageDecl *storage, TC.typeCheckDecl(setter, false); } - // We've added some members to our containing type, add them to the - // members list. - addMemberToContextIfNeeded(getter, storage->getDeclContext()); + auto *DC = storage->getDeclContext(); + + // We've added some members to our containing context, add them to + // the right list. + addMemberToContextIfNeeded(getter, DC); if (setter) - addMemberToContextIfNeeded(setter, storage->getDeclContext()); + addMemberToContextIfNeeded(setter, DC); - // Always add a materializeForSet when we're creating trivial - // accessors for a mutable stored property. We only do this when we - // need to be able to access something polymorphically, and we always - // want a materializeForSet in such situations. - if (setter) { + // If we're creating trivial accessors for a stored property of a + // nominal type, the stored property is either witnessing a + // protocol requirement or the nominal type is resilient. In both + // cases, we need to expose a materializeForSet. + // + // Global stored properties don't get a materializeForSet. + if (setter && DC->isNominalTypeOrNominalTypeExtensionContext()) { FuncDecl *materializeForSet = addMaterializeForSet(storage, TC); synthesizeMaterializeForSet(materializeForSet, storage, TC); - TC.typeCheckDecl(materializeForSet, true); TC.typeCheckDecl(materializeForSet, false); } } @@ -1003,457 +893,23 @@ void TypeChecker::synthesizeWitnessAccessorsForStorage( requirement->getSetter() && !storage->getMaterializeForSetFunc()) { FuncDecl *materializeForSet = addMaterializeForSet(storage, *this); synthesizeMaterializeForSet(materializeForSet, storage, *this); - typeCheckDecl(materializeForSet, true); typeCheckDecl(materializeForSet, false); } return; } -using CallbackGenerator = - llvm::function_ref &callbackBody, - VarDecl *selfDecl, VarDecl *bufferDecl, - VarDecl *callbackStorageDecl)>; - -/// Build a materializeForSet callback function. -/// It should have type -/// (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer, -/// inout T, T.Type) -> () -static Expr *buildMaterializeForSetCallback(ASTContext &ctx, - FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - const CallbackGenerator &generator) { - - auto DC = storage->getDeclContext(); - SourceLoc loc = storage->getLoc(); - - Type selfType = - getSelfTypeForMaterializeForSetCallback(ctx, DC, - materializeForSet->isStatic()); - - // Build the parameters pattern. - // - // Unexpected subtlety: it actually important to call the inout self - // parameter something other than 'self' so that we don't trigger - // the "implicit use of self" diagnostic. - VarDecl *bufferDecl; - VarDecl *callbackStorageDecl; - VarDecl *selfDecl; - TuplePatternElt argPatterns[] = { - buildLetArgumentPattern(loc, DC, "buffer", ctx.TheRawPointerType, - &bufferDecl, ctx), - buildInOutArgumentPattern(loc, DC, "callbackStorage", - ctx.TheUnsafeValueBufferType, - &callbackStorageDecl, ctx), - buildInOutArgumentPattern(loc, DC, "selfValue", selfType, &selfDecl, ctx), - buildLetArgumentPattern(loc, DC, "selfType", MetatypeType::get(selfType), - nullptr, ctx), - }; - auto args = TuplePattern::createSimple(ctx, SourceLoc(), argPatterns, - SourceLoc()); - args->setImplicit(); - - // Create the closure expression itself. - auto closure = new (ctx) ClosureExpr(args, SourceLoc(), SourceLoc(), - SourceLoc(), TypeLoc(), - /*discriminator*/ 0, materializeForSet); - - // Generate the body of the closure. - SmallVector body; - generator(body, selfDecl, bufferDecl, callbackStorageDecl); - closure->setBody(BraceStmt::create(ctx, SourceLoc(), body, SourceLoc(), - IsImplicit), - /*isSingleExpression*/ false); - closure->setImplicit(IsImplicit); - - // Call our special builtin to turn that into an opaque thin function. - auto result = buildCallToBuiltin(ctx, "makeMaterializeForSetCallback", - { closure }); - return result; -} - -/// Build a builtin operation on a Builtin.UnsafeValueBuffer. -static Expr *buildValueBufferOperation(ASTContext &ctx, StringRef builtinName, - VarDecl *bufferDecl, Type valueType) { - // &buffer - Expr *bufferRef = new (ctx) DeclRefExpr(bufferDecl, SourceLoc(), IsImplicit); - bufferRef = new (ctx) InOutExpr(SourceLoc(), bufferRef, Type(), IsImplicit); - - // T.self - Expr *metatypeRef = TypeExpr::createImplicit(valueType, ctx); - metatypeRef = new (ctx) DotSelfExpr(metatypeRef, SourceLoc(), SourceLoc()); - metatypeRef->setImplicit(IsImplicit); - - // Builtin.whatever(&buffer, T.self) - return buildCallToBuiltin(ctx, builtinName, { bufferRef, metatypeRef }); -} - -/// Build a call to Builtin.take. -static Expr *buildBuiltinTake(ASTContext &ctx, Expr *address, - Type valueType) { - // Builtin.take(address) as ValueType - Expr *result = buildCallToBuiltin(ctx, "take", { address }); - result = new (ctx) CoerceExpr(result, SourceLoc(), - TypeLoc::withoutLoc(valueType)); - result->setImplicit(IsImplicit); - return result; -} - -/// Build an expression to initialize callback storage. -static ASTNode buildInitializeCallbackStorage(FuncDecl *materializeForSet, - Expr *initializer, - Type initializerType, - ASTContext &ctx) { - // let allocatedCallbackStorage = - // Builtin.allocateValueBuffer(&callbackStorage, IndexType.self)) - VarDecl *callbackStorageDecl = getParamDeclAtIndex(materializeForSet, 1); - Expr *allocatedCallbackStorage = - buildValueBufferOperation(ctx, "allocValueBuffer", callbackStorageDecl, - initializerType); - - // Builtin.initialize(indexArgs, allocatedCallbackStorage) - return buildCallToBuiltin(ctx, "initialize", - { initializer, allocatedCallbackStorage }); -} - -/// Build an expression to take from callback storage. -static Expr *buildTakeFromCallbackStorage(VarDecl *storage, Type valueType, - ASTContext &ctx) { - Expr *address = - buildValueBufferOperation(ctx, "projectValueBuffer", storage, valueType); - return buildBuiltinTake(ctx, address, valueType); -} - -namespace { - /// A reference to storage from the context of a materializeForSet - /// callback. - class CallbackStorageReferenceContext : public StorageReferenceContext { - VarDecl *Self; - VarDecl *CallbackStorage; - public: - CallbackStorageReferenceContext(VarDecl *self, VarDecl *callbackStorage) - : Self(self), CallbackStorage(callbackStorage) {} - virtual ~CallbackStorageReferenceContext() = default; - - VarDecl *getSelfDecl() const override { - return Self; - } - Expr *getIndexRefExpr(ASTContext &ctx, - SubscriptDecl *subscript) const override { - return buildTakeFromCallbackStorage(CallbackStorage, - subscript->getIndicesType(), ctx); - } - }; -} - -/// Synthesize the body of a materializeForSet accessor for a -/// computed property. -static void synthesizeComputedMaterializeForSet(FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - VarDecl *bufferDecl, - TypeChecker &TC) { - ASTContext &ctx = TC.Context; - - SmallVector body; - - AccessSemantics semantics; - // If the storage is dynamic, we must dynamically redispatch through the - // accessor. Otherwise, we can do a direct peer access. - if (needsDynamicMaterializeForSet(storage)) - semantics = AccessSemantics::Ordinary; - else - semantics = AccessSemantics::DirectToAccessor; - - // Builtin.initialize(self.property, buffer) - Expr *curValue = buildStorageReference(materializeForSet, storage, - semantics, - SelfAccessKind::Peer, TC); - Expr *bufferRef = new (ctx) DeclRefExpr(bufferDecl, SourceLoc(), IsImplicit); - body.push_back(buildCallToBuiltin(ctx, "initialize", - { curValue, bufferRef })); - - // If this is a subscript, preserve the index value: - if (auto subscript = dyn_cast(storage)) { - Expr *indices = buildSubscriptIndexReference(ctx, materializeForSet); - ASTNode initialize = - buildInitializeCallbackStorage(materializeForSet, indices, - subscript->getIndicesType(), ctx); - body.push_back(initialize); - } - - // Build the callback. - Expr *callback = - buildMaterializeForSetCallback(ctx, materializeForSet, storage, - [&](SmallVectorImpl &body, - VarDecl *selfDecl, VarDecl *bufferDecl, - VarDecl *callbackStorageDecl) { - // self.property = Builtin.take(buffer) - Expr *bufferRef = - new (ctx) DeclRefExpr(bufferDecl, SourceLoc(), IsImplicit); - Expr *value = buildBuiltinTake(ctx, bufferRef, - getTypeOfStorage(storage, TC)); - - Expr *storageRef = - buildStorageReference( - CallbackStorageReferenceContext{selfDecl, callbackStorageDecl}, - storage, semantics, - SelfAccessKind::Peer, TC); - body.push_back(new (ctx) AssignExpr(storageRef, SourceLoc(), - value, IsImplicit)); - - // If this is a subscript, deallocate the subscript buffer: - if (auto subscript = dyn_cast(storage)) { - // Builtin.deallocValueBuffer(&callbackStorage, IndexType.self) - body.push_back(buildValueBufferOperation(ctx, "deallocValueBuffer", - callbackStorageDecl, - subscript->getIndicesType())); - } - }); - - // return (buffer, callback) - Expr *result = new (ctx) DeclRefExpr(bufferDecl, SourceLoc(), IsImplicit); - - result = buildMaterializeForSetResult(ctx, result, callback); - body.push_back(new (ctx) ReturnStmt(SourceLoc(), result, IsImplicit)); - - SourceLoc loc = storage->getLoc(); - materializeForSet->setBody(BraceStmt::create(ctx, loc, body, loc, true)); - - // Mark it transparent, there is no user benefit to this actually existing. - materializeForSet->getAttrs().add(new (ctx) TransparentAttr(IsImplicit)); - - TC.typeCheckDecl(materializeForSet, true); - - // Register the accessor as an external decl if the storage was imported. - if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(materializeForSet); -} - -/// Build a direct call to an addressor from within a -/// materializeForSet method. -static Expr *buildCallToAddressor(FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - VarDecl *bufferDecl, - FuncDecl *addressor, - ASTContext &ctx) { - // Build a direct reference to the addressor. - Expr *fn; - - // Apply the self argument if applicable. - if (auto self = materializeForSet->getImplicitSelfDecl()) { - Expr *selfRef = new (ctx) DeclRefExpr(self, SourceLoc(), IsImplicit); - // if (addressor->computeSelfType(nullptr)->is()) { - // selfRef = new (ctx) InOutExpr(SourceLoc(), selfRef, Type(), IsImplicit); - // } - - ValueDecl *localMembers[] = { addressor }; - fn = new (ctx) OverloadedMemberRefExpr(selfRef, SourceLoc(), - ctx.AllocateCopy(localMembers), - SourceLoc(), IsImplicit, Type(), - AccessSemantics::DirectToStorage); - } else { - fn = new (ctx) DeclRefExpr(addressor, SourceLoc(), IsImplicit, - AccessSemantics::DirectToStorage); - } - - // Apply the rest of the addressor arguments. - Expr *args; - if (isa(storage)) { - args = buildSubscriptIndexReference(ctx, materializeForSet); - } else { - args = TupleExpr::createImplicit(ctx, {}, {}); - } - - return new (ctx) CallExpr(fn, args, IsImplicit); -} - -/// Given an expression of type UnsafeMutablePointer, create an -/// expression of type Builtin.RawPointer. -static Expr *buildUnsafeMutablePointerToRawPointer(Expr *operand, - ASTContext &ctx) { - // Just directly drill in. - NominalTypeDecl *ptrType = ctx.getUnsafeMutablePointerDecl(); - - // If that doesn't work, just bail out; the result probably won't - // type-check, but there are worse failure modes for a broken stdlib. - if (!ptrType) return operand; - auto props = ptrType->getStoredProperties(); - if (props.begin() == props.end()) return operand; - - auto storageProp = props.front(); - return new (ctx) MemberRefExpr(operand, SourceLoc(), storageProp, - SourceRange(), IsImplicit); -} - -/// Synthesize the body of a materializeForSet accessor for an -/// addressed property. -static void synthesizeAddressedMaterializeForSet(FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - VarDecl *bufferDecl, - TypeChecker &TC) { - ASTContext &ctx = TC.Context; - - SmallVector body; - - // Call the mutable addressor. - auto addressor = storage->getMutableAddressor(); - Expr *addressorResult = buildCallToAddressor(materializeForSet, storage, - bufferDecl, addressor, ctx); - - Expr *result; - Expr *callback; - switch (addressor->getAddressorKind()) { - case AddressorKind::NotAddressor: - llvm_unreachable("addressor is not an addressor?"); - - // If we have an unsafe addressor, this is easy: we just pull out - // the raw pointer and use that as the result. - case AddressorKind::Unsafe: - result = buildUnsafeMutablePointerToRawPointer(addressorResult, ctx); - callback = nullptr; - break; - - case AddressorKind::Owning: - case AddressorKind::NativeOwning: - case AddressorKind::NativePinning: { - // We need to bind the result to a temporary variable. - // let temporary = addressor(self)(indices) - auto tempDecl = new (ctx) VarDecl(/*static*/ false, /*let*/ true, - SourceLoc(), ctx.getIdentifier("tmp"), - Type(), materializeForSet); - tempDecl->setImplicit(IsImplicit); - auto bindingPattern = new (ctx) NamedPattern(tempDecl, IsImplicit); - auto bindingDecl = PatternBindingDecl::create(ctx, /*static*/ SourceLoc(), - StaticSpellingKind::None, - SourceLoc(), bindingPattern, - addressorResult, - materializeForSet); - bindingDecl->setImplicit(IsImplicit); - body.push_back(bindingDecl); - body.push_back(tempDecl); - - // This should be Builtin.NativePointer or something like it. - Type ownerType = [&]() -> Type { - switch (addressor->getAddressorKind()){ - case AddressorKind::NotAddressor: - case AddressorKind::Unsafe: - llvm_unreachable("filtered out"); - case AddressorKind::Owning: - return ctx.TheUnknownObjectType; - case AddressorKind::NativeOwning: - return ctx.TheNativeObjectType; - case AddressorKind::NativePinning: - return OptionalType::get(ctx.TheNativeObjectType); - } - llvm_unreachable("bad addressor kind"); - }(); - - // Initialize the callback storage with the owner value, which is - // the second element of the addressor result. - Expr *owner = new (ctx) DeclRefExpr(tempDecl, SourceLoc(), IsImplicit); - owner = new (ctx) TupleElementExpr(owner, SourceLoc(), /*field index*/ 1, - SourceLoc(), Type()); - owner->setImplicit(IsImplicit); - body.push_back(buildInitializeCallbackStorage(materializeForSet, owner, - ownerType, ctx)); - - // The result is the first element of the addressor result. - result = new (ctx) DeclRefExpr(tempDecl, SourceLoc(), IsImplicit); - result = new (ctx) TupleElementExpr(result, SourceLoc(), /*field index*/ 0, - SourceLoc(), Type()); - result->setImplicit(IsImplicit); - result = buildUnsafeMutablePointerToRawPointer(result, ctx); - - // Build the callback. - callback = buildMaterializeForSetCallback(ctx, materializeForSet, storage, - [&](SmallVectorImpl &body, VarDecl *selfDecl, - VarDecl *bufferDecl, VarDecl *callbackStorageDecl) { - // Pull the owner out of callback storage. - Expr *owner = - buildTakeFromCallbackStorage(callbackStorageDecl, ownerType, ctx); - - // For an owning addressor, we can just drop the value we pulled out. - if (addressor->getAddressorKind() != AddressorKind::NativePinning) { - body.push_back(owner); - - // For a pinning addressor, we have to unpin it. - } else { - Expr *unpin = buildCallToBuiltin(ctx, "unpin", { owner }); - body.push_back(unpin); - } - - // This should always be a no-op, but do it for the sake of formalism. - // Builtin.deallocValueBuffer(&callbackStorage, OwnerType.self) - body.push_back(buildValueBufferOperation(ctx, "deallocValueBuffer", - callbackStorageDecl, - ownerType)); - }); - break; - } - } - - // return (buffer, callback) - result = buildMaterializeForSetResult(ctx, result, callback); - body.push_back(new (ctx) ReturnStmt(SourceLoc(), result, IsImplicit)); - - SourceLoc loc = storage->getLoc(); - materializeForSet->setBody(BraceStmt::create(ctx, loc, body, loc)); +void swift::synthesizeMaterializeForSet(FuncDecl *materializeForSet, + AbstractStorageDecl *storage, + TypeChecker &TC) { + // The body is actually emitted by SILGen - // Mark it transparent, there is no user benefit to this actually existing. - materializeForSet->getAttrs().add(new (ctx) TransparentAttr(IsImplicit)); + maybeMarkTransparent(materializeForSet, storage, TC); TC.typeCheckDecl(materializeForSet, true); // Register the accessor as an external decl if the storage was imported. if (needsToBeRegisteredAsExternalDecl(storage)) - TC.Context.addedExternalDecl(materializeForSet); -} - -void swift::synthesizeMaterializeForSet(FuncDecl *materializeForSet, - AbstractStorageDecl *storage, - TypeChecker &TC) { - VarDecl *bufferDecl = getFirstParamDecl(materializeForSet); - - switch (storage->getStorageKind()) { - case AbstractStorageDecl::Stored: - case AbstractStorageDecl::Addressed: - llvm_unreachable("no accessors"); - - // We can use direct access to stored variables, but not if they're - // weak, unowned, or dynamic. - case AbstractStorageDecl::StoredWithTrivialAccessors: { - // Only variables can be Stored, and only variables can be weak/unowned. - auto var = cast(storage); - if (var->getType()->is() - || needsDynamicMaterializeForSet(var)) { - synthesizeComputedMaterializeForSet(materializeForSet, storage, - bufferDecl, TC); - return; - } - - synthesizeStoredMaterializeForSet(materializeForSet, storage, - bufferDecl, TC); - return; - } - - // We should access these by calling mutableAddress. - case AbstractStorageDecl::AddressedWithTrivialAccessors: - case AbstractStorageDecl::ComputedWithMutableAddress: - synthesizeAddressedMaterializeForSet(materializeForSet, storage, - bufferDecl, TC); - return; - - // These must be accessed with a getter/setter pair. - // TODO: StoredWithObservers and AddressedWithObservers could be - // made to work with the callback as long as there isn't a willSet. - case AbstractStorageDecl::StoredWithObservers: - case AbstractStorageDecl::InheritedWithObservers: - case AbstractStorageDecl::AddressedWithObservers: - case AbstractStorageDecl::Computed: - synthesizeComputedMaterializeForSet(materializeForSet, storage, - bufferDecl, TC); - return; - } - llvm_unreachable("bad abstract storage kind"); + TC.Context.addExternalDecl(materializeForSet); } /// Given a VarDecl with a willSet: and/or didSet: specifier, synthesize the @@ -1476,11 +932,7 @@ void swift::synthesizeObservingAccessors(VarDecl *VD, TypeChecker &TC) { // decls for 'self' and 'value'. auto *Set = VD->getSetter(); auto *SelfDecl = Set->getImplicitSelfDecl(); - VarDecl *ValueDecl = nullptr; - Set->getBodyParamPatterns().back()->forEachVariable([&](VarDecl *VD) { - assert(!ValueDecl && "Already found 'value'?"); - ValueDecl = VD; - }); + VarDecl *ValueDecl = Set->getParameterLists().back()->get(0); // The setter loads the oldValue, invokes willSet with the incoming value, // does a direct store, then invokes didSet with the oldValue. @@ -1516,10 +968,12 @@ void swift::synthesizeObservingAccessors(VarDecl *VD, TypeChecker &TC) { // or: // (call_expr (decl_ref_expr(willSet)), (declrefexpr(value))) if (auto willSet = VD->getWillSetFunc()) { - Expr *Callee = new (Ctx) DeclRefExpr(willSet, SourceLoc(), /*imp*/true); - auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, SourceLoc(), /*imp*/true); + Expr *Callee = new (Ctx) DeclRefExpr(willSet, DeclNameLoc(), /*imp*/true); + auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, DeclNameLoc(), + /*imp*/true); if (SelfDecl) { - auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, SourceLoc(), /*imp*/true); + auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, DeclNameLoc(), + /*imp*/true); Callee = new (Ctx) DotSyntaxCallExpr(Callee, SourceLoc(), SelfDRE); } SetterBody.push_back(new (Ctx) CallExpr(Callee, ValueDRE, true)); @@ -1531,7 +985,7 @@ void swift::synthesizeObservingAccessors(VarDecl *VD, TypeChecker &TC) { } // Create an assignment into the storage or call to superclass setter. - auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, SourceLoc(), true); + auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, DeclNameLoc(), true); createPropertyStoreOrCallSuperclassSetter(Set, ValueDRE, VD, SetterBody, TC); // Create: @@ -1541,11 +995,12 @@ void swift::synthesizeObservingAccessors(VarDecl *VD, TypeChecker &TC) { // or: // (call_expr (decl_ref_expr(didSet)), (decl_ref_expr(tmp))) if (auto didSet = VD->getDidSetFunc()) { - auto *OldValueExpr = new (Ctx) DeclRefExpr(OldValue, SourceLoc(), + auto *OldValueExpr = new (Ctx) DeclRefExpr(OldValue, DeclNameLoc(), /*impl*/true); - Expr *Callee = new (Ctx) DeclRefExpr(didSet, SourceLoc(), /*imp*/true); + Expr *Callee = new (Ctx) DeclRefExpr(didSet, DeclNameLoc(), /*imp*/true); if (SelfDecl) { - auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, SourceLoc(), /*imp*/true); + auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, DeclNameLoc(), + /*imp*/true); Callee = new (Ctx) DotSyntaxCallExpr(Callee, SourceLoc(), SelfDRE); } SetterBody.push_back(new (Ctx) CallExpr(Callee, OldValueExpr, true)); @@ -1572,7 +1027,7 @@ static void convertNSManagedStoredVarToComputed(VarDecl *VD, TypeChecker &TC) { auto *Get = createGetterPrototype(VD, TC); // Create the setter. - VarDecl *SetValueDecl = nullptr; + ParamDecl *SetValueDecl = nullptr; auto *Set = createSetterPrototype(VD, SetValueDecl, TC); // Okay, we have both the getter and setter. Set them in VD. @@ -1619,7 +1074,7 @@ namespace { }; } -/// Synthesize the getter for an lazy property with the specified storage +/// Synthesize the getter for a lazy property with the specified storage /// vardecl. static FuncDecl *completeLazyPropertyGetter(VarDecl *VD, VarDecl *Storage, TypeChecker &TC) { @@ -1656,14 +1111,14 @@ static FuncDecl *completeLazyPropertyGetter(VarDecl *VD, VarDecl *Storage, Body.push_back(Tmp1VD); // Build the early return inside the if. - auto *Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, SourceLoc(), /*Implicit*/true, + auto *Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, DeclNameLoc(), /*Implicit*/true, AccessSemantics::DirectToStorage); auto *EarlyReturnVal = new (Ctx) ForceValueExpr(Tmp1DRE, SourceLoc()); auto *Return = new (Ctx) ReturnStmt(SourceLoc(), EarlyReturnVal, /*implicit*/true); // Build the "if" around the early return. - Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, SourceLoc(), /*Implicit*/true, + Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, DeclNameLoc(), /*Implicit*/true, AccessSemantics::DirectToStorage); // Call through "hasValue" on the decl ref. @@ -1712,12 +1167,12 @@ static FuncDecl *completeLazyPropertyGetter(VarDecl *VD, VarDecl *Storage, Body.push_back(Tmp2VD); // Assign tmp2 into storage. - auto Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, SourceLoc(), /*Implicit*/true, + auto Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, DeclNameLoc(), /*Implicit*/true, AccessSemantics::DirectToStorage); createPropertyStoreOrCallSuperclassSetter(Get, Tmp2DRE, Storage, Body, TC); // Return tmp2. - Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, SourceLoc(), /*Implicit*/true, + Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, DeclNameLoc(), /*Implicit*/true, AccessSemantics::DirectToStorage); Body.push_back(new (Ctx) ReturnStmt(SourceLoc(), Tmp2DRE, /*implicit*/true)); @@ -1808,12 +1263,9 @@ void swift::maybeAddMaterializeForSet(AbstractStorageDecl *storage, if (storage->isInvalid()) return; // We only need materializeForSet in polymorphic contexts: - auto containerTy = - storage->getDeclContext()->getDeclaredTypeOfContext(); - if (!containerTy) return; - - NominalTypeDecl *container = containerTy->getAnyNominal(); - assert(container && "extension of non-nominal type?"); + NominalTypeDecl *container = storage->getDeclContext() + ->isNominalTypeOrNominalTypeExtensionContext(); + if (!container) return; // - in non-ObjC protocols, but not protocol extensions. if (auto protocol = dyn_cast(container)) { @@ -1829,20 +1281,34 @@ void swift::maybeAddMaterializeForSet(AbstractStorageDecl *storage, return; } - // Structs and enums don't need this. - } else { - assert(isa(container) || isa(container)); + // Enums don't need this. + } else if (isa(container)) { return; + + // Structs imported by Clang don't need this, because we can + // synthesize it later. + } else { + assert(isa(container)); + if (container->hasClangNode()) + return; } addMaterializeForSet(storage, TC); } void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) { - if (var->getGetter() || var->isBeingTypeChecked() || isa(var)) + // If we've already synthesized accessors or are currently in the process + // of doing so, don't proceed. + if (var->getGetter() || var->isBeingTypeChecked()) + return; + + // Local variables don't get accessors. + if (var->getDeclContext()->isLocalContext()) return; - // Lazy properties get accessors. + assert(!var->hasAccessorFunctions()); + + // Lazy properties require special handling. if (var->getAttrs().hasAttribute()) { var->setIsBeingTypeChecked(); @@ -1852,7 +1318,7 @@ void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) { getter->setMutating(); getter->setAccessibility(var->getFormalAccess()); - VarDecl *newValueParam = nullptr; + ParamDecl *newValueParam = nullptr; auto *setter = createSetterPrototype(var, newValueParam, TC); var->makeComputed(var->getLoc(), getter, setter, nullptr, var->getLoc()); @@ -1864,41 +1330,47 @@ void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) { addMemberToContextIfNeeded(getter, var->getDeclContext()); addMemberToContextIfNeeded(setter, var->getDeclContext()); return; - } - // Stored properties in SIL mode don't get auto-synthesized accessors. - bool isInSILMode = false; - if (auto sourceFile = var->getDeclContext()->getParentSourceFile()) - isInSILMode = sourceFile->Kind == SourceFileKind::SIL; + + // Implicit properties don't get accessors. + if (var->isImplicit()) + return; auto nominal = var->getDeclContext()->isNominalTypeOrNominalTypeExtensionContext(); - if (var->hasAccessorFunctions() || - var->isImplicit() || - nominal == nullptr) + if (!nominal) { + // Fixed-layout global variables don't get accessors. + if (var->hasFixedLayout()) + return; + + // Stored properties in protocols are converted to computed + // elsewhere. + } else if (isa(nominal)) { return; - // Non-NSManaged class instance variables get accessors, because it affects - // vtable layout. - if (isa(nominal)) { + // NSManaged properties on classes require special handling. + } else if (isa(nominal)) { if (var->getAttrs().hasAttribute()) { var->setIsBeingTypeChecked(); convertNSManagedStoredVarToComputed(var, TC); var->setIsBeingTypeChecked(false); - } else if (!isInSILMode) { - var->setIsBeingTypeChecked(); - addTrivialAccessorsToStorage(var, TC); - var->setIsBeingTypeChecked(false); + return; } - } - // Public instance variables of resilient structs get accessors. - if (auto structDecl = dyn_cast(nominal)) { - if (!structDecl->hasFixedLayout() && !isInSILMode) { - var->setIsBeingTypeChecked(); - addTrivialAccessorsToStorage(var, TC); - var->setIsBeingTypeChecked(false); - } + // Stored properties imported from Clang don't get accessors. + } else if (isa(nominal)) { + if (nominal->hasClangNode()) + return; } + + // Stored properties in SIL mode don't get accessors. + if (auto sourceFile = var->getDeclContext()->getParentSourceFile()) + if (sourceFile->Kind == SourceFileKind::SIL) + return; + + // Everything else gets accessors. + var->setIsBeingTypeChecked(); + addTrivialAccessorsToStorage(var, TC); + var->setIsBeingTypeChecked(false); } /// \brief Create an implicit struct or class constructor. @@ -1918,8 +1390,7 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc, accessLevel = std::min(accessLevel, Accessibility::Internal); // Determine the parameter type of the implicit constructor. - SmallVector patternElts; - SmallVector argNames; + SmallVector params; if (ICK == ImplicitConstructorKind::Memberwise) { assert(isa(decl) && "Only struct have memberwise constructor"); @@ -1929,7 +1400,6 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc, continue; tc.validateDecl(var); - // Initialized 'let' properties have storage, but don't get an argument // to the memberwise initializer since they already have an initial // value that cannot be overridden. @@ -1949,27 +1419,22 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc, varType = OptionalType::get(varType); // Create the parameter. - auto *arg = new (context) ParamDecl(/*IsLet*/true, Loc, var->getName(), + auto *arg = new (context) ParamDecl(/*IsLet*/true, SourceLoc(), + Loc, var->getName(), Loc, var->getName(), varType, decl); arg->setImplicit(); - argNames.push_back(var->getName()); - Pattern *pattern = new (context) NamedPattern(arg); - pattern->setImplicit(); - TypeLoc tyLoc = TypeLoc::withoutLoc(varType); - pattern = new (context) TypedPattern(pattern, tyLoc); - patternElts.push_back(TuplePatternElt(var->getName(), SourceLoc(), - pattern, false)); + params.push_back(arg); } } - auto pattern = TuplePattern::create(context, Loc, patternElts, Loc); - pattern->setImplicit(); - + auto paramList = ParameterList::create(context, params); + // Create the constructor. - DeclName name(context, context.Id_init, argNames); - Pattern *selfPat = buildImplicitSelfParameter(Loc, decl); + DeclName name(context, context.Id_init, paramList); + auto *selfParam = ParamDecl::createSelf(Loc, decl, + /*static*/false, /*inout*/true); auto *ctor = new (context) ConstructorDecl(name, Loc, OTK_None, SourceLoc(), - selfPat, pattern, + selfParam, paramList, nullptr, SourceLoc(), decl); // Mark implicit. @@ -1993,111 +1458,12 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc, // If the struct in which this constructor is being added was imported, // add it as an external definition. if (decl->hasClangNode()) { - tc.Context.addedExternalDecl(ctor); + tc.Context.addExternalDecl(ctor); } return ctor; } -/// Create an expression that references the variables in the given -/// pattern for, e.g., forwarding of these variables to another -/// function with the same signature. -static Expr *forwardArguments(TypeChecker &tc, ClassDecl *classDecl, - ConstructorDecl *toDecl, - Pattern *bodyPattern, - ArrayRef argumentNames) { - switch (bodyPattern->getKind()) { -#define PATTERN(Id, Parent) -#define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: -#include "swift/AST/PatternNodes.def" - return nullptr; - - case PatternKind::Paren: { - auto subExpr = forwardArguments(tc, classDecl, toDecl, - cast(bodyPattern)->getSubPattern(), - { }); - if (!subExpr) return nullptr; - - // If there is a name for this single-argument thing, then form a tupleexpr. - if (argumentNames.size() != 1 || argumentNames[0].empty()) - return new (tc.Context) ParenExpr(SourceLoc(), subExpr, SourceLoc(), - /*hasTrailingClosure=*/false); - - return TupleExpr::createImplicit(tc.Context, subExpr, argumentNames); - } - - - case PatternKind::Tuple: { - auto bodyTuple = cast(bodyPattern); - SmallVector values; - - // FIXME: Can't forward varargs yet. - if (bodyTuple->hasAnyEllipsis()) { - tc.diagnose(classDecl->getLoc(), - diag::unsupported_synthesize_init_variadic, - classDecl->getDeclaredType()); - tc.diagnose(toDecl, diag::variadic_superclass_init_here); - return nullptr; - } - - for (unsigned i = 0, n = bodyTuple->getNumElements(); i != n; ++i) { - // Forward the value. - auto subExpr = forwardArguments(tc, classDecl, toDecl, - bodyTuple->getElement(i).getPattern(), - { }); - if (!subExpr) - return nullptr; - values.push_back(subExpr); - - // Dig out the name. - auto subPattern = bodyTuple->getElement(i).getPattern(); - do { - if (auto typed = dyn_cast(subPattern)) { - subPattern = typed->getSubPattern(); - continue; - } - - if (auto paren = dyn_cast(subPattern)) { - subPattern = paren->getSubPattern(); - continue; - } - - break; - } while (true); - } - - if (values.size() == 1 && - (argumentNames.empty() || argumentNames[0].empty())) - return new (tc.Context) ParenExpr(SourceLoc(), values[0], SourceLoc(), - /*hasTrailingClosure=*/false); - - return TupleExpr::createImplicit(tc.Context, values, argumentNames); - } - - case PatternKind::Any: - case PatternKind::Named: { - auto decl = cast(bodyPattern)->getDecl(); - Expr *declRef = new (tc.Context) DeclRefExpr(decl, SourceLoc(), - /*Implicit=*/true); - if (decl->getType()->is()) - declRef = new (tc.Context) InOutExpr(SourceLoc(), declRef, - Type(), /*isImplicit=*/true); - return declRef; - } - - case PatternKind::Typed: - return forwardArguments(tc, classDecl, toDecl, - cast(bodyPattern)->getSubPattern(), - argumentNames); - - case PatternKind::Var: - return forwardArguments(tc, classDecl, toDecl, - cast(bodyPattern)->getSubPattern(), - argumentNames); - - } -} - /// Create a stub body that emits a fatal error message. static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) { auto unimplementedInitDecl = tc.Context.getUnimplementedInitializerDecl(&tc); @@ -2109,7 +1475,8 @@ static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) { // Create a call to Swift._unimplemented_initializer auto loc = classDecl->getLoc(); - Expr *fn = new (tc.Context) DeclRefExpr(unimplementedInitDecl, loc, + Expr *fn = new (tc.Context) DeclRefExpr(unimplementedInitDecl, + DeclNameLoc(loc), /*Implicit=*/true); llvm::SmallString<64> buffer; @@ -2118,8 +1485,10 @@ static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) { "." + classDecl->getName().str()).toStringRef(buffer)); - Expr *className = new (tc.Context) StringLiteralExpr(fullClassName, loc); + Expr *className = new (tc.Context) StringLiteralExpr(fullClassName, loc, + /*Implicit=*/true); className = new (tc.Context) ParenExpr(loc, className, loc, false); + className->setImplicit(); Expr *call = new (tc.Context) CallExpr(fn, className, /*Implicit=*/true); ctor->setBody(BraceStmt::create(tc.Context, SourceLoc(), ASTNode(call), @@ -2146,87 +1515,18 @@ swift::createDesignatedInitOverride(TypeChecker &tc, auto &ctx = tc.Context; // Create the 'self' declaration and patterns. - auto *selfDecl = new (ctx) ParamDecl(/*IsLet*/ true, - SourceLoc(), Identifier(), - SourceLoc(), ctx.Id_self, - Type(), classDecl); - selfDecl->setImplicit(); - Pattern *selfBodyPattern - = new (ctx) NamedPattern(selfDecl, /*Implicit=*/true); - selfBodyPattern = new (ctx) TypedPattern(selfBodyPattern, TypeLoc()); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), classDecl); // Create the initializer parameter patterns. - OptionSet options = Pattern::Implicit; - options |= Pattern::Inherited; - Pattern *bodyParamPatterns - = superclassCtor->getBodyParamPatterns()[1]->clone(ctx, options); - - // Fix up the default arguments in the type to refer to inherited default - // arguments. - // FIXME: If we weren't cloning the type along with the pattern, this would be - // a lot more direct. - Type argType = bodyParamPatterns->getType(); - - // Local function that maps default arguments to inherited default arguments. - std::function inheritDefaultArgs = [&](Type type) -> Type { - auto tuple = type->getAs(); - if (!tuple) - return type; - - bool anyChanged = false; - SmallVector elements; - unsigned index = 0; - for (const auto &elt : tuple->getElements()) { - Type eltTy = elt.getType().transform(inheritDefaultArgs); - if (!eltTy) - return Type(); - - // If nothing has changed, just keep going. - if (!anyChanged && eltTy.getPointer() == elt.getType().getPointer() && - (elt.getDefaultArgKind() == DefaultArgumentKind::None || - elt.getDefaultArgKind() == DefaultArgumentKind::Inherited)) { - ++index; - continue; - } - - // If this is the first change we've seen, copy all of the previous - // elements. - if (!anyChanged) { - // Copy all of the previous elements. - for (unsigned i = 0; i != index; ++i) { - const TupleTypeElt &FromElt = tuple->getElement(i); - elements.push_back(TupleTypeElt(FromElt.getType(), FromElt.getName(), - FromElt.getDefaultArgKind(), - FromElt.isVararg())); - } - - anyChanged = true; - } - - // Add the new tuple element, with the new type, no initializer, - auto defaultArgKind = elt.getDefaultArgKind(); - if (defaultArgKind != DefaultArgumentKind::None) - defaultArgKind = DefaultArgumentKind::Inherited; - elements.push_back(TupleTypeElt(eltTy, elt.getName(), defaultArgKind, - elt.isVararg())); - ++index; - } - - if (!anyChanged) - return type; - - return TupleType::get(elements, ctx); - }; - - argType = argType.transform(inheritDefaultArgs); - bodyParamPatterns->setType(argType); - + OptionSet options = ParameterList::Implicit; + options |= ParameterList::Inherited; + auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx,options); + // Create the initializer declaration. auto ctor = new (ctx) ConstructorDecl(superclassCtor->getFullName(), classDecl->getBraces().Start, superclassCtor->getFailability(), - SourceLoc(), - selfBodyPattern, bodyParamPatterns, + SourceLoc(), selfDecl, bodyParams, nullptr, SourceLoc(), classDecl); ctor->setImplicit(); ctor->setAccessibility(std::min(classDecl->getFormalAccess(), @@ -2238,13 +1538,10 @@ swift::createDesignatedInitOverride(TypeChecker &tc, ctx); // Configure 'self'. - Type selfType = configureImplicitSelf(tc, ctor); - selfBodyPattern->setType(selfType); - cast(selfBodyPattern)->getSubPattern()->setType(selfType); + auto selfType = configureImplicitSelf(tc, ctor); // Set the type of the initializer. - configureConstructorType(ctor, selfType, - bodyParamPatterns->getType(), + configureConstructorType(ctor, selfType, bodyParams->getType(ctx), superclassCtor->isBodyThrowing()); if (superclassCtor->isObjC()) { auto errorConvention = superclassCtor->getForeignErrorConvention(); @@ -2280,19 +1577,21 @@ swift::createDesignatedInitOverride(TypeChecker &tc, // Reference to super.init. Expr *superRef = new (ctx) SuperRefExpr(selfDecl, SourceLoc(), /*Implicit=*/true); - Expr *ctorRef = new (ctx) UnresolvedConstructorExpr(superRef, - SourceLoc(), - SourceLoc(), - /*Implicit=*/true); + Expr *ctorRef = new (ctx) UnresolvedDotExpr(superRef, SourceLoc(), + superclassCtor->getFullName(), + DeclNameLoc(), + /*Implicit=*/true); + + auto ctorArgs = buildArgumentForwardingExpr(bodyParams->getArray(), ctx); - Expr *ctorArgs = forwardArguments(tc, classDecl, superclassCtor, - ctor->getBodyParamPatterns()[1], - ctor->getFullName().getArgumentNames()); + // If buildArgumentForwardingExpr failed, then it was because we tried to + // forward varargs, which cannot be done yet. + // TODO: We should be able to forward varargs! if (!ctorArgs) { - // FIXME: We should be able to assert that this never happens, - // but there are currently holes when dealing with vararg - // initializers and _ parameters. Fail somewhat gracefully by - // generating a stub here. + tc.diagnose(classDecl->getLoc(), + diag::unsupported_synthesize_init_variadic, + classDecl->getDeclaredType()); + tc.diagnose(superclassCtor, diag::variadic_superclass_init_here); createStubBody(tc, ctor); return ctor; } @@ -2314,10 +1613,10 @@ void TypeChecker::addImplicitDestructor(ClassDecl *CD) { if (CD->hasDestructor() || CD->isInvalid()) return; - Pattern *selfPat = buildImplicitSelfParameter(CD->getLoc(), CD); + auto *selfDecl = ParamDecl::createSelf(CD->getLoc(), CD); auto *DD = new (Context) DestructorDecl(Context.Id_deinit, CD->getLoc(), - selfPat, CD); + selfDecl, CD); DD->setImplicit(); diff --git a/lib/Sema/CodeSynthesis.h b/lib/Sema/CodeSynthesis.h index bd6b17ecb6b29..878fa2f6c73b9 100644 --- a/lib/Sema/CodeSynthesis.h +++ b/lib/Sema/CodeSynthesis.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index f7f9e9c48e57d..b19c98de9a067 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -1,8 +1,8 @@ -//===--- Constraint.cpp - Constraint in the Type Checker --------*- C++ -*-===// +//===--- Constraint.cpp - Constraint in the Type Checker ------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,7 @@ #include "swift/AST/Types.h" #include "swift/Basic/Fallthrough.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SaveAndRestore.h" #include using namespace swift; @@ -338,6 +339,10 @@ void Constraint::dump(SourceManager *sm) const { } void Constraint::dump(ConstraintSystem *CS) const { + // Print all type variables as $T0 instead of _ here. + llvm::SaveAndRestore X(CS->getASTContext().LangOpts. + DebugConstraintSolver, true); + dump(&CS->getASTContext().SourceMgr); } diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h index ebbec8f9de2fc..b82cc5e9852d7 100644 --- a/lib/Sema/Constraint.h +++ b/lib/Sema/Constraint.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -138,7 +138,7 @@ enum class ConstraintClassification : char { /// it a reference type. Member, - /// \brief An property of a single type, such as whether it is an archetype. + /// \brief A property of a single type, such as whether it is an archetype. TypeProperty, /// \brief A disjunction constraint. diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp index e92cd1fe4be61..ecdc486a60646 100644 --- a/lib/Sema/ConstraintGraph.cpp +++ b/lib/Sema/ConstraintGraph.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -687,6 +687,179 @@ unsigned ConstraintGraph::computeConnectedComponents( return numComponents; } + +/// For a given constraint kind, decide if we should attempt to eliminate its +/// edge in the graph. +static bool shouldContractEdge(ConstraintKind kind) { + switch (kind) { + case ConstraintKind::Bind: + case ConstraintKind::BindParam: + case ConstraintKind::Equal: + case ConstraintKind::BindOverload: + + // We currently only allow subtype contractions for the purpose of + // parameter binding constraints. + // TODO: We do this because of how inout parameter bindings are handled + // for implicit closure parameters. We should consider adjusting our + // current approach to unlock more opportunities for subtype contractions. + case ConstraintKind::Subtype: + return true; + + default: + return false; + } +} + +/// We use this function to determine if a subtype constraint is set +/// between two (possibly sugared) type variables, one of which is wrapped +/// in an inout type. +static bool isStrictInoutSubtypeConstraint(Constraint *constraint) { + if (constraint->getKind() != ConstraintKind::Subtype) + return false; + + auto t1 = constraint->getFirstType()->getDesugaredType(); + + if (auto tt = t1->getAs()) { + if (tt->getNumElements() != 1) + return false; + + t1 = tt->getElementType(0).getPointer(); + } + + auto iot = t1->getAs(); + + if (!iot) + return false; + + return iot->getObjectType()->getAs() == nullptr; +} + +bool ConstraintGraph::contractEdges() { + llvm::SetVector> contractions; + + auto tyvars = getTypeVariables(); + auto didContractEdges = false; + + for (auto tyvar : tyvars) { + SmallVector constraints; + gatherConstraints(tyvar, constraints); + + for (auto constraint : constraints) { + auto kind = constraint->getKind(); + // Contract binding edges between type variables. + if (shouldContractEdge(kind)) { + auto t1 = constraint->getFirstType()->getDesugaredType(); + auto t2 = constraint->getSecondType()->getDesugaredType(); + + if (kind == ConstraintKind::Subtype) { + if (auto iot1 = t1->getAs()) { + t1 = iot1->getObjectType().getPointer(); + } else { + continue; + } + } + + auto tyvar1 = t1->getAs(); + auto tyvar2 = t2->getAs(); + + if (!(tyvar1 && tyvar2)) + continue; + + auto isParamBindingConstraint = kind == ConstraintKind::BindParam; + + // We need to take special care not to directly contract parameter + // binding constraints if there is an inout subtype constraint on the + // type variable. The constraint solver depends on multiple constraints + // being present in this case, so it can generate the appropriate lvalue + // wrapper for the argument type. + if (isParamBindingConstraint) { + auto node = tyvar1->getImpl().getGraphNode(); + auto hasDependentConstraint = false; + + for (auto t1Constraint : node->getConstraints()) { + if (isStrictInoutSubtypeConstraint(t1Constraint)) { + hasDependentConstraint = true; + break; + } + } + + if (hasDependentConstraint) + continue; + } + + auto rep1 = CS.getRepresentative(tyvar1); + auto rep2 = CS.getRepresentative(tyvar2); + + if (((rep1->getImpl().canBindToLValue() == + rep2->getImpl().canBindToLValue()) || + // Allow l-value contractions when binding parameter types. + isParamBindingConstraint)) { + if (CS.TC.getLangOpts().DebugConstraintSolver) { + auto &log = CS.getASTContext().TypeCheckerDebug->getStream(); + if (CS.solverState) + log.indent(CS.solverState->depth * 2); + + log << "Contracting constraint "; + constraint->print(log, &CS.getASTContext().SourceMgr); + log << "\n"; + } + + // Merge the edges and remove the constraint. + removeEdge(constraint); + if (rep1 != rep2) + CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); + didContractEdges = true; + } + } + } + } + + return didContractEdges; +} + +void ConstraintGraph::removeEdge(Constraint *constraint) { + + for (auto &active : CS.ActiveConstraints) { + if (&active == constraint) { + CS.ActiveConstraints.erase(constraint); + break; + } + } + + for (auto &inactive : CS.InactiveConstraints) { + if (&inactive == constraint) { + CS.InactiveConstraints.erase(constraint); + break; + } + } + + size_t index = 0; + for (auto generated : CS.solverState->generatedConstraints) { + if (generated == constraint) { + unsigned last = CS.solverState->generatedConstraints.size()-1; + auto lastConstraint = CS.solverState->generatedConstraints[last]; + if (lastConstraint == generated) { + CS.solverState->generatedConstraints.pop_back(); + break; + } else { + CS.solverState->generatedConstraints[index] = lastConstraint; + CS.solverState->generatedConstraints[last] = constraint; + CS.solverState->generatedConstraints.pop_back(); + break; + } + } + index++; + } + + removeConstraint(constraint); +} + +void ConstraintGraph::optimize() { + // Merge equivalence classes until a fixed point is reached. + while(contractEdges()) {} +} + #pragma mark Debugging output void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) { diff --git a/lib/Sema/ConstraintGraph.h b/lib/Sema/ConstraintGraph.h index 3385275f30bd1..c52ebbea4dd26 100644 --- a/lib/Sema/ConstraintGraph.h +++ b/lib/Sema/ConstraintGraph.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -287,6 +287,10 @@ class ConstraintGraph { /// Verify the invariants of the graph. void verify(); + /// Optimize the constraint graph by eliminating simple transitive + /// connections between nodes. + void optimize(); + private: /// Remove the node corresponding to the given type variable. /// @@ -304,6 +308,15 @@ class ConstraintGraph { /// caution. void unbindTypeVariable(TypeVariableType *typeVar, Type fixedType); + + /// Perform edge contraction on the constraint graph, merging equivalence + /// classes until a fixed point is reached. + bool contractEdges(); + + /// To support edge contraction, remove a constraint from both the constraint + /// graph and its enclosing constraint system. + void removeEdge(Constraint *constraint); + /// The constraint system. ConstraintSystem &CS; diff --git a/lib/Sema/ConstraintGraphScope.h b/lib/Sema/ConstraintGraphScope.h index d6410dd78a914..213ca89439613 100644 --- a/lib/Sema/ConstraintGraphScope.h +++ b/lib/Sema/ConstraintGraphScope.h @@ -1,8 +1,8 @@ -//===--- ConstraintGraphScope.h - Constraint Graph Scope---------*- C++ -*-===// +//===--- ConstraintGraphScope.h - Constraint Graph Scope --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -53,6 +53,6 @@ class ConstraintGraphScope { }; } // end namespace swift::constraints -} // end namespacae swift +} // end namespace swift #endif // LLVM_SWIFT_SEMA_CONSTRAINT_GRAPH_SCOPE_H diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index ab653deced826..6b94519ba2141 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 50023142901fe..9b6c02d86e97d 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -51,7 +51,7 @@ namespace constraints { /// to indicate constraints on its argument or result type. class ConstraintLocator : public llvm::FoldingSetNode { public: - /// \brief Describes the kind of a a particular path element, e.g., + /// \brief Describes the kind of a particular path element, e.g., /// "tuple element", "call result", "base of member lookup", etc. enum PathElementKind : unsigned char { /// \brief The argument of function application. @@ -116,7 +116,7 @@ class ConstraintLocator : public llvm::FoldingSetNode { Load, /// The candidate witness during protocol conformance checking. Witness, - /// This is refering to a type produced by opening a generic type at the + /// This is referring to a type produced by opening a generic type at the /// base of the locator. OpenedGeneric, }; @@ -449,17 +449,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { Profile(id, anchor, getPath()); } - /// \brief Determine whether or not constraint failures associated with this - /// locator should be discarded. - bool shouldDiscardFailures() { - return discardFailures; - } - - /// \brief Toggle option to discard constraint failures. - void setDiscardFailures(bool shouldDiscard = true) { - discardFailures = shouldDiscard; - } - /// \brief Produce a debugging dump of this locator. LLVM_ATTRIBUTE_DEPRECATED( void dump(SourceManager *SM) LLVM_ATTRIBUTE_USED, @@ -474,8 +463,7 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// \brief Initialize a constraint locator with an anchor and a path. ConstraintLocator(Expr *anchor, ArrayRef path, unsigned flags) - : anchor(anchor), numPathElements(path.size()), summaryFlags(flags), - discardFailures(false) + : anchor(anchor), numPathElements(path.size()), summaryFlags(flags) { // FIXME: Alignment. std::copy(path.begin(), path.end(), @@ -510,11 +498,6 @@ class ConstraintLocator : public llvm::FoldingSetNode { /// \brief A set of flags summarizing interesting properties of the path. unsigned summaryFlags : 7; - /// \brief Determines whether or not we should record constraint application - /// failures associated with this locator. This information cannot be - /// inferred from the path itself, so it is not stored as a summary flag. - unsigned discardFailures: 1; - friend class ConstraintSystem; }; diff --git a/lib/Sema/ConstraintSolverStats.def b/lib/Sema/ConstraintSolverStats.def index cddacbddd54f1..d18433bc71a54 100644 --- a/lib/Sema/ConstraintSolverStats.def +++ b/lib/Sema/ConstraintSolverStats.def @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index e799fd2ae44a4..49f06c32375db 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,7 +60,8 @@ void ConstraintSystem::addTypeVariable(TypeVariableType *typeVar) { } void ConstraintSystem::mergeEquivalenceClasses(TypeVariableType *typeVar1, - TypeVariableType *typeVar2) { + TypeVariableType *typeVar2, + bool updateWorkList) { assert(typeVar1 == getRepresentative(typeVar1) && "typeVar1 is not the representative"); assert(typeVar2 == getRepresentative(typeVar2) && @@ -70,7 +71,10 @@ void ConstraintSystem::mergeEquivalenceClasses(TypeVariableType *typeVar1, // Merge nodes in the constraint graph. CG.mergeNodes(typeVar1, typeVar2); - addTypeVariableConstraintsToWorkList(typeVar1); + + if (updateWorkList) { + addTypeVariableConstraintsToWorkList(typeVar1); + } } void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type, @@ -424,13 +428,11 @@ namespace { ConstraintSystem &CS; ConstraintGraph &CG; ConstraintLocatorBuilder &Locator; - DependentTypeOpener *Opener; public: GetTypeVariable(ConstraintSystem &cs, - ConstraintLocatorBuilder &locator, - DependentTypeOpener *opener) - : CS(cs), CG(CS.getConstraintGraph()), Locator(locator), Opener(opener) {} + ConstraintLocatorBuilder &locator) + : CS(cs), CG(CS.getConstraintGraph()), Locator(locator) {} TypeVariableType *operator()(Type base, AssociatedTypeDecl *member) { // FIXME: Premature associated type -> identifier mapping. We should @@ -476,31 +478,12 @@ namespace { auto memberTypeVar = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding); - // Determine whether we should bind the new type variable as a - // member of the base type variable, or let it float. - Type replacementType; - bool shouldBindMember = true; - if (Opener) { - shouldBindMember = Opener->shouldBindAssociatedType(base, baseTypeVar, - member, - memberTypeVar, - replacementType); - } - // Bind the member's type variable as a type member of the base, - // if needed. - if (shouldBindMember) { - CS.addConstraint(Constraint::create(CS, ConstraintKind::TypeMember, - baseTypeVar, memberTypeVar, - member->getName(), locator)); - } + // Bind the member's type variable as a type member of the base. + CS.addConstraint(Constraint::create(CS, ConstraintKind::TypeMember, + baseTypeVar, memberTypeVar, + member->getName(), locator)); - // If we have a replacement type, bind the member's type - // variable to it. - if (replacementType) - CS.addConstraint(ConstraintKind::Bind, memberTypeVar, - replacementType, locator); - if (!archetype) { // If the nested type is not an archetype (because it was constrained // to a concrete type by a requirement), return the fresh type @@ -532,7 +515,6 @@ namespace { DeclContext *dc; bool skipProtocolSelfConstraint; unsigned minOpeningDepth; - DependentTypeOpener *opener; ConstraintLocatorBuilder &locator; llvm::DenseMap &replacements; GetTypeVariable &getTypeVariable; @@ -543,12 +525,11 @@ namespace { DeclContext *dc, bool skipProtocolSelfConstraint, unsigned minOpeningDepth, - DependentTypeOpener *opener, ConstraintLocatorBuilder &locator, llvm::DenseMap &replacements, GetTypeVariable &getTypeVariable) : cs(cs), dc(dc), skipProtocolSelfConstraint(skipProtocolSelfConstraint), - minOpeningDepth(minOpeningDepth), opener(opener), locator(locator), + minOpeningDepth(minOpeningDepth), locator(locator), replacements(replacements), getTypeVariable(getTypeVariable) { } Type operator()(Type type) { @@ -559,24 +540,8 @@ namespace { return type; } - // Replace archetypes with fresh type variables. - if (auto archetype = type->getAs()) { - auto known = replacements.find(archetype->getCanonicalType()); - if (known != replacements.end()) - return known->second; - - return archetype; - } - // Replace a generic type parameter with its corresponding type variable. if (auto genericParam = type->getAs()) { - if (opener) { - // If we have a mapping for this type parameter, there's nothing else to do. - if (Type replacement = opener->mapGenericTypeParamType(genericParam)){ - return replacement; - } - } - auto known = replacements.find(genericParam->getCanonicalType()); if (known == replacements.end()) @@ -588,14 +553,6 @@ namespace { // Replace a dependent member with a fresh type variable and make it a // member of its base type. if (auto dependentMember = type->getAs()) { - if (opener) { - // If we have a mapping for this type parameter, there's nothing else to do. - if (Type replacement - = opener->mapDependentMemberType(dependentMember)) { - return replacement; - } - } - // Check whether we've already dealt with this dependent member. auto known = replacements.find(dependentMember->getCanonicalType()); if (known != replacements.end()) @@ -619,7 +576,6 @@ namespace { genericFn->getRequirements(), skipProtocolSelfConstraint, minOpeningDepth, - opener, locator, replacements); @@ -651,17 +607,16 @@ namespace { // Open up the generic type. cs.openGeneric(unboundDecl, - unboundDecl->getGenericParamTypes(), + unboundDecl->getInnermostGenericParamTypes(), unboundDecl->getGenericRequirements(), /*skipProtocolSelfConstraint=*/false, minOpeningDepth, - opener, locator, replacements); // Map the generic parameters to their corresponding type variables. llvm::SmallVector arguments; - for (auto gp : unboundDecl->getGenericParamTypes()) { + for (auto gp : unboundDecl->getInnermostGenericParamTypes()) { assert(replacements.count(gp->getCanonicalType()) && "Missing generic parameter?"); arguments.push_back(replacements[gp->getCanonicalType()]); @@ -680,14 +635,12 @@ Type ConstraintSystem::openType( llvm::DenseMap &replacements, DeclContext *dc, bool skipProtocolSelfConstraint, - unsigned minOpeningDepth, - DependentTypeOpener *opener) { - GetTypeVariable getTypeVariable{*this, locator, opener}; + unsigned minOpeningDepth) { + GetTypeVariable getTypeVariable{*this, locator}; ReplaceDependentTypes replaceDependentTypes(*this, dc, skipProtocolSelfConstraint, minOpeningDepth, - opener, locator, replacements, getTypeVariable); return startingType.transform(replaceDependentTypes); @@ -827,8 +780,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, bool isTypeReference, bool isSpecialized, ConstraintLocatorBuilder locator, - const DeclRefExpr *base, - DependentTypeOpener *opener) { + const DeclRefExpr *base) { llvm::DenseMap replacements; if (value->getDeclContext()->isTypeContext() && isa(value)) { @@ -836,11 +788,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, auto func = cast(value); assert(func->isOperator() && "Lookup should only find operators"); - auto openedType = openType(func->getInterfaceType(), locator, - replacements, func, - false, - value->getDeclContext()->getGenericTypeContextDepth(), - opener); + auto openedType = + openType(func->getInterfaceType(), locator, + replacements, func, + false, + value->getDeclContext()->getGenericTypeContextDepth()); auto openedFnType = openedType->castTo(); // If this is a method whose result type is dynamic Self, replace @@ -849,7 +801,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, Type selfTy = openedFnType->getInput()->getRValueInstanceType(); openedType = openedType->replaceCovariantResultType( selfTy, - func->getNumParamPatterns()); + func->getNumParameterLists()); openedFnType = openedType->castTo(); } @@ -880,8 +832,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, type = openType(type, locator, replacements, value->getInnermostDeclContext(), false, - value->getDeclContext()->getGenericTypeContextDepth(), - opener); + value->getDeclContext()->getGenericTypeContextDepth()); // If we opened up any type variables, record the replacements. recordOpenedTypes(locator, replacements); @@ -916,10 +867,9 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // Adjust the type of the reference. valueType = openType(valueType, locator, replacements, - value->getPotentialGenericDeclContext(), + value->getInnermostDeclContext(), /*skipProtocolSelfConstraint=*/false, - value->getDeclContext()->getGenericTypeContextDepth(), - opener); + value->getDeclContext()->getGenericTypeContextDepth()); // If we opened up any type variables, record the replacements. recordOpenedTypes(locator, replacements); @@ -933,17 +883,12 @@ void ConstraintSystem::openGeneric( ArrayRef requirements, bool skipProtocolSelfConstraint, unsigned minOpeningDepth, - DependentTypeOpener *opener, ConstraintLocatorBuilder locator, llvm::DenseMap &replacements) { auto locatorPtr = getConstraintLocator(locator); // Create the type variables for the generic parameters. for (auto gp : params) { - // If we have a mapping for this type parameter, there's nothing else to do. - if (opener && opener->mapGenericTypeParamType(gp)) - continue; - ArchetypeType *archetype = ArchetypeBuilder::mapTypeIntoContext(dc, gp) ->castTo(); auto typeVar = createTypeVariable(getConstraintLocator( @@ -955,24 +900,14 @@ void ConstraintSystem::openGeneric( if (gp->getDepth() < minOpeningDepth) addConstraint(ConstraintKind::Bind, typeVar, archetype, locatorPtr); - - // Note that we opened a generic parameter to a type variable. - if (opener) { - Type replacementType; - opener->openedGenericParameter(gp, typeVar, replacementType); - - if (replacementType) - addConstraint(ConstraintKind::Bind, typeVar, replacementType, - locatorPtr); - } } - GetTypeVariable getTypeVariable{*this, locator, opener}; + GetTypeVariable getTypeVariable{*this, locator}; ReplaceDependentTypes replaceDependentTypes(*this, dc, skipProtocolSelfConstraint, minOpeningDepth, - opener, locator, replacements, + locator, replacements, getTypeVariable); // Remember that any new constraints generated by opening this generic are @@ -986,23 +921,26 @@ void ConstraintSystem::openGeneric( switch (req.getKind()) { case RequirementKind::Conformance: { auto subjectTy = req.getFirstType().transform(replaceDependentTypes); - if (auto proto = req.getSecondType()->getAs()) { - // Determine whether this is the protocol 'Self' constraint we should - // skip. - if (skipProtocolSelfConstraint && - (proto->getDecl() == dc->isProtocolOrProtocolExtensionContext() || - proto->getDecl() - == dc->getParent()->isProtocolOrProtocolExtensionContext())&& - isProtocolSelfType(req.getFirstType())) { - break; - } - - addConstraint(ConstraintKind::ConformsTo, subjectTy, proto, - locatorPtr); - } else { - auto boundTy = req.getSecondType().transform(replaceDependentTypes); - addConstraint(ConstraintKind::Subtype, subjectTy, boundTy, locatorPtr); + auto proto = req.getSecondType()->castTo(); + // Determine whether this is the protocol 'Self' constraint we should + // skip. + if (skipProtocolSelfConstraint && + (proto->getDecl() == dc->isProtocolOrProtocolExtensionContext() || + proto->getDecl() + == dc->getParent()->isProtocolOrProtocolExtensionContext())&& + isProtocolSelfType(req.getFirstType())) { + break; } + + addConstraint(ConstraintKind::ConformsTo, subjectTy, proto, + locatorPtr); + break; + } + + case RequirementKind::Superclass: { + auto subjectTy = req.getFirstType().transform(replaceDependentTypes); + auto boundTy = req.getSecondType().transform(replaceDependentTypes); + addConstraint(ConstraintKind::Subtype, subjectTy, boundTy, locatorPtr); break; } @@ -1069,12 +1007,13 @@ Type ConstraintSystem::replaceSelfTypeInArchetype(ArchetypeType *archetype) { } std::pair -ConstraintSystem::getTypeOfMemberReference(Type baseTy, ValueDecl *value, - bool isTypeReference, - bool isDynamicResult, - ConstraintLocatorBuilder locator, - const DeclRefExpr *base, - DependentTypeOpener *opener) { +ConstraintSystem::getTypeOfMemberReference( + Type baseTy, ValueDecl *value, + bool isTypeReference, + bool isDynamicResult, + ConstraintLocatorBuilder locator, + const DeclRefExpr *base, + llvm::DenseMap *replacementsPtr) { // Figure out the instance type used for the base. TypeVariableType *baseTypeVar = nullptr; Type baseObjTy = getFixedTypeRecursive(baseTy, baseTypeVar, @@ -1088,7 +1027,7 @@ ConstraintSystem::getTypeOfMemberReference(Type baseTy, ValueDecl *value, // If the base is a module type, just use the type of the decl. if (baseObjTy->is()) { return getTypeOfReference(value, isTypeReference, /*isSpecialized=*/false, - locator, base, opener); + locator, base); } // Handle associated type lookup as a special case, horribly. @@ -1138,40 +1077,39 @@ ConstraintSystem::getTypeOfMemberReference(Type baseTy, ValueDecl *value, } // Figure out the declaration context to use when opening this type. - DeclContext *dc = value->getPotentialGenericDeclContext(); + DeclContext *dc = value->getInnermostDeclContext(); + unsigned minOpeningDepth = + value->getDeclContext()->getGenericTypeContextDepth(); // Open the type of the generic function or member of a generic type. Type openedType; auto isClassBoundExistential = false; - llvm::DenseMap replacements; + llvm::DenseMap localReplacements; + auto &replacements = replacementsPtr ? *replacementsPtr : localReplacements; if (auto genericFn = value->getInterfaceType()->getAs()){ - openedType = openType(genericFn, locator, replacements, - dc, + openedType = openType(genericFn, locator, replacements, dc, /*skipProtocolSelfConstraint=*/true, - value->getDeclContext()->getGenericTypeContextDepth(), - opener); + minOpeningDepth); } else { openedType = TC.getUnopenedTypeOfReference(value, baseTy, DC, base, /*wantInterfaceType=*/true); Type selfTy; if (auto sig = dc->getGenericSignatureOfContext()) { - unsigned minOpeningDepth = - value->getDeclContext()->getGenericTypeContextDepth(); // Open up the generic parameter list for the container. openGeneric(dc, sig->getGenericParams(), sig->getRequirements(), /*skipProtocolSelfConstraint=*/true, minOpeningDepth, - opener, locator, replacements); + locator, replacements); // Open up the type of the member. - openedType = openType(openedType, locator, replacements, nullptr, false, - value->getDeclContext()->getGenericTypeContextDepth(), - opener); + openedType = openType(openedType, locator, replacements, nullptr, + /*skipProtocolSelfConstraint=*/false, + minOpeningDepth); // Determine the object type of 'self'. - auto nominal = value->getDeclContext()->getDeclaredTypeOfContext() - ->getAnyNominal(); + auto nominal = value->getDeclContext() + ->isNominalTypeOrNominalTypeExtensionContext(); // We want to track if the generic context is represented by a // class-bound existential so we won't inappropriately wrap the @@ -1220,7 +1158,7 @@ ConstraintSystem::getTypeOfMemberReference(Type baseTy, ValueDecl *value, func->hasArchetypeSelf())) { openedType = openedType->replaceCovariantResultType( baseObjTy, - func->getNumParamPatterns()); + func->getNumParameterLists()); } } // If this is an initializer, replace the result type with the base diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 10cffc80983ce..c1b3669395aa9 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -299,7 +299,6 @@ class TypeVariableType::Implementation { if (record) otherRep->getImpl().recordBinding(*record); otherRep->getImpl().ParentOrFixed = getTypeVariable(); - assert(otherRep->getImpl().canBindToLValue() == canBindToLValue()); if (!mustBeMaterializable() && otherRep->getImpl().mustBeMaterializable()) { if (record) recordBinding(*record); @@ -356,203 +355,6 @@ namespace constraints { struct ResolvedOverloadSetListItem; -/// \brief Describes a failure. -class Failure : public llvm::FoldingSetNode { -public: - /// \brief The various kinds of failures that can occur - enum FailureKind { - /// \brief The type is not bridged to an Objective-C type. - IsNotBridgedToObjectiveC, - /// \brief The type is not allowed to be an l-value. - IsForbiddenLValue, - /// Type has no public initializers. - NoPublicInitializers, - /// The type is not materializable. - IsNotMaterializable, - }; - -private: - /// \brief The kind of failure this describes. - FailureKind kind : 8; - - /// \brief A value, if used. - unsigned value; - - /// \brief Another value, if used. - unsigned value2; - - /// Describes the location of this failure. - ConstraintLocator *locator; - - /// The resolved overload sets that led to this failure. - ResolvedOverloadSetListItem *resolvedOverloadSets; - - /// \brief The first type. - Type first; - - /// \brief The second value, which may be one of several things (type, - /// member name, etc.). - union { - TypeBase *type; - } second; - -public: - /// \brief Retrieve the failure kind. - FailureKind getKind() const { return kind; } - - /// \brief Retrieve the failure locator. - ConstraintLocator *getLocator() const { - return locator; - } - - /// Retrieve the resolved overload sets active when this failure occurred. - ResolvedOverloadSetListItem *getResolvedOverloadSets() const { - return resolvedOverloadSets; - } - - /// \brief Retrieve the first type. - Type getFirstType() const { return first; } - - /// \brief Retrieve the second type. - Type getSecondType() const { - return second.type; - } - - /// \brief Retrieve the value. - unsigned getValue() const { return value; } - - /// \brief Retrieve the value. - unsigned getSecondValue() const { return value2; } - - /// \brief Profile the given failure. - void Profile(llvm::FoldingSetNodeID &id) { - switch (kind) { - case IsForbiddenLValue: - case IsNotMaterializable: - return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(), - getSecondType()); - - case IsNotBridgedToObjectiveC: - case NoPublicInitializers: - return Profile(id, locator, kind, resolvedOverloadSets, getFirstType(), - value); - } - } - - /// \brief Dump a debug representation of this failure. - LLVM_ATTRIBUTE_DEPRECATED( - void dump(SourceManager *SM) const LLVM_ATTRIBUTE_USED, - "only for use within the debugger"); - - void dump(SourceManager *SM, raw_ostream &OS) const; - -private: - friend class ConstraintSystem; - - /// \brief Construct a failure involving one type. - Failure(ConstraintLocator *locator, FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type, unsigned value = 0) - : kind(kind), value(value), value2(0), locator(locator), - resolvedOverloadSets(resolvedOverloadSets), first(type) - { - second.type = nullptr; - } - - /// \brief Construct a failure involving two types and an optional value. - Failure(ConstraintLocator *locator, FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type1, Type type2, unsigned value = 0) - : kind(kind), value(value), value2(0), locator(locator), - resolvedOverloadSets(resolvedOverloadSets), first(type1) - { - second.type = type2.getPointer(); - } - - /// \brief Construct a failure involving two values. - Failure(ConstraintLocator *locator, FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - unsigned value, unsigned value2 = 0) - : kind(kind), value(value), value2(value2), locator(locator), - resolvedOverloadSets(resolvedOverloadSets) - { - second.type = nullptr; - } - - /// \brief Profile a failure involving one type. - static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, - FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type, unsigned value = 0) { - id.AddPointer(locator); - id.AddInteger(kind); - id.AddPointer(resolvedOverloadSets); - id.AddPointer(type.getPointer()); - id.AddInteger(value); - } - - /// \brief Profile a failure involving two types. - /// Note that because FoldingSet hashes on pointers are unstable, we need - /// to hash on each type's string representation to preserve ordering. - static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, - FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type1, Type type2) { - id.AddPointer(locator); - id.AddInteger(kind); - id.AddPointer(resolvedOverloadSets); - id.AddString(type1.getString()); - id.AddString(type2.getString()); - } - - /// \brief Profile a failure involving two types and a value. - static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, - FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type1, Type type2, unsigned value) { - id.AddPointer(locator); - id.AddInteger(kind); - id.AddPointer(resolvedOverloadSets); - id.AddString(type1.getString()); - id.AddString(type2.getString()); - id.AddInteger(value); - } - - /// \brief Profile a failure involving a type and a name. - static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, - FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - Type type, DeclName name) { - id.AddPointer(locator); - id.AddInteger(kind); - id.AddPointer(resolvedOverloadSets); - id.AddPointer(type.getPointer()); - id.AddPointer(name.getOpaqueValue()); - } - - /// \brief Profile a failure involving two values. - static void Profile(llvm::FoldingSetNodeID &id, ConstraintLocator *locator, - FailureKind kind, - ResolvedOverloadSetListItem *resolvedOverloadSets, - unsigned value, unsigned value2 = 0) { - id.AddPointer(locator); - id.AddInteger(kind); - id.AddPointer(resolvedOverloadSets); - id.AddInteger(value); - id.AddInteger(value2); - } - - /// \brief Create a new Failure object with the given arguments, allocated - /// from the given bump pointer allocator. - template - static Failure *create(llvm::BumpPtrAllocator &allocator, - ConstraintLocator *locator, FailureKind kind, - Args &&...args) { - void *mem = allocator.Allocate(sizeof(Failure), alignof(Failure)); - return new (mem) Failure(locator, kind, args...); - } -}; - /// \brief The kind of type matching to perform in matchTypes(). enum class TypeMatchKind : char { /// \brief Bind the types together directly. @@ -973,66 +775,6 @@ struct SpecificConstraint { ConstraintKind Kind; }; -/// Abstract class implemented by clients that want to be involved in -/// the process of opening dependent types to type variables. -class DependentTypeOpener { -public: - virtual ~DependentTypeOpener() { } - - /// Directly map a generic type parameter to a type, or return null if - /// the type parameter should be opened. - virtual Type mapGenericTypeParamType(GenericTypeParamType *param) { - return Type(); - } - - /// Directly map a dependent member type to a type, or return null if - /// the dependent member type should be opened. - virtual Type mapDependentMemberType(DependentMemberType *memberType) { - return Type(); - } - - /// Invoked when a generic type parameter is opened to a type variable. - /// - /// \param param The generic type parameter. - /// - /// \param typeVar The type variable to which the generic parameter was - /// opened. - /// - /// \param replacementType If the caller sets this to a non-null type, the - /// type variable will be bound directly to this type. - virtual void openedGenericParameter(GenericTypeParamType *param, - TypeVariableType *typeVar, - Type &replacementType) { } - - /// Invoked when an associated type reference is opened to a type - /// variable to determine how the associated type should be resolved. - /// - /// \param baseType The type of the base of the reference. - /// - /// \param baseTypeVar The type variable to which the base type was - /// opened. - /// - /// \param assocType The associated type being opened. - /// - /// \param memberTypeVar The type variable representing the - /// dependent member type. - /// - /// \param replacementType If the caller sets this to a non-null type, the - /// member type variable will be bound directly to this type. - /// - /// \returns true if the constraint system should introduce a - /// constraint that specifies that the member type is in fact a the - /// named member of the base's type variable. - virtual bool shouldBindAssociatedType(Type baseType, - TypeVariableType *baseTypeVar, - AssociatedTypeDecl *assocType, - TypeVariableType *memberTypeVar, - Type &replacementType) { - return true; - } -}; - - /// An intrusive, doubly-linked list of constraints. typedef llvm::ilist ConstraintList; @@ -1093,6 +835,8 @@ struct MemberLookupResult { /// only have an rvalue base. This is more specific than the former one. UR_MutatingGetterOnRValue, + /// The member is inaccessible (e.g. a private member in another file). + UR_Inaccessible, }; /// This is a list of considered, but rejected, candidates, along with a @@ -1133,19 +877,12 @@ class ConstraintSystem { friend class Fix; friend class OverloadChoice; + friend class ConstraintGraph; class SolverScope; Constraint *failedConstraint = nullptr; - /// \brief Failures that occurred while solving. - /// - /// FIXME: We really need to track overload sets and type variable bindings - /// to make any sense of this data. Also, it probably belongs within - /// SolverState. - llvm::FoldingSetVector failures; - - private: /// \brief Allocator used for all of the related constraint systems. @@ -1173,13 +910,6 @@ class ConstraintSystem { /// constraint system. llvm::FoldingSetVector ConstraintLocators; - /// \brief Folding set containing all of the failures that have occurred - /// while building and initially simplifying this constraint system. - /// - /// These failures are unavoidable, in the sense that they occur before - /// we have made any (potentially incorrect) assumptions at all. - TinyPtrVector unavoidableFailures; - /// \brief The overload sets that have been resolved along the current path. ResolvedOverloadSetListItem *resolvedOverloadSets = nullptr; @@ -1268,7 +998,7 @@ class ConstraintSystem { unsigned depth = 0; /// \brief Whether to record failures or not. - bool recordFailures = false; + bool recordFixes = false; /// The list of constraints that have been retired along the /// current path. @@ -1534,112 +1264,20 @@ class ConstraintSystem { ConstraintLocator * getConstraintLocator(const ConstraintLocatorBuilder &builder); -private: - /// \brief Record failure with already-simplified arguments. - template - void recordFailureSimplified(ConstraintLocator *locator, - Failure::FailureKind kind, - Args &&...args) { - // If there is no solver state, this failure is unavoidable. - if (!solverState) { - auto failure = Failure::create(getAllocator(), locator, kind, - resolvedOverloadSets, - std::forward(args)...); - - // Debug output. - if (getASTContext().LangOpts.DebugConstraintSolver) { - auto &log = getASTContext().TypeCheckerDebug->getStream(); - log.indent(2); - failure->dump(&TC.Context.SourceMgr, log); - } - - unavoidableFailures.push_back(failure); - return; - } - - // Check whether we've recorded this failure already. - llvm::FoldingSetNodeID id; - Failure::Profile(id, locator, kind, resolvedOverloadSets, args...); - void *insertPos = nullptr; - Failure *failure = failures.FindNodeOrInsertPos(id, insertPos); - if (!failure) { - // Allocate a new failure and record it. - failure = Failure::create(getAllocator(), locator, kind, - resolvedOverloadSets, args...); - failures.InsertNode(failure, insertPos); - } - - // Debug output. - if (getASTContext().LangOpts.DebugConstraintSolver) { - auto &log = getASTContext().TypeCheckerDebug->getStream(); - log.indent(solverState->depth * 2 + 2); - failure->dump(&TC.Context.SourceMgr, log); - } - - return; - } - - /// \brief Simplifies an argument to the failure by simplifying the type. - Type simplifyFailureArg(Type type) { - // FIXME: Should also map type variables back to their corresponding - // archetypes here. - return simplifyType(type); - } - - /// \brief Simplifies an argument to the failure by simplifying the type. - Type simplifyFailureArg(TypeBase *type) { - return simplifyType(type); - } - - /// \brief Simplifies an argument to the failure (a no-op). - unsigned simplifyFailureArg(unsigned arg) { - return arg; - } - - /// \brief Simplifies an argument to the failure (a no-op). - DeclName simplifyFailureArg(DeclName arg) { - return arg; - } - public: - /// \brief Whether we should be recording failures. - bool shouldRecordFailures() { - // FIXME: It still makes sense to record failures when there are fixes - // present, but they shold be less desirable. - if (!Fixes.empty()) - return false; - - return !solverState || solverState->recordFailures || - TC.Context.LangOpts.DebugConstraintSolver; - } /// \brief Whether we should attempt to fix problems. bool shouldAttemptFixes() { if (!(Options & ConstraintSystemFlags::AllowFixes)) return false; - return !solverState || solverState->recordFailures; + return !solverState || solverState->recordFixes; } /// \brief Log and record the application of the fix. Return true iff any /// subsequent solution would be worse than the best known solution. bool recordFix(Fix fix, ConstraintLocatorBuilder locator); - - /// \brief Record a failure at the given location with the given kind, - /// along with any additional arguments to be passed to the failure - /// constructor. - template - void recordFailure(ConstraintLocator *locator, Failure::FailureKind kind, - Args &&...args) { - // If we don't want to record failures, don't. - if (!shouldRecordFailures() || - (locator && locator->shouldDiscardFailures())) - return; - - recordFailureSimplified(locator, kind, - simplifyFailureArg(std::forward(args))...); - } - + /// \brief Try to salvage the constraint system by applying (speculative) /// fixes to the underlying expression. /// @@ -1780,7 +1418,8 @@ class ConstraintSystem { /// representatives of their equivalence classes, and must be /// distinct. void mergeEquivalenceClasses(TypeVariableType *typeVar1, - TypeVariableType *typeVar2); + TypeVariableType *typeVar2, + bool updateWorkList = true); /// \brief Retrieve the fixed type corresponding to the given type variable, /// or a null type if there is no fixed type. @@ -1848,13 +1487,11 @@ class ConstraintSystem { /// /// \returns The opened type. Type openType(Type type, ConstraintLocatorBuilder locator, - DeclContext *dc = nullptr, - DependentTypeOpener *opener = nullptr) { + DeclContext *dc = nullptr) { llvm::DenseMap replacements; return openType(type, locator, replacements, dc, /*skipProtocolSelfConstraint=*/false, - /*minOpeningDepth=*/0, - /*opener=*/opener); + /*minOpeningDepth=*/0); } /// \brief "Open" the given type by replacing any occurrences of generic @@ -1874,17 +1511,13 @@ class ConstraintSystem { /// contexts that we're inheriting context archetypes from. See the comment /// on openGeneric(). /// - /// \param opener Abstract class that assists in opening dependent - /// types. - /// /// \returns The opened type, or \c type if there are no archetypes in it. Type openType(Type type, ConstraintLocatorBuilder locator, llvm::DenseMap &replacements, DeclContext *dc = nullptr, bool skipProtocolSelfConstraint = false, - unsigned minOpeningDepth = 0, - DependentTypeOpener *opener = nullptr); + unsigned minOpeningDepth = 0); /// \brief "Open" the given binding type by replacing any occurrences of /// archetypes (including those implicit in unbound generic types) with @@ -1924,7 +1557,6 @@ class ConstraintSystem { ArrayRef requirements, bool skipProtocolSelfConstraint, unsigned minOpeningDepth, - DependentTypeOpener *opener, ConstraintLocatorBuilder locator, llvm::DenseMap &replacements); @@ -1953,8 +1585,7 @@ class ConstraintSystem { bool isTypeReference, bool isSpecialized, ConstraintLocatorBuilder locator, - const DeclRefExpr *base = nullptr, - DependentTypeOpener *opener = nullptr); + const DeclRefExpr *base = nullptr); /// Replace the 'Self' type in the archetype with the appropriate /// type variable, if needed. @@ -1982,7 +1613,8 @@ class ConstraintSystem { bool isDynamicResult, ConstraintLocatorBuilder locator, const DeclRefExpr *base = nullptr, - DependentTypeOpener *opener = nullptr); + llvm::DenseMap + *replacements = nullptr); /// \brief Add a new overload set to the list of unresolved overload /// sets. @@ -2072,7 +1704,7 @@ class ConstraintSystem { /// Indicates we're matching an operator parameter. TMF_ApplyingOperatorParameter = 0x4, - /// Indicates we're unwrapping an optional type for an value-to-optional + /// Indicates we're unwrapping an optional type for a value-to-optional /// conversion. TMF_UnwrappingOptional = 0x8, @@ -2173,9 +1805,14 @@ class ConstraintSystem { /// perform a lookup into the specified base type to find a candidate list. /// The list returned includes the viable candidates as well as the unviable /// ones (along with reasons why they aren't viable). + /// + /// If includeInaccessibleMembers is set to true, this burns compile time to + /// try to identify and classify inaccessible members that may be being + /// referenced. MemberLookupResult performMemberLookup(ConstraintKind constraintKind, DeclName memberName, Type baseTy, - ConstraintLocator *memberLocator); + ConstraintLocator *memberLocator, + bool includeInaccessibleMembers); private: @@ -2426,7 +2063,7 @@ class ConstraintSystem { } /// \brief Reorder the disjunctive clauses for a given expression to - /// increase the likelyhood that a favored constraint will be be successfully + /// increase the likelihood that a favored constraint will be successfully /// resolved before any others. void optimizeConstraints(Expr *e); @@ -2539,7 +2176,7 @@ class MatchCallArgumentListener { /// \param prevArgIdx The argument that the \c argIdx should have preceded. virtual void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx); - /// Indicates that the arguments need to be relabed to match the parameters. + /// Indicates that the arguments need to be relabeled to match the parameters. /// /// \returns true to indicate that this should cause a failure, false /// otherwise. @@ -2596,80 +2233,6 @@ void simplifyLocator(Expr *&anchor, SmallVectorImpl &targetPath, SourceRange &range); -/// Describes the kind of entity to which a locator was resolved. -enum class ResolvedLocatorKind : uint8_t { - /// The locator could not be resolved. - Unresolved, - /// The locator refers to a function. - Function, - /// The locator refers to a constructor. - Constructor, - /// The locator refers to a parameter of a function. - Parameter -}; - -/// The entity to which a locator resolved. -class ResolvedLocator { - ResolvedLocatorKind kind; - ConcreteDeclRef decl; - -public: - ResolvedLocator() : kind(ResolvedLocatorKind::Unresolved) { } - - enum ForFunction_t { ForFunction }; - enum ForConstructor_t { ForConstructor }; - enum ForVar_t { ForVar }; - - ResolvedLocator(ForFunction_t, ConcreteDeclRef decl) - : kind(ResolvedLocatorKind::Function), decl(decl) - { - assert(isa(decl.getDecl())); - } - - ResolvedLocator(ForConstructor_t, ConcreteDeclRef decl) - : kind(ResolvedLocatorKind::Constructor), decl(decl) - { - assert(isa(decl.getDecl())); - } - - ResolvedLocator(ForVar_t, ConcreteDeclRef decl) - : kind(ResolvedLocatorKind::Parameter), decl(decl) - { - assert(isa(decl.getDecl())); - } - - /// Determine the kind of entity to which the locator resolved. - ResolvedLocatorKind getKind() const { return kind; } - - /// Retrieve the declaration to which the locator resolved. - ConcreteDeclRef getDecl() const { return decl; } - - explicit operator bool() const { - return getKind() != ResolvedLocatorKind::Unresolved; - } -}; - -/// Resolve a locator to the specific declaration it references, if possible. -/// -/// \param cs The constraint system in which the locator will be resolved. -/// -/// \param locator The locator to resolve. -/// -/// \param findOvlChoice A function that searches for the overload choice -/// associated with the given locator, or an empty optional if there is no such -/// overload. -/// -/// \returns the entity to which the locator resolved. -/// -/// FIXME: It would be more natural to express the result as a locator. -ResolvedLocator resolveLocatorToDecl( - ConstraintSystem &cs, - ConstraintLocator *locator, - std::function(ConstraintLocator *)> - findOvlChoice, - std::function getConcreteDeclRef); - } // end namespace constraints template diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index e437ff9fc8668..fcb1cf626d139 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -1,8 +1,8 @@ -//===--- DerivedConformanceEquatableHashable.cpp - Derived Equatable & co. ===// +//===--- DerivedConformanceEquatableHashable.cpp - Derived Equatable & co -===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -99,7 +99,7 @@ static DeclRefExpr *convertEnumToIndex(SmallVectorImpl &stmts, auto indexExpr = new (C) IntegerLiteralExpr(StringRef(indexStr.data(), indexStr.size()), SourceLoc(), /*implicit*/ true); - auto indexRef = new (C) DeclRefExpr(indexVar, SourceLoc(), + auto indexRef = new (C) DeclRefExpr(indexVar, DeclNameLoc(), /*implicit*/true); auto assignExpr = new (C) AssignExpr(indexRef, SourceLoc(), indexExpr, /*implicit*/ true); @@ -111,7 +111,7 @@ static DeclRefExpr *convertEnumToIndex(SmallVectorImpl &stmts, } // generate: switch enumVar { } - auto enumRef = new (C) DeclRefExpr(enumVarDecl, SourceLoc(), + auto enumRef = new (C) DeclRefExpr(enumVarDecl, DeclNameLoc(), /*implicit*/true); auto switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(), enumRef, SourceLoc(), cases, SourceLoc(), C); @@ -119,8 +119,8 @@ static DeclRefExpr *convertEnumToIndex(SmallVectorImpl &stmts, stmts.push_back(indexBind); stmts.push_back(switchStmt); - return new (C) DeclRefExpr(indexVar, SourceLoc(), /*implicit*/ true, - AccessSemantics::Ordinary, intType); + return new (C) DeclRefExpr(indexVar, DeclNameLoc(), /*implicit*/ true, + AccessSemantics::Ordinary, intType); } /// Derive the body for an '==' operator for an enum @@ -128,15 +128,9 @@ static void deriveBodyEquatable_enum_eq(AbstractFunctionDecl *eqDecl) { auto parentDC = eqDecl->getDeclContext(); ASTContext &C = parentDC->getASTContext(); - auto args = cast(eqDecl->getBodyParamPatterns().back()); - auto aPattern = args->getElement(0).getPattern(); - auto aParamPattern = - cast(aPattern->getSemanticsProvidingPattern()); - auto aParam = aParamPattern->getDecl(); - auto bPattern = args->getElement(1).getPattern(); - auto bParamPattern = - cast(bPattern->getSemanticsProvidingPattern()); - auto bParam = bParamPattern->getDecl(); + auto args = eqDecl->getParameterLists().back(); + auto aParam = args->get(0); + auto bParam = args->get(1); CanType boolTy = C.getBoolDecl()->getDeclaredType().getCanonicalTypeOrNull(); @@ -160,7 +154,7 @@ static void deriveBodyEquatable_enum_eq(AbstractFunctionDecl *eqDecl) { { }, { }, SourceLoc(), /*HasTrailingClosure*/ false, /*Implicit*/ true, tType); - auto *cmpFuncExpr = new (C) DeclRefExpr(cmpFunc, SourceLoc(), + auto *cmpFuncExpr = new (C) DeclRefExpr(cmpFunc, DeclNameLoc(), /*implicit*/ true, AccessSemantics::Ordinary, cmpFunc->getType()); @@ -200,48 +194,22 @@ deriveEquatable_enum_eq(TypeChecker &tc, Decl *parentDecl, EnumDecl *enumDecl) { auto parentDC = cast(parentDecl); auto enumTy = parentDC->getDeclaredTypeInContext(); - auto getParamPattern = [&](StringRef s) -> std::pair { - VarDecl *aDecl = new (C) ParamDecl(/*isLet*/ true, - SourceLoc(), - Identifier(), - SourceLoc(), - C.getIdentifier(s), - enumTy, - parentDC); - aDecl->setImplicit(); - Pattern *aParam = new (C) NamedPattern(aDecl, /*implicit*/ true); - aParam->setType(enumTy); - aParam = new (C) TypedPattern(aParam, TypeLoc::withoutLoc(enumTy)); - aParam->setType(enumTy); - aParam->setImplicit(); - return {aDecl, aParam}; + auto getParamDecl = [&](StringRef s) -> ParamDecl* { + return new (C) ParamDecl(/*isLet*/true, SourceLoc(), SourceLoc(), + Identifier(), SourceLoc(), C.getIdentifier(s), + enumTy, parentDC); }; - auto aParam = getParamPattern("a"); - auto bParam = getParamPattern("b"); - - TupleTypeElt typeElts[] = { - TupleTypeElt(enumTy), - TupleTypeElt(enumTy) - }; - auto paramsTy = TupleType::get(typeElts, C); - - TuplePatternElt paramElts[] = { - TuplePatternElt(aParam.second), - TuplePatternElt(bParam.second), - }; - auto params = TuplePattern::create(C, SourceLoc(), - paramElts, SourceLoc()); - params->setImplicit(); - params->setType(paramsTy); + auto params = ParameterList::create(C, { + getParamDecl("a"), + getParamDecl("b") + }); auto genericParams = parentDC->getGenericParamsOfContext(); - auto boolTy = C.getBoolDecl()->getDeclaredType(); - auto moduleDC = parentDecl->getModuleContext(); - DeclName name(C, C.Id_EqualsOperator, { Identifier(), Identifier() }); + DeclName name(C, C.Id_EqualsOperator, params); auto eqDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), name, SourceLoc(), SourceLoc(), SourceLoc(), @@ -267,6 +235,7 @@ deriveEquatable_enum_eq(TypeChecker &tc, Decl *parentDecl, EnumDecl *enumDecl) { eqDecl->setBodySynthesizer(&deriveBodyEquatable_enum_eq); // Compute the type. + auto paramsTy = params->getType(C); Type fnTy; if (genericParams) fnTy = PolymorphicFunctionType::get(paramsTy, boolTy, genericParams); @@ -296,11 +265,16 @@ deriveEquatable_enum_eq(TypeChecker &tc, Decl *parentDecl, EnumDecl *enumDecl) { eqDecl->setAccessibility(std::max(enumDecl->getFormalAccess(), Accessibility::Internal)); + // If the enum was not imported, the derived conformance is either from the + // enum itself or an extension, in which case we will emit the declaration + // normally. if (enumDecl->hasClangNode()) - tc.implicitlyDefinedFunctions.push_back(eqDecl); + tc.Context.addExternalDecl(eqDecl); // Since it's an operator we insert the decl after the type at global scope. - return insertOperatorDecl(C, cast(parentDecl), eqDecl); + insertOperatorDecl(C, cast(parentDecl), eqDecl); + + return eqDecl; } ValueDecl *DerivedConformance::deriveEquatable(TypeChecker &tc, @@ -329,20 +303,15 @@ deriveBodyHashable_enum_hashValue(AbstractFunctionDecl *hashValueDecl) { ASTContext &C = parentDC->getASTContext(); auto enumDecl = parentDC->isEnumOrEnumExtensionContext(); - SmallVector statements; - - Pattern *curriedArgs = hashValueDecl->getBodyParamPatterns().front(); - auto selfPattern = - cast(curriedArgs->getSemanticsProvidingPattern()); - auto selfDecl = selfPattern->getDecl(); + auto selfDecl = hashValueDecl->getImplicitSelfDecl(); DeclRefExpr *indexRef = convertEnumToIndex(statements, parentDC, enumDecl, selfDecl, hashValueDecl, "index"); auto memberRef = new (C) UnresolvedDotExpr(indexRef, SourceLoc(), C.Id_hashValue, - SourceLoc(), + DeclNameLoc(), /*implicit*/true); auto returnStmt = new (C) ReturnStmt(SourceLoc(), memberRef); statements.push_back(returnStmt); @@ -373,8 +342,6 @@ deriveHashable_enum_hashValue(TypeChecker &tc, Decl *parentDecl, ASTContext &C = tc.Context; auto parentDC = cast(parentDecl); - - Type enumType = parentDC->getDeclaredTypeInContext(); Type intType = C.getIntDecl()->getDeclaredType(); // We can't form a Hashable conformance if Int isn't Hashable or @@ -393,21 +360,12 @@ deriveHashable_enum_hashValue(TypeChecker &tc, Decl *parentDecl, return nullptr; } - VarDecl *selfDecl = new (C) ParamDecl(/*IsLet*/true, - SourceLoc(), - Identifier(), - SourceLoc(), - C.Id_self, - enumType, - parentDC); - selfDecl->setImplicit(); - Pattern *selfParam = new (C) NamedPattern(selfDecl, /*implicit*/ true); - selfParam->setType(enumType); - selfParam = new (C) TypedPattern(selfParam, TypeLoc::withoutLoc(enumType)); - selfParam->setType(enumType); - Pattern *methodParam = TuplePattern::create(C, SourceLoc(),{},SourceLoc()); - methodParam->setType(TupleType::getEmpty(tc.Context)); - Pattern *params[] = {selfParam, methodParam}; + auto selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC); + + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createEmpty(C) + }; FuncDecl *getterDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), @@ -421,6 +379,8 @@ deriveHashable_enum_hashValue(TypeChecker &tc, Decl *parentDecl, GenericParamList *genericParams = getterDecl->getGenericParamsOfContext(); Type methodType = FunctionType::get(TupleType::getEmpty(tc.Context), intType); Type selfType = getterDecl->computeSelfType(); + selfDecl->overwriteType(selfType); + Type type; if (genericParams) type = PolymorphicFunctionType::get(selfType, methodType, genericParams); @@ -441,8 +401,11 @@ deriveHashable_enum_hashValue(TypeChecker &tc, Decl *parentDecl, getterDecl->setInterfaceType(interfaceType); getterDecl->setAccessibility(enumDecl->getFormalAccess()); + // If the enum was not imported, the derived conformance is either from the + // enum itself or an extension, in which case we will emit the declaration + // normally. if (enumDecl->hasClangNode()) - tc.implicitlyDefinedFunctions.push_back(getterDecl); + tc.Context.addExternalDecl(getterDecl); // Create the property. VarDecl *hashValueDecl = new (C) VarDecl(/*static*/ false, diff --git a/lib/Sema/DerivedConformanceErrorType.cpp b/lib/Sema/DerivedConformanceErrorType.cpp index 741f0819272b3..99c7b32ef3bf8 100644 --- a/lib/Sema/DerivedConformanceErrorType.cpp +++ b/lib/Sema/DerivedConformanceErrorType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -147,11 +147,10 @@ static ValueDecl *deriveErrorType_code(TypeChecker &tc, Decl *parentDecl, ASTContext &C = tc.Context; auto intTy = C.getIntDecl()->getDeclaredType(); - Type nominalType = cast(parentDecl)->getDeclaredTypeInContext(); // Define the getter. auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, nominal, - nominalType, intTy, intTy); + intTy, intTy); if (isa(nominal)) getterDecl->setBodySynthesizer(&deriveBodyErrorType_enum_code); else @@ -225,11 +224,10 @@ static ValueDecl *deriveBridgedNSError_enum_NSErrorDomain(TypeChecker &tc, ASTContext &C = tc.Context; auto stringTy = C.getStringDecl()->getDeclaredType(); - Type enumType = enumDecl->getDeclaredTypeInContext(); // Define the getter. auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, enumDecl, - enumType, stringTy, stringTy, + stringTy, stringTy, /*isStatic=*/true); getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_NSErrorDomain); diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index f85a2641c2eea..de9d4ae779973 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -130,11 +130,8 @@ static VarDecl *deriveRawRepresentable_raw(TypeChecker &tc, auto rawInterfaceType = enumDecl->getRawType(); auto rawType = ArchetypeBuilder::mapTypeIntoContext(parentDC, rawInterfaceType); - Type enumType = parentDC->getDeclaredTypeInContext(); - // Define the getter. auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, enumDecl, - enumType, rawInterfaceType, rawType); getterDecl->setBodySynthesizer(&deriveBodyRawRepresentable_raw); @@ -204,11 +201,12 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl) { auto labelItem = CaseLabelItem(/*IsDefault=*/false, litPat, SourceLoc(), nullptr); - auto eltRef = new (C) DeclRefExpr(elt, SourceLoc(), /*implicit*/true); + auto eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit*/true); auto metaTyRef = TypeExpr::createImplicit(enumType, C); auto valueExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef); - auto selfRef = new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/true, + auto selfRef = new (C) DeclRefExpr(selfDecl, DeclNameLoc(), + /*implicit*/true, AccessSemantics::DirectToStorage); auto assignment = new (C) AssignExpr(selfRef, SourceLoc(), valueExpr, @@ -234,10 +232,8 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl) { /*HasBoundDecls=*/false, SourceLoc(), dfltBody)); - Pattern *args = initDecl->getBodyParamPatterns().back(); - auto rawArgPattern = cast(args->getSemanticsProvidingPattern()); - auto rawDecl = rawArgPattern->getDecl(); - auto rawRef = new (C) DeclRefExpr(rawDecl, SourceLoc(), /*implicit*/true); + auto rawDecl = initDecl->getParameterList(1)->get(0); + auto rawRef = new (C) DeclRefExpr(rawDecl, DeclNameLoc(), /*implicit*/true); auto switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(), rawRef, SourceLoc(), cases, SourceLoc(), C); auto body = BraceStmt::create(C, SourceLoc(), @@ -270,49 +266,22 @@ static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc, } Type enumType = parentDC->getDeclaredTypeInContext(); - VarDecl *selfDecl = new (C) ParamDecl(/*IsLet*/false, - SourceLoc(), - Identifier(), - SourceLoc(), - C.Id_self, - enumType, - parentDC); - selfDecl->setImplicit(); - Pattern *selfParam = new (C) NamedPattern(selfDecl, /*implicit*/ true); - selfParam->setType(enumType); - selfParam = new (C) TypedPattern(selfParam, - TypeLoc::withoutLoc(enumType)); - selfParam->setType(enumType); - selfParam->setImplicit(); - - VarDecl *rawDecl = new (C) ParamDecl(/*IsVal*/true, - SourceLoc(), - C.Id_rawValue, - SourceLoc(), - C.Id_rawValue, - rawType, - parentDC); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC, + /*static*/false, /*inout*/true); + + auto *rawDecl = new (C) ParamDecl(/*IsLet*/true, SourceLoc(), SourceLoc(), + C.Id_rawValue, SourceLoc(), + C.Id_rawValue, rawType, parentDC); rawDecl->setImplicit(); - Pattern *rawParam = new (C) NamedPattern(rawDecl, /*implicit*/ true); - rawParam->setType(rawType); - rawParam = new (C) TypedPattern(rawParam, TypeLoc::withoutLoc(rawType)); - rawParam->setType(rawType); - rawParam->setImplicit(); - rawParam = new (C) ParenPattern(SourceLoc(), rawParam, SourceLoc()); - rawParam->setType(rawType); - rawParam->setImplicit(); + auto paramList = ParameterList::createWithoutLoc(rawDecl); auto retTy = OptionalType::get(enumType); - DeclName name(C, C.Id_init, { C.Id_rawValue }); + DeclName name(C, C.Id_init, paramList); auto initDecl = new (C) ConstructorDecl(name, SourceLoc(), /*failability*/ OTK_Optional, - SourceLoc(), - selfParam, - rawParam, - nullptr, - SourceLoc(), - parentDC); + SourceLoc(), selfDecl, paramList, + nullptr, SourceLoc(), parentDC); initDecl->setImplicit(); initDecl->setBodySynthesizer(&deriveBodyRawRepresentable_init); @@ -328,6 +297,7 @@ static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc, Type type = FunctionType::get(argType, retTy); Type selfType = initDecl->computeSelfType(); + selfDecl->overwriteType(selfType); Type selfMetatype = MetatypeType::get(selfType->getInOutObjectType()); Type allocType; @@ -367,8 +337,11 @@ static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc, initDecl->setInitializerInterfaceType(initIfaceType); initDecl->setAccessibility(enumDecl->getFormalAccess()); + // If the enum was not imported, the derived conformance is either from the + // enum itself or an extension, in which case we will emit the declaration + // normally. if (enumDecl->hasClangNode()) - tc.implicitlyDefinedFunctions.push_back(initDecl); + tc.Context.addExternalDecl(initDecl); cast(parentDecl)->addMember(initDecl); return initDecl; diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index fcee5ebb24c5c..534bfd22c08cf 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,7 +40,7 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, // Retrieve the requirement. auto results = proto->lookupDirect(name); - return results.empty() ? nullptr : results.front(); + return results.empty() ? nullptr : results.front(); }; // Properties. @@ -93,9 +93,9 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, return nullptr; } -void DerivedConformance::_insertOperatorDecl(ASTContext &C, - IterableDeclContext *scope, - Decl *member) { +void DerivedConformance::insertOperatorDecl(ASTContext &C, + IterableDeclContext *scope, + Decl *member) { // Find the module. auto mod = member->getModuleContext(); @@ -117,45 +117,24 @@ DeclRefExpr * DerivedConformance::createSelfDeclRef(AbstractFunctionDecl *fn) { ASTContext &C = fn->getASTContext(); - Pattern *curriedArgs = fn->getBodyParamPatterns().front(); - auto selfPattern = - cast(curriedArgs->getSemanticsProvidingPattern()); - auto selfDecl = selfPattern->getDecl(); - return new (C) DeclRefExpr(selfDecl, SourceLoc(), /*implicit*/true); + auto selfDecl = fn->getImplicitSelfDecl(); + return new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true); } FuncDecl *DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl, - Type contextType, Type propertyInterfaceType, Type propertyContextType, bool isStatic) { auto &C = tc.Context; - - Type selfType = contextType; - if (isStatic) - selfType = MetatypeType::get(selfType); - auto parentDC = cast(parentDecl); - - VarDecl *selfDecl = new (C) ParamDecl(/*IsLet*/true, - SourceLoc(), - Identifier(), - SourceLoc(), - C.Id_self, - selfType, - parentDC); - selfDecl->setImplicit(); - Pattern *selfParam = new (C) NamedPattern(selfDecl, /*implicit*/ true); - selfParam->setType(selfType); - selfParam = new (C) TypedPattern(selfParam, - TypeLoc::withoutLoc(selfType)); - selfParam->setType(selfType); - Pattern *methodParam = TuplePattern::create(C, SourceLoc(),{},SourceLoc()); - methodParam->setType(TupleType::getEmpty(C)); - Pattern *params[] = {selfParam, methodParam}; - + auto selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC, isStatic); + ParameterList *params[] = { + ParameterList::createWithoutLoc(selfDecl), + ParameterList::createEmpty(C) + }; + FuncDecl *getterDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, SourceLoc(), DeclName(), SourceLoc(), SourceLoc(), SourceLoc(), @@ -168,7 +147,9 @@ FuncDecl *DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc, GenericParamList *genericParams = getterDecl->getGenericParamsOfContext(); Type type = FunctionType::get(TupleType::getEmpty(C), propertyContextType); - selfType = getterDecl->computeSelfType(); + Type selfType = getterDecl->computeSelfType(); + selfDecl->overwriteType(selfType); + if (genericParams) type = PolymorphicFunctionType::get(selfType, type, genericParams); else @@ -189,8 +170,11 @@ FuncDecl *DerivedConformance::declareDerivedPropertyGetter(TypeChecker &tc, getterDecl->setInterfaceType(interfaceType); getterDecl->setAccessibility(typeDecl->getFormalAccess()); - if (typeDecl->hasClangNode()) - tc.implicitlyDefinedFunctions.push_back(getterDecl); + // If the enum was not imported, the derived conformance is either from the + // enum itself or an extension, in which case we will emit the declaration + // normally. + if (parentDecl->hasClangNode()) + tc.Context.addExternalDecl(getterDecl); return getterDecl; } @@ -207,8 +191,7 @@ DerivedConformance::declareDerivedReadOnlyProperty(TypeChecker &tc, auto &C = tc.Context; auto parentDC = cast(parentDecl); - VarDecl *propDecl = new (C) VarDecl(isStatic, - /*let*/ false, + VarDecl *propDecl = new (C) VarDecl(isStatic, /*let*/ false, SourceLoc(), name, propertyContextType, parentDC); diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index d2d302819405a..08ecf7d531c76 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -109,25 +109,14 @@ ValueDecl *deriveBridgedNSError(TypeChecker &tc, /// Insert an operator declaration associated with a declaration /// context. The operator declaration is added at global scope. -void _insertOperatorDecl(ASTContext &C, - IterableDeclContext *scope, - Decl *member); - -/// Insert an operator declaration associated with a declaration -/// context. The operator declaration is added at global scope. -template -inline SomeDecl *insertOperatorDecl(ASTContext &C, - IterableDeclContext *scope, - SomeDecl *member) { - ::swift::DerivedConformance::_insertOperatorDecl(C, scope, member); - return member; -} +void insertOperatorDecl(ASTContext &C, + IterableDeclContext *scope, + Decl *member); /// Declare a getter for a derived property. FuncDecl *declareDerivedPropertyGetter(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl, - Type contextType, Type propertyInterfaceType, Type propertyContextType, bool isStatic = false); diff --git a/lib/Sema/GenericTypeResolver.h b/lib/Sema/GenericTypeResolver.h index a69bfe23b7b3b..3a3bb5822803e 100644 --- a/lib/Sema/GenericTypeResolver.h +++ b/lib/Sema/GenericTypeResolver.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/ITCDecl.cpp b/lib/Sema/ITCDecl.cpp index 086f272691c70..1371b77b31bc0 100644 --- a/lib/Sema/ITCDecl.cpp +++ b/lib/Sema/ITCDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,9 +22,9 @@ #include using namespace swift; -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Inheritance clause handling -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// static std::tuple> decomposeInheritedClauseDecl( @@ -116,9 +116,9 @@ bool IterativeTypeChecker::breakCycleForResolveInheritedClauseEntry( return true; } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Superclass handling -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isTypeCheckSuperclassSatisfied(ClassDecl *payload) { return payload->LazySemanticInfo.Superclass.getInt(); } @@ -162,9 +162,9 @@ bool IterativeTypeChecker::breakCycleForTypeCheckSuperclass( return true; } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Raw type handling -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isTypeCheckRawTypeSatisfied(EnumDecl *payload) { return payload->LazySemanticInfo.RawType.getInt(); } @@ -205,9 +205,9 @@ bool IterativeTypeChecker::breakCycleForTypeCheckRawType(EnumDecl *enumDecl) { return true; } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Inherited protocols -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isInheritedProtocolsSatisfied(ProtocolDecl *payload){ return payload->isInheritedProtocolsValid(); } @@ -280,9 +280,9 @@ bool IterativeTypeChecker::breakCycleForInheritedProtocols( return true; } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Resolve a type declaration -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isResolveTypeDeclSatisfied(TypeDecl *typeDecl) { if (auto typeAliasDecl = dyn_cast(typeDecl)) { // If the underlying type was validated, we're done. diff --git a/lib/Sema/ITCNameLookup.cpp b/lib/Sema/ITCNameLookup.cpp index 880d1460b8ea5..87ab7256d3682 100644 --- a/lib/Sema/ITCNameLookup.cpp +++ b/lib/Sema/ITCNameLookup.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,9 +21,9 @@ #include using namespace swift; -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Qualified name lookup handling -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isQualifiedLookupInDeclContextSatisfied( TypeCheckRequest::DeclContextLookupPayloadType payload) { auto dc = payload.DC; @@ -35,6 +35,7 @@ bool IterativeTypeChecker::isQualifiedLookupInDeclContextSatisfied( case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::SerializedLocal: + case DeclContextKind::SubscriptDecl: llvm_unreachable("not a DeclContext that supports name lookup"); case DeclContextKind::Module: @@ -122,15 +123,16 @@ bool IterativeTypeChecker::breakCycleForQualifiedLookupInDeclContext( return false; } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Qualified name lookup handling -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isUnqualifiedLookupInDeclContextSatisfied( TypeCheckRequest::DeclContextLookupPayloadType payload) { auto dc = payload.DC; switch (dc->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::SerializedLocal: diff --git a/lib/Sema/ITCType.cpp b/lib/Sema/ITCType.cpp index 1d7ccd3391123..8a8c4bdfc859d 100644 --- a/lib/Sema/ITCType.cpp +++ b/lib/Sema/ITCType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,12 +18,13 @@ #include "TypeChecker.h" #include "swift/Sema/IterativeTypeChecker.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" using namespace swift; -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Type resolution. -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// bool IterativeTypeChecker::isResolveTypeReprSatisfied( std::tuple payload) { auto typeRepr = std::get<0>(payload); diff --git a/lib/Sema/IterativeTypeChecker.cpp b/lib/Sema/IterativeTypeChecker.cpp index 061c36e34460e..0cd26e9788ef4 100644 --- a/lib/Sema/IterativeTypeChecker.cpp +++ b/lib/Sema/IterativeTypeChecker.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -112,9 +112,9 @@ void IterativeTypeChecker::satisfy(TypeCheckRequest request) { } } -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// // Diagnostics -//----------------------------------------------------------------------------// +//===----------------------------------------------------------------------===// void IterativeTypeChecker::diagnoseCircularReference( ArrayRef requests) { bool isFirst = true; diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 781fa734c416d..621f3ce92f302 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,9 +25,9 @@ #include "llvm/ADT/MapVector.h" using namespace swift; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Diagnose assigning variable to itself. -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// static Decl *findSimpleReferencedDecl(const Expr *E) { if (auto *LE = dyn_cast(E)) @@ -437,8 +437,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, isa(ParentExpr) || // T.foo() T() isa(ParentExpr) || isa(ParentExpr) || - isa(ParentExpr) || - isa(ParentExpr) || isa(ParentExpr) || isa(ParentExpr)) { return; @@ -490,7 +488,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, TC.diagnose(DRE->getLoc(), diag::warn_unqualified_access, VD->getName(), VD->getDescriptiveKind(), declParent->getDescriptiveKind(), declParent->getFullName()); - TC.diagnose(VD, diag::decl_declared_here, VD->getName()); + TC.diagnose(VD, diag::decl_declared_here, VD->getFullName()); if (VD->getDeclContext()->isTypeContext()) { TC.diagnose(DRE->getLoc(), diag::fix_unqualified_access_member) @@ -677,8 +675,8 @@ static void diagnoseImplicitSelfUseInClosure(TypeChecker &TC, const Expr *E, /// Return true if this is an implicit reference to self. static bool isImplicitSelfUse(Expr *E) { auto *DRE = dyn_cast(E); - return DRE && DRE->isImplicit() && DRE->getDecl()->hasName() && - DRE->getDecl()->getName().str() == "self" && + return DRE && DRE->isImplicit() && isa(DRE->getDecl()) && + cast(DRE->getDecl())->isSelfParameter() && // Metatype self captures don't extend the lifetime of an object. !DRE->getType()->is(); } @@ -771,63 +769,15 @@ static void diagnoseImplicitSelfUseInClosure(TypeChecker &TC, const Expr *E, const_cast(E)->walk(DiagnoseWalker(TC, isAlreadyInClosure)); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Diagnose availability. -//===--------------------------------------------------------------------===// - -static void tryFixPrintWithAppendNewline(const ValueDecl *D, - const Expr *ParentExpr, - InFlightDiagnostic &Diag) { - if (!D || !ParentExpr) - return; - if (!D->getModuleContext()->isStdlibModule()) - return; - - DeclName Name = D->getFullName(); - if (Name.getBaseName().str() != "print") - return; - auto ArgNames = Name.getArgumentNames(); - if (ArgNames.size() != 2) - return; - if (ArgNames[1].empty() || ArgNames[1].str() != "appendNewline") - return; - - // Go through the expr to determine if second parameter is boolean literal. - auto *CE = dyn_cast_or_null(ParentExpr); - if (!CE) - return; - auto *TE = dyn_cast(CE->getArg()); - if (!TE) - return; - if (TE->getNumElements() != 2) - return; - auto *SCE = dyn_cast(TE->getElement(1)); - if (!SCE || !SCE->isImplicit()) - return; - auto *STE = dyn_cast(SCE->getArg()); - if (!STE || !STE->isImplicit()) - return; - if (STE->getNumElements() != 1) - return; - auto *BE = dyn_cast(STE->getElement(0)); - if (!BE) - return; - - SmallString<20> termStr = StringRef("terminator: \""); - if (BE->getValue()) - termStr += "\\n"; - termStr += "\""; - - SourceRange RangeToFix(TE->getElementNameLoc(1), BE->getEndLoc()); - Diag.fixItReplace(RangeToFix, termStr); -} +//===----------------------------------------------------------------------===// /// Emit a diagnostic for references to declarations that have been /// marked as unavailable, either through "unavailable" or "obsoleted=". bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R, - const DeclContext *DC, - const Expr *ParentExpr) { + const DeclContext *DC) { auto *Attr = AvailableAttr::isUnavailable(D); if (!Attr) return false; @@ -865,9 +815,9 @@ bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D, diagnose(Loc, diag::availability_decl_unavailable, Name).highlight(R); } else { EncodedDiagnosticMessage EncodedMessage(Attr->Message); - tryFixPrintWithAppendNewline(D, ParentExpr, - diagnose(Loc, diag::availability_decl_unavailable_msg, Name, - EncodedMessage.Message).highlight(R)); + diagnose(Loc, diag::availability_decl_unavailable_msg, Name, + EncodedMessage.Message) + .highlight(R); } break; @@ -905,35 +855,6 @@ bool TypeChecker::diagnoseExplicitUnavailability(const ValueDecl *D, return true; } -/// Diagnose uses of unavailable declarations. Returns true if a diagnostic -/// was emitted. -static bool diagAvailability(TypeChecker &TC, const ValueDecl *D, - SourceRange R, const DeclContext *DC, - const Expr *ParentExpr = nullptr) { - if (!D) - return false; - - if (TC.diagnoseExplicitUnavailability(D, R, DC, ParentExpr)) - return true; - - // Diagnose for deprecation - if (const AvailableAttr *Attr = TypeChecker::getDeprecated(D)) { - TC.diagnoseDeprecated(R, DC, Attr, D->getFullName()); - } - - if (TC.getLangOpts().DisableAvailabilityChecking) { - return false; - } - - // Diagnose for potential unavailability - auto maybeUnavail = TC.checkDeclarationAvailability(D, R.Start, DC); - if (maybeUnavail.hasValue()) { - TC.diagnosePotentialUnavailability(D, R, DC, maybeUnavail.getValue()); - return true; - } - return false; -} - namespace { class AvailabilityWalker : public ASTWalker { /// Describes how the next member reference will be treated as we traverse @@ -954,13 +875,13 @@ class AvailabilityWalker : public ASTWalker { }; TypeChecker &TC; - const DeclContext *DC; + DeclContext *DC; const MemberAccessContext AccessContext; SmallVector ExprStack; public: AvailabilityWalker( - TypeChecker &TC, const DeclContext *DC, + TypeChecker &TC, DeclContext *DC, MemberAccessContext AccessContext = MemberAccessContext::Getter) : TC(TC), DC(DC), AccessContext(AccessContext) {} @@ -974,21 +895,22 @@ class AvailabilityWalker : public ASTWalker { }; if (auto DR = dyn_cast(E)) - diagAvailability(TC, DR->getDecl(), DR->getSourceRange(), DC, - getParentForDeclRef()); + diagAvailability(DR->getDecl(), DR->getSourceRange()); if (auto MR = dyn_cast(E)) { walkMemberRef(MR); return skipChildren(); } if (auto OCDR = dyn_cast(E)) - diagAvailability(TC, OCDR->getDecl(), OCDR->getConstructorLoc(), DC); + diagAvailability(OCDR->getDecl(), + OCDR->getConstructorLoc().getSourceRange()); if (auto DMR = dyn_cast(E)) - diagAvailability(TC, DMR->getMember().getDecl(), DMR->getNameLoc(), DC); + diagAvailability(DMR->getMember().getDecl(), + DMR->getNameLoc().getSourceRange()); if (auto DS = dyn_cast(E)) - diagAvailability(TC, DS->getMember().getDecl(), DS->getSourceRange(), DC); + diagAvailability(DS->getMember().getDecl(), DS->getSourceRange()); if (auto S = dyn_cast(E)) { if (S->hasDecl()) - diagAvailability(TC, S->getDecl().getDecl(), S->getSourceRange(), DC); + diagAvailability(S->getDecl().getDecl(), S->getSourceRange()); } if (auto A = dyn_cast(E)) { walkAssignExpr(A); @@ -1010,6 +932,10 @@ class AvailabilityWalker : public ASTWalker { } private: + bool diagAvailability(const ValueDecl *D, SourceRange R); + bool diagnoseIncDecDeprecation(const ValueDecl *D, SourceRange R, + const AvailableAttr *Attr); + /// Walk an assignment expression, checking for availability. void walkAssignExpr(AssignExpr *E) const { // We take over recursive walking of assignment expressions in order to @@ -1042,13 +968,11 @@ class AvailabilityWalker : public ASTWalker { ValueDecl *D = E->getMember().getDecl(); // Diagnose for the member declaration itself. - if (diagAvailability(TC, D, E->getNameLoc(), DC)) { + if (diagAvailability(D, E->getNameLoc().getSourceRange())) return; - } - if (TC.getLangOpts().DisableAvailabilityChecking) { + if (TC.getLangOpts().DisableAvailabilityChecking) return; - } if (auto *ASD = dyn_cast(D)) { // Diagnose for appropriate accessors, given the access context. @@ -1113,54 +1037,128 @@ class AvailabilityWalker : public ASTWalker { ForInout); } } +}; +} - const Expr *getParentForDeclRef() { - assert(isa(ExprStack.back())); - ArrayRef Stack = ExprStack; - Stack = Stack.drop_back(); - if (Stack.empty()) - return nullptr; +/// Diagnose uses of unavailable declarations. Returns true if a diagnostic +/// was emitted. +bool AvailabilityWalker::diagAvailability(const ValueDecl *D, SourceRange R) { + if (!D) + return false; - if (isa(Stack.back())) - Stack = Stack.drop_back(); - if (Stack.empty()) - return nullptr; - - return Stack.back(); + if (TC.diagnoseExplicitUnavailability(D, R, DC)) + return true; + + // Diagnose for deprecation + if (const AvailableAttr *Attr = TypeChecker::getDeprecated(D)) { + if (!diagnoseIncDecDeprecation(D, R, Attr)) + TC.diagnoseDeprecated(R, DC, Attr, D->getFullName()); } -}; + + if (TC.getLangOpts().DisableAvailabilityChecking) + return false; + + // Diagnose for potential unavailability + auto maybeUnavail = TC.checkDeclarationAvailability(D, R.Start, DC); + if (maybeUnavail.hasValue()) { + TC.diagnosePotentialUnavailability(D, R, DC, maybeUnavail.getValue()); + return true; + } + return false; } -/// Diagnose uses of unavailable declarations. -static void diagAvailability(TypeChecker &TC, const Expr *E, - const DeclContext *DC) { - AvailabilityWalker walker(TC, DC); - const_cast(E)->walk(walker); + +/// Return true if the specified type looks like an integer of floating point +/// type. +static bool isIntegerOrFloatingPointType(Type ty, DeclContext *DC, + TypeChecker &TC) { + auto integerType = + TC.getProtocol(SourceLoc(), + KnownProtocolKind::IntegerLiteralConvertible); + auto floatingType = + TC.getProtocol(SourceLoc(), + KnownProtocolKind::FloatLiteralConvertible); + if (!integerType || !floatingType) return false; + + return + TC.conformsToProtocol(ty, integerType, DC, + ConformanceCheckFlags::InExpression) || + TC.conformsToProtocol(ty, floatingType, DC, + ConformanceCheckFlags::InExpression); } -//===--------------------------------------------------------------------===// -// High-level entry points. -//===--------------------------------------------------------------------===// -/// \brief Emit diagnostics for syntactic restrictions on a given expression. -void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E, - const DeclContext *DC, - bool isExprStmt) { - diagSelfAssignment(TC, E); - diagSyntacticUseRestrictions(TC, E, DC, isExprStmt); - diagRecursivePropertyAccess(TC, E, DC); - diagnoseImplicitSelfUseInClosure(TC, E, DC); - diagAvailability(TC, E, DC); +/// If this is a call to a deprecated ++ / -- operator, try to diagnose it with +/// a fixit hint and return true. If not, or if we fail, return false. +bool AvailabilityWalker::diagnoseIncDecDeprecation(const ValueDecl *D, + SourceRange R, + const AvailableAttr *Attr) { + // We can only produce a fixit if we're talking about ++ or --. + bool isInc = D->getNameStr() == "++"; + if (!isInc && D->getNameStr() != "--") + return false; + + // We can only handle the simple cases of lvalue++ and ++lvalue. This is + // always modeled as: + // (postfix_unary_expr (declrefexpr ++), (inoutexpr (lvalue))) + // if not, bail out. + if (ExprStack.size() != 2 || + !isa(ExprStack[1]) || + !(isa(ExprStack[0]) || + isa(ExprStack[0]))) + return false; + + auto call = cast(ExprStack[0]); + + // If the expression type is integer or floating point, then we can rewrite it + // to "lvalue += 1". + std::string replacement; + if (isIntegerOrFloatingPointType(call->getType(), DC, TC)) + replacement = isInc ? " += 1" : " -= 1"; + else { + // Otherwise, it must be an index type. Rewrite to: + // "lvalue = lvalue.successor()". + auto &SM = TC.Context.SourceMgr; + auto CSR = Lexer::getCharSourceRangeFromSourceRange(SM, + call->getArg()->getSourceRange()); + replacement = " = " + SM.extractText(CSR).str(); + replacement += isInc ? ".successor()" : ".predecessor()"; + } + + if (!replacement.empty()) { + // If we emit a deprecation diagnostic, produce a fixit hint as well. + TC.diagnoseDeprecated(R, DC, Attr, D->getFullName(), + [&](InFlightDiagnostic &diag) { + if (isa(call)) { + // Prefix: remove the ++ or --. + diag.fixItRemove(call->getFn()->getSourceRange()); + diag.fixItInsertAfter(call->getArg()->getEndLoc(), replacement); + } else { + // Postfix: replace the ++ or --. + diag.fixItReplace(call->getFn()->getSourceRange(), replacement); + } + }); + + return true; + } + + + return false; } -void swift::performStmtDiagnostics(TypeChecker &TC, const Stmt *S) { - TC.checkUnsupportedProtocolType(const_cast(S)); + + +/// Diagnose uses of unavailable declarations. +static void diagAvailability(TypeChecker &TC, const Expr *E, + DeclContext *DC) { + AvailabilityWalker walker(TC, DC); + const_cast(E)->walk(walker); } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Per func/init diagnostics -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// namespace { class VarDeclUsageChecker : public ASTWalker { @@ -1195,13 +1193,22 @@ class VarDeclUsageChecker : public ASTWalker { public: VarDeclUsageChecker(TypeChecker &TC, AbstractFunctionDecl *AFD) : TC(TC) { // Track the parameters of the function. - for (auto P : AFD->getBodyParamPatterns()) - P->forEachVariable([&](VarDecl *VD) { - if (shouldTrackVarDecl(VD)) - VarDecls[VD] = 0; - }); + for (auto PL : AFD->getParameterLists()) + for (auto param : *PL) + if (shouldTrackVarDecl(param)) + VarDecls[param] = 0; + } - + + VarDeclUsageChecker(TypeChecker &TC, VarDecl *VD) : TC(TC) { + // Track a specific VarDecl + VarDecls[VD] = 0; + } + + void suppressDiagnostics() { + sawError = true; // set this flag so that no diagnostics will be emitted on delete. + } + // After we have scanned the entire region, diagnose variables that could be // declared with a narrower usage kind. ~VarDeclUsageChecker(); @@ -1224,6 +1231,10 @@ class VarDeclUsageChecker : public ASTWalker { } return sawMutation; } + + bool isVarDeclEverWritten(VarDecl *VD) { + return (VarDecls[VD] & RK_Written) != 0; + } bool shouldTrackVarDecl(VarDecl *VD) { // If the variable is implicit, ignore it. @@ -1481,17 +1492,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { } // If this is a parameter explicitly marked 'var', remove it. - if (auto *param = dyn_cast(var)) - if (auto *pattern = param->getParamParentPattern()) - if (auto *vp = dyn_cast(pattern)) { - TC.diagnose(var->getLoc(), diag::variable_never_mutated, - var->getName(), /*param*/1) - .fixItRemove(vp->getLoc()); - continue; - } - unsigned varKind = isa(var); - // FIXME: fixit when we can find a pattern binding. if (FixItLoc.isInvalid()) TC.diagnose(var->getLoc(), diag::variable_never_mutated, var->getName(), varKind); @@ -1689,12 +1690,528 @@ void swift::performAbstractFuncDeclDiagnostics(TypeChecker &TC, AFD->getBody()->walk(VarDeclUsageChecker(TC, AFD)); } +/// Diagnose C style for loops. + +static Expr *endConditionValueForConvertingCStyleForLoop(const ForStmt *FS, VarDecl *loopVar) { + auto *Cond = FS->getCond().getPtrOrNull(); + if (!Cond) + return nullptr; + auto callExpr = dyn_cast(Cond); + if (!callExpr) + return nullptr; + auto dotSyntaxExpr = dyn_cast(callExpr->getFn()); + if (!dotSyntaxExpr) + return nullptr; + auto binaryExpr = dyn_cast(dotSyntaxExpr->getBase()); + if (!binaryExpr) + return nullptr; + auto binaryFuncExpr = dyn_cast(binaryExpr->getFn()); + if (!binaryFuncExpr) + return nullptr; + + // Verify that the condition is a simple != or < comparison to the loop variable. + auto comparisonOpName = binaryFuncExpr->getDecl()->getNameStr(); + if (comparisonOpName != "!=" && comparisonOpName != "<") + return nullptr; + auto args = binaryExpr->getArg()->getElements(); + auto loadExpr = dyn_cast(args[0]); + if (!loadExpr) + return nullptr; + auto declRefExpr = dyn_cast(loadExpr->getSubExpr()); + if (!declRefExpr) + return nullptr; + if (declRefExpr->getDecl() != loopVar) + return nullptr; + return args[1]; +} + +static bool unaryIncrementForConvertingCStyleForLoop(const ForStmt *FS, VarDecl *loopVar) { + auto *Increment = FS->getIncrement().getPtrOrNull(); + if (!Increment) + return false; + ApplyExpr *unaryExpr = dyn_cast(Increment); + if (!unaryExpr) + unaryExpr = dyn_cast(Increment); + if (!unaryExpr) + return false; + auto inoutExpr = dyn_cast(unaryExpr->getArg()); + if (!inoutExpr) + return false; + auto incrementDeclRefExpr = dyn_cast(inoutExpr->getSubExpr()); + if (!incrementDeclRefExpr) + return false; + auto unaryFuncExpr = dyn_cast(unaryExpr->getFn()); + if (!unaryFuncExpr) + return false; + if (unaryFuncExpr->getDecl()->getNameStr() != "++") + return false; + return incrementDeclRefExpr->getDecl() == loopVar; +} + +static bool plusEqualOneIncrementForConvertingCStyleForLoop(TypeChecker &TC, const ForStmt *FS, VarDecl *loopVar) { + auto *Increment = FS->getIncrement().getPtrOrNull(); + if (!Increment) + return false; + ApplyExpr *binaryExpr = dyn_cast(Increment); + if (!binaryExpr) + return false; + auto binaryFuncExpr = dyn_cast(binaryExpr->getFn()); + if (!binaryFuncExpr) + return false; + if (binaryFuncExpr->getDecl()->getNameStr() != "+=") + return false; + auto argTupleExpr = dyn_cast(binaryExpr->getArg()); + if (!argTupleExpr) + return false; + auto addOneConstExpr = argTupleExpr->getElement(1); + + // Rather than unwrapping expressions all the way down implicit constructors, etc, just check that the + // source text for the += argument is "1". + SourceLoc constEndLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, addOneConstExpr->getEndLoc()); + auto range = CharSourceRange(TC.Context.SourceMgr, addOneConstExpr->getStartLoc(), constEndLoc); + if (range.str() != "1") + return false; + + auto inoutExpr = dyn_cast(argTupleExpr->getElement(0)); + if (!inoutExpr) + return false; + auto declRefExpr = dyn_cast(inoutExpr->getSubExpr()); + if (!declRefExpr) + return false; + return declRefExpr->getDecl() == loopVar; +} + +static void checkCStyleForLoop(TypeChecker &TC, const ForStmt *FS) { + // If we're missing semi-colons we'll already be erroring out, and this may not even have been intended as C-style. + if (FS->getFirstSemicolonLoc().isInvalid() || FS->getSecondSemicolonLoc().isInvalid()) + return; + + InFlightDiagnostic diagnostic = TC.diagnose(FS->getStartLoc(), diag::deprecated_c_style_for_stmt); + + // Try to construct a fix it using for-each: + + // Verify that there is only one loop variable, and it is declared here. + auto initializers = FS->getInitializerVarDecls(); + PatternBindingDecl *loopVarDecl = initializers.size() == 2 ? dyn_cast(initializers[0]) : nullptr; + if (!loopVarDecl || loopVarDecl->getNumPatternEntries() != 1) + return; + VarDecl *loopVar = dyn_cast(initializers[1]); + Expr *startValue = loopVarDecl->getInit(0); + Expr *endValue = endConditionValueForConvertingCStyleForLoop(FS, loopVar); + bool strideByOne = unaryIncrementForConvertingCStyleForLoop(FS, loopVar) || + plusEqualOneIncrementForConvertingCStyleForLoop(TC, FS, loopVar); + if (!loopVar || !startValue || !endValue || !strideByOne) + return; + + // Verify that the loop variable is invariant inside the body. + VarDeclUsageChecker checker(TC, loopVar); + checker.suppressDiagnostics(); + FS->getBody()->walk(checker); + + if (checker.isVarDeclEverWritten(loopVar)) { + diagnostic.flush(); + TC.diagnose(FS->getStartLoc(), diag::cant_fix_c_style_for_stmt); + return; + } + + SourceLoc loopPatternEnd = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, loopVarDecl->getPattern(0)->getEndLoc()); + SourceLoc endOfIncrementLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, FS->getIncrement().getPtrOrNull()->getEndLoc()); + + diagnostic + .fixItRemoveChars(loopVarDecl->getLoc(), loopVar->getLoc()) + .fixItReplaceChars(loopPatternEnd, startValue->getStartLoc(), " in ") + .fixItReplaceChars(FS->getFirstSemicolonLoc(), endValue->getStartLoc(), " ..< ") + .fixItRemoveChars(FS->getSecondSemicolonLoc(), endOfIncrementLoc); +} -//===--------------------------------------------------------------------===// +static Optional +parseObjCSelector(ASTContext &ctx, StringRef string) { + // Find the first colon. + auto colonPos = string.find(':'); + + // If there is no colon, we have a nullary selector. + if (colonPos == StringRef::npos) { + if (string.empty() || !Lexer::isIdentifier(string)) return None; + return ObjCSelector(ctx, 0, { ctx.getIdentifier(string) }); + } + + SmallVector pieces; + do { + // Check whether we have a valid selector piece. + auto piece = string.substr(0, colonPos); + if (piece.empty()) { + pieces.push_back(Identifier()); + } else { + if (!Lexer::isIdentifier(piece)) return None; + pieces.push_back(ctx.getIdentifier(piece)); + } + + // Move to the next piece. + string = string.substr(colonPos+1); + colonPos = string.find(':'); + } while (colonPos != StringRef::npos); + + // If anything remains of the string, it's not a selector. + if (!string.empty()) return None; + + return ObjCSelector(ctx, pieces.size(), pieces); +} + + +namespace { + +class ObjCSelectorWalker : public ASTWalker { + TypeChecker &TC; + const DeclContext *DC; + Type SelectorTy; + + /// Determine whether a reference to the given method via its + /// enclosing class/protocol is ambiguous (and, therefore, needs to + /// be disambiguated with a coercion). + bool isSelectorReferenceAmbiguous(AbstractFunctionDecl *method) { + // Determine the name we would search for. If there are no + // argument names, our lookup will be based solely on the base + // name. + DeclName lookupName = method->getFullName(); + if (lookupName.getArgumentNames().empty()) + lookupName = lookupName.getBaseName(); + + // Look for members with the given name. + auto nominal = + method->getDeclContext()->isNominalTypeOrNominalTypeExtensionContext(); + auto result = TC.lookupMember(const_cast(DC), + nominal->getInterfaceType(), lookupName, + (defaultMemberLookupOptions | + NameLookupFlags::KnownPrivate)); + + // If we didn't find multiple methods, there is no ambiguity. + if (result.size() < 2) return false; + + // If we found more than two methods, it's ambiguous. + if (result.size() > 2) return true; + + // Dig out the methods. + auto firstMethod = dyn_cast(result[0].Decl); + auto secondMethod = dyn_cast(result[1].Decl); + if (!firstMethod || !secondMethod) return true; + + // If one is a static/class method and the other is not... + if (firstMethod->isStatic() == secondMethod->isStatic()) return true; + + // ... overload resolution will prefer the static method. Check + // that it has the correct selector. We don't even care that it's + // the same method we're asking for, just that it has the right + // selector. + FuncDecl *staticMethod = + firstMethod->isStatic() ? firstMethod : secondMethod; + return staticMethod->getObjCSelector() != method->getObjCSelector(); + } + +public: + ObjCSelectorWalker(TypeChecker &tc, const DeclContext *dc, Type selectorTy) + : TC(tc), DC(dc), SelectorTy(selectorTy) { } + + virtual std::pair walkToExprPre(Expr *expr) override { + // Only diagnose calls. + auto call = dyn_cast(expr); + if (!call) return { true, expr }; + + // That produce Selectors. + if (!call->getType() || !call->getType()->isEqual(SelectorTy)) + return { true, expr }; + + // Via a constructor. + ConstructorDecl *ctor = nullptr; + if (auto ctorRefCall = dyn_cast(call->getFn())) { + if (auto ctorRef = dyn_cast(ctorRefCall->getFn())) + ctor = dyn_cast(ctorRef->getDecl()); + else if (auto otherCtorRef = + dyn_cast(ctorRefCall->getFn())) + ctor = otherCtorRef->getDecl(); + } + + if (!ctor) return { true, expr }; + + // Make sure the constructor is within Selector. + auto ctorContextType = ctor->getDeclContext()->getDeclaredTypeOfContext(); + if (!ctorContextType || !ctorContextType->isEqual(SelectorTy)) + return { true, expr }; + + auto argNames = ctor->getFullName().getArgumentNames(); + if (argNames.size() != 1) return { true, expr }; + + // Is this the init(stringLiteral:) initializer or init(_:) initializer? + bool fromStringLiteral = false; + if (argNames[0] == TC.Context.Id_stringLiteral) + fromStringLiteral = true; + else if (!argNames[0].empty()) + return { true, expr }; + + // Dig out the argument. + Expr *arg = call->getArg()->getSemanticsProvidingExpr(); + if (auto tupleExpr = dyn_cast(arg)) { + if (tupleExpr->getNumElements() == 1 && + tupleExpr->getElementName(0) == TC.Context.Id_stringLiteral) + arg = tupleExpr->getElement(0)->getSemanticsProvidingExpr(); + } + + // If the argument is a call, it might be to + // init(__builtinStringLiteral:byteSize:isASCII:). If so, dig + // through that. + if (auto argCall = dyn_cast(arg)) { + if (auto ctorRefCall = + dyn_cast(argCall->getFn())) { + if (auto argCtor = + dyn_cast_or_null(ctorRefCall->getCalledValue())){ + auto argArgumentNames = argCtor->getFullName().getArgumentNames(); + if (argArgumentNames.size() == 3 && + argArgumentNames[0] == TC.Context.Id_builtinStringLiteral) { + arg = argCall->getArg()->getSemanticsProvidingExpr(); + } + } + } + } + + // Check whether we have a string literal. + auto stringLiteral = dyn_cast(arg); + if (!stringLiteral) return { true, expr }; + + /// Retrieve the parent expression that coerces to Selector, if + /// there is one. + auto getParentCoercion = [&]() -> CoerceExpr * { + auto parentExpr = Parent.getAsExpr(); + if (!parentExpr) return nullptr; + + auto coerce = dyn_cast(parentExpr); + if (!coerce) return nullptr; + + if (coerce->getType() && coerce->getType()->isEqual(SelectorTy)) + return coerce; + + return nullptr; + }; + + // Local function that adds the constructor syntax around string + // literals implicitly treated as a Selector. + auto addSelectorConstruction = [&](InFlightDiagnostic &diag) { + if (!fromStringLiteral) return; + + // Introduce the beginning part of the Selector construction. + diag.fixItInsert(stringLiteral->getLoc(), "Selector("); + + if (auto coerce = getParentCoercion()) { + // If the string literal was coerced to Selector, replace the + // coercion with the ")". + SourceLoc endLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, + expr->getEndLoc()); + diag.fixItReplace(SourceRange(endLoc, coerce->getEndLoc()), ")"); + } else { + // Otherwise, just insert the closing ")". + diag.fixItInsertAfter(stringLiteral->getEndLoc(), ")"); + } + }; + + // Try to parse the string literal as an Objective-C selector, and complain + // if it isn't one. + auto selector = parseObjCSelector(TC.Context, stringLiteral->getValue()); + if (!selector) { + auto diag = TC.diagnose(stringLiteral->getLoc(), + diag::selector_literal_invalid); + diag.highlight(stringLiteral->getSourceRange()); + addSelectorConstruction(diag); + return { true, expr }; + } + + // Look for methods with this selector. + SmallVector allMethods; + DC->lookupAllObjCMethods(*selector, allMethods); + + // If we didn't find any methods, complain. + if (allMethods.empty()) { + auto diag = + TC.diagnose(stringLiteral->getLoc(), diag::selector_literal_undeclared, + *selector); + addSelectorConstruction(diag); + return { true, expr }; + } + + // Separate out the accessor methods. + auto splitPoint = + std::stable_partition(allMethods.begin(), allMethods.end(), + [](AbstractFunctionDecl *abstractFunc) -> bool { + if (auto func = dyn_cast(abstractFunc)) + return !func->isAccessor(); + + return true; + }); + ArrayRef methods(allMethods.begin(), splitPoint); + ArrayRef accessors(splitPoint, allMethods.end()); + + // Find the "best" method that has this selector, so we can report + // that. + AbstractFunctionDecl *bestMethod = nullptr; + for (auto method : methods) { + // If this is the first method, use it. + if (!bestMethod) { + bestMethod = method; + continue; + } + + // If referencing the best method would produce an ambiguity and + // referencing the new method would not, we have a new "best". + if (isSelectorReferenceAmbiguous(bestMethod) && + !isSelectorReferenceAmbiguous(method)) { + bestMethod = method; + continue; + } + + // If this method is within a protocol... + if (auto proto = + method->getDeclContext()->isProtocolOrProtocolExtensionContext()) { + // If the best so far is not from a protocol, or is from a + // protocol that inherits this protocol, we have a new best. + auto bestProto = bestMethod->getDeclContext() + ->isProtocolOrProtocolExtensionContext(); + if (!bestProto || bestProto->inheritsFrom(proto)) + bestMethod = method; + continue; + } + + // This method is from a class. + auto classDecl = + method->getDeclContext()->isClassOrClassExtensionContext(); + + // If the best method was from a protocol, keep it. + auto bestClassDecl = + bestMethod->getDeclContext()->isClassOrClassExtensionContext(); + if (!bestClassDecl) continue; + + // If the best method was from a subclass of the place where + // this method was declared, we have a new best. + while (auto superclassTy = bestClassDecl->getSuperclass()) { + auto superclassDecl = superclassTy->getClassOrBoundGenericClass(); + if (!superclassDecl) break; + + if (classDecl == superclassDecl) { + bestMethod = method; + break; + } + + bestClassDecl = superclassDecl; + } + } + + // If we have a best method, reference it. + if (bestMethod) { + // Form the replacement #selector expression. + SmallString<32> replacement; + { + llvm::raw_svector_ostream out(replacement); + auto nominal = bestMethod->getDeclContext() + ->isNominalTypeOrNominalTypeExtensionContext(); + auto name = bestMethod->getFullName(); + out << "#selector(" << nominal->getName().str() << "." + << name.getBaseName().str(); + auto argNames = name.getArgumentNames(); + + // Only print the parentheses if there are some argument + // names, because "()" would indicate a call. + if (argNames.size() > 0) { + out << "("; + for (auto argName : argNames) { + if (argName.empty()) out << "_"; + else out << argName.str(); + out << ":"; + } + out << ")"; + } + + // If there will be an ambiguity when referring to the method, + // introduce a coercion to resolve it to the method we found. + if (isSelectorReferenceAmbiguous(bestMethod)) { + if (auto fnType = + bestMethod->getInterfaceType()->getAs()) { + // For static/class members, drop the metatype argument. + if (bestMethod->isStatic()) + fnType = fnType->getResult()->getAs(); + + // Drop the argument labels. + // FIXME: They never should have been in the type anyway. + Type type = fnType->getUnlabeledType(TC.Context); + + // Coerce to this type. + out << " as "; + type.print(out); + } + } + + out << ")"; + } + + // Emit the diagnostic. + SourceRange replacementRange = expr->getSourceRange(); + if (auto coerce = getParentCoercion()) + replacementRange.End = coerce->getEndLoc(); + + TC.diagnose(expr->getLoc(), + fromStringLiteral ? diag::selector_literal_deprecated_suggest + : diag::selector_construction_suggest) + .fixItReplace(replacementRange, replacement); + return { true, expr }; + } + + // If we couldn't pick a method to use for #selector, just wrap + // the string literal in Selector(...). + if (fromStringLiteral) { + auto diag = TC.diagnose(stringLiteral->getLoc(), + diag::selector_literal_deprecated); + addSelectorConstruction(diag); + return { true, expr }; + } + + return { true, expr }; + } + +}; +} + +static void diagDeprecatedObjCSelectors(TypeChecker &tc, const DeclContext *dc, + const Expr *expr) { + auto selectorTy = tc.getObjCSelectorType(const_cast(dc)); + if (!selectorTy) return; + + const_cast(expr)->walk(ObjCSelectorWalker(tc, dc, selectorTy)); +} + +//===----------------------------------------------------------------------===// +// High-level entry points. +//===----------------------------------------------------------------------===// + +/// \brief Emit diagnostics for syntactic restrictions on a given expression. +void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E, + const DeclContext *DC, + bool isExprStmt) { + diagSelfAssignment(TC, E); + diagSyntacticUseRestrictions(TC, E, DC, isExprStmt); + diagRecursivePropertyAccess(TC, E, DC); + diagnoseImplicitSelfUseInClosure(TC, E, DC); + diagAvailability(TC, E, const_cast(DC)); + if (TC.Context.LangOpts.EnableObjCInterop) + diagDeprecatedObjCSelectors(TC, DC, E); +} + +void swift::performStmtDiagnostics(TypeChecker &TC, const Stmt *S) { + TC.checkUnsupportedProtocolType(const_cast(S)); + + if (auto forStmt = dyn_cast(S)) + checkCStyleForLoop(TC, forStmt); +} + +//===----------------------------------------------------------------------===// // Utility functions -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD, Accessibility desiredAccess, bool isForSetter) { @@ -1890,22 +2407,13 @@ static Optional omitNeedlessWords(AbstractFunctionDecl *afd) { // String'ify the parameter types. SmallVector paramTypes; - Type functionType = afd->getInterfaceType(); - Type argumentType; - for (unsigned i = 0, n = afd->getNaturalArgumentCount()-1; i != n; ++i) - functionType = functionType->getAs()->getResult(); - argumentType = functionType->getAs()->getInput(); - if (auto tupleTy = argumentType->getAs()) { - if (tupleTy->getNumElements() == argNameStrs.size()) { - for (const auto &elt : tupleTy->getElements()) - paramTypes.push_back(getTypeNameForOmission(elt.getType()) - .withDefaultArgument(elt.hasDefaultArg())); - } - } - - if (argNameStrs.size() == 1 && paramTypes.empty()) - paramTypes.push_back(getTypeNameForOmission(argumentType)); + // Always look at the parameters in the last parameter list. + for (auto param : *afd->getParameterLists().back()) { + paramTypes.push_back(getTypeNameForOmission(param->getType()) + .withDefaultArgument(param->isDefaultArgument())); + } + // Handle contextual type, result type, and returnsSelf. Type contextType = afd->getDeclContext()->getDeclaredInterfaceType(); Type resultType; @@ -1921,18 +2429,9 @@ static Optional omitNeedlessWords(AbstractFunctionDecl *afd) { // Figure out the first parameter name. StringRef firstParamName; - unsigned skipBodyPatterns = afd->getImplicitSelfDecl() ? 1 : 0; - auto bodyPattern = afd->getBodyParamPatterns()[skipBodyPatterns]; - if (auto tuplePattern = dyn_cast(bodyPattern)) { - if (tuplePattern->getNumElements() > 0) { - auto firstParam = tuplePattern->getElement(0).getPattern(); - if (auto named = dyn_cast( - firstParam->getSemanticsProvidingPattern())) { - if (!named->getBodyName().empty()) - firstParamName = named->getBodyName().str(); - } - } - } + auto params = afd->getParameterList(afd->getImplicitSelfDecl() ? 1 : 0); + if (params->size() != 0 && !params->get(0)->getName().empty()) + firstParamName = params->get(0)->getName().str(); // Find the set of property names. const InheritedNameSet *allPropertyNames = nullptr; @@ -2045,57 +2544,12 @@ void TypeChecker::checkOmitNeedlessWords(VarDecl *var) { .fixItReplace(var->getLoc(), newName->str()); } -/// Determine the "fake" default argument provided by the given expression. -static Optional getDefaultArgForExpr(Expr *expr) { - // Empty array literals, []. - if (auto arrayExpr = dyn_cast(expr)) { - if (arrayExpr->getElements().empty()) - return StringRef("[]"); - - return None; - } - - // nil. - if (auto call = dyn_cast(expr)) { - if (auto ctorRefCall = dyn_cast(call->getFn())) { - if (auto ctorRef = dyn_cast(ctorRefCall->getFn())) { - if (auto ctor = dyn_cast(ctorRef->getDecl())) { - if (ctor->getFullName().getArgumentNames().size() == 1 && - ctor->getFullName().getArgumentNames()[0] - == ctor->getASTContext().Id_nilLiteral) - return StringRef("nil"); - } - } - } - } - - return None; -} - -namespace { - struct CallEdit { - enum { - RemoveDefaultArg, - Rename, - } Kind; - - // The source range affected by this change. - SourceRange Range; - - // The replacement text, for a rename. - std::string Name; - }; - -} - /// Find the source ranges of extraneous default arguments within a /// call to the given function. -static bool hasExtraneousDefaultArguments( - AbstractFunctionDecl *afd, - Expr *arg, - DeclName name, - SmallVectorImpl &ranges, - SmallVectorImpl &removedArgs) { +static bool hasExtraneousDefaultArguments(AbstractFunctionDecl *afd, + Expr *arg, DeclName name, + SmallVectorImpl &ranges, + SmallVectorImpl &removedArgs) { if (!afd->getClangDecl()) return false; @@ -2107,133 +2561,124 @@ static bool hasExtraneousDefaultArguments( TupleExpr *argTuple = dyn_cast(arg); ParenExpr *argParen = dyn_cast(arg); - - ArrayRef bodyPatterns = afd->getBodyParamPatterns(); - - // Skip over the implicit 'self'. - if (afd->getImplicitSelfDecl()) { - bodyPatterns = bodyPatterns.slice(1); - } - + ASTContext &ctx = afd->getASTContext(); - Pattern *bodyPattern = bodyPatterns[0]; - if (auto *tuple = dyn_cast(bodyPattern)) { - Optional firstRemoved; - Optional lastRemoved; - unsigned numElementsInParens; - if (argTuple) { - numElementsInParens = (argTuple->getNumElements() - - argTuple->hasTrailingClosure()); - } else if (argParen) { - numElementsInParens = 1 - argParen->hasTrailingClosure(); - } else { - numElementsInParens = 0; - } - - for (unsigned i = 0; i != numElementsInParens; ++i) { - auto &elt = tuple->getElements()[i]; - if (elt.getDefaultArgKind() == DefaultArgumentKind::None) - continue; + // Skip over the implicit 'self'. + auto *bodyParams = afd->getParameterList(afd->getImplicitSelfDecl()?1:0); - auto defaultArg - = elt.getPattern()->getType()->getInferredDefaultArgString(); + Optional firstRemoved; + Optional lastRemoved; + unsigned numElementsInParens; + if (argTuple) { + numElementsInParens = (argTuple->getNumElements() - + argTuple->hasTrailingClosure()); + } else if (argParen) { + numElementsInParens = 1 - argParen->hasTrailingClosure(); + } else { + numElementsInParens = 0; + } - // Never consider removing the first argument for a "set" method - // with an unnamed first argument. - if (i == 0 && - !name.getBaseName().empty() && - camel_case::getFirstWord(name.getBaseName().str()) == "set" && - name.getArgumentNames().size() > 0 && - name.getArgumentNames()[0].empty()) - continue; + for (unsigned i = 0; i != numElementsInParens; ++i) { + auto param = bodyParams->get(i); + if (!param->isDefaultArgument()) + continue; - SourceRange removalRange; - if (argTuple && i < argTuple->getNumElements()) { - // Check whether we have a default argument. - auto exprArg = getDefaultArgForExpr(argTuple->getElement(i)); - if (!exprArg || defaultArg != *exprArg) - continue; + auto defaultArg = param->getDefaultArgumentKind(); - // Figure out where to start removing this argument. - if (i == 0) { - // Start removing right after the opening parenthesis. - removalRange.Start = argTuple->getLParenLoc(); - } else { - // Start removing right after the preceding argument, so we - // consume the comma as well. - removalRange.Start = argTuple->getElement(i-1)->getEndLoc(); - } + // Never consider removing the first argument for a "set" method + // with an unnamed first argument. + if (i == 0 && + !name.getBaseName().empty() && + camel_case::getFirstWord(name.getBaseName().str()) == "set" && + name.getArgumentNames().size() > 0 && + name.getArgumentNames()[0].empty()) + continue; - // Adjust to the end of the starting token. - removalRange.Start - = Lexer::getLocForEndOfToken(ctx.SourceMgr, removalRange.Start); - - // Figure out where to finish removing this element. - if (i == 0 && i < numElementsInParens - 1) { - // We're the first of several arguments; consume the - // following comma as well. - removalRange.End = argTuple->getElementNameLoc(i+1); - if (removalRange.End.isInvalid()) - removalRange.End = argTuple->getElement(i+1)->getStartLoc(); - } else if (i < numElementsInParens - 1) { - // We're in the middle; consume through the end of this - // element. - removalRange.End - = Lexer::getLocForEndOfToken(ctx.SourceMgr, - argTuple->getElement(i)->getEndLoc()); - } else { - // We're at the end; consume up to the closing parentheses. - removalRange.End = argTuple->getRParenLoc(); - } - } else if (argParen) { - // Check whether we have a default argument. - auto exprArg = getDefaultArgForExpr(argParen->getSubExpr()); - if (!exprArg || defaultArg != *exprArg) - continue; + SourceRange removalRange; + if (argTuple && i < argTuple->getNumElements()) { + // Check whether the supplied argument is the same as the + // default argument. + if (defaultArg != inferDefaultArgumentKind(argTuple->getElement(i))) + continue; - removalRange = SourceRange(argParen->getSubExpr()->getStartLoc(), - argParen->getRParenLoc()); + // Figure out where to start removing this argument. + if (i == 0) { + // Start removing right after the opening parenthesis. + removalRange.Start = argTuple->getLParenLoc(); } else { - continue; + // Start removing right after the preceding argument, so we + // consume the comma as well. + removalRange.Start = argTuple->getElement(i-1)->getEndLoc(); } - if (removalRange.isInvalid()) + // Adjust to the end of the starting token. + removalRange.Start + = Lexer::getLocForEndOfToken(ctx.SourceMgr, removalRange.Start); + + // Figure out where to finish removing this element. + if (i == 0 && i < numElementsInParens - 1) { + // We're the first of several arguments; consume the + // following comma as well. + removalRange.End = argTuple->getElementNameLoc(i+1); + if (removalRange.End.isInvalid()) + removalRange.End = argTuple->getElement(i+1)->getStartLoc(); + } else if (i < numElementsInParens - 1) { + // We're in the middle; consume through the end of this + // element. + removalRange.End + = Lexer::getLocForEndOfToken(ctx.SourceMgr, + argTuple->getElement(i)->getEndLoc()); + } else { + // We're at the end; consume up to the closing parentheses. + removalRange.End = argTuple->getRParenLoc(); + } + } else if (argParen) { + // Check whether we have a default argument. + if (defaultArg != inferDefaultArgumentKind(argParen->getSubExpr())) continue; - // Note that we're removing this argument. - removedArgs.push_back(i); + removalRange = SourceRange(argParen->getSubExpr()->getStartLoc(), + argParen->getRParenLoc()); + } else { + continue; + } - // If we hadn't removed anything before, this is the first - // removal. - if (!firstRemoved) { - ranges.push_back(removalRange); - firstRemoved = i; - lastRemoved = i; - continue; - } + if (removalRange.isInvalid()) + continue; - // If the previous removal range was the previous argument, - // combine the ranges. - if (*lastRemoved == i - 1) { - ranges.back().End = removalRange.End; - lastRemoved = i; - continue; - } + // Note that we're removing this argument. + removedArgs.push_back(i); - // Otherwise, add this new removal range. + // If we hadn't removed anything before, this is the first + // removal. + if (!firstRemoved) { ranges.push_back(removalRange); + firstRemoved = i; lastRemoved = i; + continue; } - // If there is a single removal range that covers everything but - // the trailing closure at the end, also zap the parentheses. - if (ranges.size() == 1 && - *firstRemoved == 0 && *lastRemoved == tuple->getNumElements() - 2 && - argTuple && argTuple->hasTrailingClosure()) { - ranges.front().Start = argTuple->getLParenLoc(); - ranges.front().End - = Lexer::getLocForEndOfToken(ctx.SourceMgr, argTuple->getRParenLoc()); + // If the previous removal range was the previous argument, + // combine the ranges. + if (*lastRemoved == i - 1) { + ranges.back().End = removalRange.End; + lastRemoved = i; + continue; } + + // Otherwise, add this new removal range. + ranges.push_back(removalRange); + lastRemoved = i; + } + + // If there is a single removal range that covers everything but + // the trailing closure at the end, also zap the parentheses. + if (ranges.size() == 1 && + *firstRemoved == 0 && *lastRemoved == bodyParams->size() - 2 && + argTuple && argTuple->hasTrailingClosure()) { + ranges.front().Start = argTuple->getLParenLoc(); + ranges.front().End + = Lexer::getLocForEndOfToken(ctx.SourceMgr, argTuple->getRParenLoc()); } return !ranges.empty(); @@ -2373,5 +2818,5 @@ void TypeChecker::checkOmitNeedlessWords(MemberRefExpr *memberRef) { // Fix the name. auto name = var->getName(); diagnose(memberRef->getNameLoc(), diag::omit_needless_words, name, *newName) - .fixItReplace(memberRef->getNameLoc(), newName->str()); + .fixItReplace(memberRef->getNameLoc().getSourceRange(), newName->str()); } diff --git a/lib/Sema/MiscDiagnostics.h b/lib/Sema/MiscDiagnostics.h index de5d97c100235..c821d8a20c685 100644 --- a/lib/Sema/MiscDiagnostics.h +++ b/lib/Sema/MiscDiagnostics.h @@ -1,8 +1,8 @@ -//===--- MiscDiagnostics.h - AST-Level Diagnostics ------------------------===// +//===--- MiscDiagnostics.h - AST-Level Diagnostics --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 86d6aba94b504..f6c8b99b137dc 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -253,7 +253,7 @@ void NameBinder::addImport( if (decls.size() == 1) diagnose(decls.front(), diag::decl_declared_here, - decls.front()->getName()); + decls.front()->getFullName()); } } } diff --git a/lib/Sema/OverloadChoice.cpp b/lib/Sema/OverloadChoice.cpp index f647b09fbecd6..8eb4d4754142d 100644 --- a/lib/Sema/OverloadChoice.cpp +++ b/lib/Sema/OverloadChoice.cpp @@ -1,8 +1,8 @@ -//===--- OverloadChoice.cpp - A Choice from an Overload Set ----*- C++ -*-===// +//===--- OverloadChoice.cpp - A Choice from an Overload Set --------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/OverloadChoice.h b/lib/Sema/OverloadChoice.h index 7c2e9744f83ac..53d19c03be889 100644 --- a/lib/Sema/OverloadChoice.h +++ b/lib/Sema/OverloadChoice.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 319db048f173b..35467e98a88c3 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -59,7 +59,7 @@ class Instrumenter { std::mt19937_64 &RNG; ASTContext &Context; DeclContext *TypeCheckDC; - unsigned TmpNameIndex = 0; + unsigned &TmpNameIndex; bool HighPerformance; struct BracePair { @@ -170,10 +170,11 @@ class Instrumenter { ClosureFinder CF; public: - Instrumenter (ASTContext &C, DeclContext *DC, std::mt19937_64 &RNG, - bool HP) : - RNG(RNG), Context(C), TypeCheckDC(DC), HighPerformance(HP), CF(*this) { } - + Instrumenter(ASTContext &C, DeclContext *DC, std::mt19937_64 &RNG, bool HP, + unsigned &TmpNameIndex) + : RNG(RNG), Context(C), TypeCheckDC(DC), TmpNameIndex(TmpNameIndex), + HighPerformance(HP), CF(*this) {} + Stmt *transformStmt(Stmt *S) { switch (S->getKind()) { default: @@ -354,7 +355,7 @@ class Instrumenter { ValueDecl *D = cast(E)->getDecl(); Added DRE = new (Context) DeclRefExpr(ConcreteDeclRef(D), - cast(E)->getLoc(), + cast(E)->getNameLoc(), true, // implicit AccessSemantics::Ordinary, cast(E)->getType()); @@ -370,7 +371,7 @@ class Instrumenter { new (Context) MemberRefExpr(*BaseVariable.first, cast(E)->getDotLoc(), ConcreteDeclRef(M), - cast(E)->getSourceRange(), + cast(E)->getNameLoc(), true, // implicit AccessSemantics::Ordinary)); return std::make_pair(MRE, M); @@ -530,7 +531,7 @@ class Instrumenter { buildPatternAndVariable(AE->getSrc()); DeclRefExpr *DRE = new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, AE->getSrc()->getType()); @@ -544,7 +545,7 @@ class Instrumenter { Added Log(buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, AE->getSrc()->getType()), @@ -625,7 +626,7 @@ class Instrumenter { buildPatternAndVariable(E); Added Log = buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, E->getType()), @@ -637,15 +638,14 @@ class Instrumenter { EI += 2; } } - } - else { + } else { if (E->getType()->getCanonicalType() != Context.TheEmptyTupleType) { std::pair PV = buildPatternAndVariable(E); Added Log = buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, E->getType()), @@ -666,7 +666,7 @@ class Instrumenter { buildPatternAndVariable(RS->getResult()); DeclRefExpr *DRE = new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, RS->getResult()->getType()); @@ -675,7 +675,7 @@ class Instrumenter { true); // implicit Added Log = buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, RS->getResult()->getType()), @@ -750,7 +750,7 @@ class Instrumenter { return buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(VD), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, Type()), @@ -768,7 +768,7 @@ class Instrumenter { return buildLoggerCall( new (Context) DeclRefExpr(ConcreteDeclRef(VD), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, Type()), @@ -787,7 +787,7 @@ class Instrumenter { new (Context) MemberRefExpr(B, SourceLoc(), M, - SourceRange(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary), MRE->getSourceRange(), M.getDecl()->getName().str().str().c_str()); @@ -803,7 +803,7 @@ class Instrumenter { std::pair PV = buildPatternAndVariable(PE->getSubExpr()); PE->setSubExpr(new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, PE->getSubExpr()->getType())); @@ -832,7 +832,7 @@ class Instrumenter { TE->setElement(0, new (Context) DeclRefExpr( ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, TE->getElement(0)->getType())); @@ -842,7 +842,7 @@ class Instrumenter { buildPatternAndVariable(TE); Print->setArg(new (Context) DeclRefExpr( ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, TE->getType())); @@ -864,7 +864,7 @@ class Instrumenter { new (Context) UnresolvedDeclRefExpr( Context.getIdentifier(LoggerName), DeclRefKind::Ordinary, - AE->getSourceRange().End); + DeclNameLoc(AE->getSourceRange().End)); std::tie(ArgPattern, ArgVariable) = maybeFixupPrintArgument(AE); @@ -897,8 +897,7 @@ class Instrumenter { dyn_cast(InitExpr->getType().getPointer())) { MaybeLoadInitExpr = new (Context) LoadExpr (InitExpr, LVT->getObjectType()); - } - else { + } else { MaybeLoadInitExpr = InitExpr; } @@ -984,7 +983,7 @@ class Instrumenter { new (Context) UnresolvedDeclRefExpr( Context.getIdentifier(LoggerName), DeclRefKind::Ordinary, - SR.End); + DeclNameLoc(SR.End)); LoggerRef->setImplicit(true); @@ -1034,7 +1033,7 @@ class Instrumenter { buildPatternAndVariable(*Apply); DeclRefExpr *DRE = new (Context) DeclRefExpr(ConcreteDeclRef(PV.second), - SourceLoc(), + DeclNameLoc(), true, // implicit AccessSemantics::Ordinary, Apply->getType()); @@ -1053,7 +1052,7 @@ class Instrumenter { new (Context) UnresolvedDeclRefExpr( Context.getIdentifier("$builtin_send_data"), DeclRefKind::Ordinary, - SourceLoc()); + DeclNameLoc()); SendDataRef->setImplicit(true); @@ -1087,15 +1086,16 @@ void swift::performPlaygroundTransform(SourceFile &SF, private: std::mt19937_64 RNG; bool HighPerformance; + unsigned TmpNameIndex = 0; public: - ExpressionFinder(bool HP) : HighPerformance(HP) { } + ExpressionFinder(bool HP) : HighPerformance(HP) {} virtual bool walkToDeclPre(Decl *D) { if (AbstractFunctionDecl *FD = dyn_cast(D)) { if (!FD->isImplicit()) { if (BraceStmt *Body = FD->getBody()) { ASTContext &ctx = FD->getASTContext(); - Instrumenter I(ctx, FD, RNG, HighPerformance); + Instrumenter I(ctx, FD, RNG, HighPerformance, TmpNameIndex); BraceStmt *NewBody = I.transformBraceStmt(Body); if (NewBody != Body) { FD->setBody(NewBody); @@ -1108,7 +1108,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, if (!TLCD->isImplicit()) { if (BraceStmt *Body = TLCD->getBody()) { ASTContext &ctx = static_cast(TLCD)->getASTContext(); - Instrumenter I(ctx, TLCD, RNG, HighPerformance); + Instrumenter I(ctx, TLCD, RNG, HighPerformance, TmpNameIndex); BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index 1445c53df3cea..09e5f0e04e4da 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -1,8 +1,8 @@ -//===--- SourceLoader.cpp - Import .swift files as modules ------*- c++ -*-===// +//===--- SourceLoader.cpp - Import .swift files as modules ----------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -106,6 +106,8 @@ Module *SourceLoader::loadModule(SourceLoc importLoc, bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(inputFile)); auto *importMod = Module::create(moduleID.first, Ctx); + if (EnableResilience) + importMod->setResilienceEnabled(true); Ctx.LoadedModules[moduleID.first] = importMod; auto implicitImportKind = SourceFile::ImplicitModuleImportKind::Stdlib; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 2ffa0897493b1..79fd18d78500f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -70,6 +70,7 @@ class AttributeEarlyChecker : public AttributeVisitor { IGNORED_ATTR(RequiresStoredPropertyInits) IGNORED_ATTR(Rethrows) IGNORED_ATTR(Semantics) + IGNORED_ATTR(Swift3Migration) IGNORED_ATTR(SwiftNativeObjCRuntimeBase) IGNORED_ATTR(SynthesizedProtocol) IGNORED_ATTR(Testable) @@ -643,6 +644,7 @@ class AttributeChecker : public AttributeVisitor { IGNORED_ATTR(SynthesizedProtocol) IGNORED_ATTR(RequiresStoredPropertyInits) IGNORED_ATTR(SILStored) + IGNORED_ATTR(Swift3Migration) IGNORED_ATTR(Testable) IGNORED_ATTR(WarnUnqualifiedAccess) #undef IGNORED_ATTR @@ -683,8 +685,8 @@ class AttributeChecker : public AttributeVisitor { static bool checkObjectOrOptionalObjectType(TypeChecker &TC, Decl *D, - const Pattern *argPattern) { - Type ty = argPattern->getType(); + ParamDecl *param) { + Type ty = param->getType(); if (auto unwrapped = ty->getAnyOptionalObjectType()) ty = unwrapped; @@ -692,8 +694,8 @@ static bool checkObjectOrOptionalObjectType(TypeChecker &TC, Decl *D, // @objc class types are okay. if (!classDecl->isObjC()) { TC.diagnose(D, diag::ibaction_nonobjc_class_argument, - argPattern->getType()) - .highlight(argPattern->getSourceRange()); + param->getType()) + .highlight(param->getSourceRange()); return true; } } else if (ty->isObjCExistentialType()) { @@ -702,8 +704,8 @@ static bool checkObjectOrOptionalObjectType(TypeChecker &TC, Decl *D, } else { // No other types are permitted. TC.diagnose(D, diag::ibaction_nonobject_argument, - argPattern->getSemanticsProvidingPattern()->getType()) - .highlight(argPattern->getSourceRange()); + param->getType()) + .highlight(param->getSourceRange()); return true; } @@ -733,64 +735,50 @@ void AttributeChecker::visitIBActionAttr(IBActionAttr *attr) { return; } - auto Arguments = FD->getBodyParamPatterns()[1]; - auto ArgTuple = dyn_cast(Arguments); - - auto checkSingleArgument = [this](const Pattern *argPattern) -> bool { + auto paramList = FD->getParameterList(1); + bool relaxedIBActionUsedOnOSX = false; + bool Valid = true; + switch (paramList->size()) { + case 0: + // (iOS only) No arguments. + if (!isRelaxedIBAction(TC)) { + relaxedIBActionUsedOnOSX = true; + break; + } + break; + case 1: // One argument. May be a scalar on iOS/watchOS (because of WatchKit). if (isRelaxedIBAction(TC)) { // Do a rough check to allow any ObjC-representable struct or enum type // on iOS. - Type ty = argPattern->getType(); + Type ty = paramList->get(0)->getType(); if (auto nominal = ty->getAnyNominal()) if (isa(nominal) || isa(nominal)) if (nominal->classifyAsOptionalType() == OTK_None) if (TC.isTriviallyRepresentableInObjC(cast(D), ty)) - return false; + break; // Looks ok. } - return checkObjectOrOptionalObjectType(TC, D, argPattern); - }; - - bool relaxedIBActionUsedOnOSX = false; - bool Valid = true; - if (ArgTuple) { - auto fields = ArgTuple->getElements(); - switch (ArgTuple->getNumElements()) { - case 0: - // (iOS only) No arguments. - if (!isRelaxedIBAction(TC)) { - relaxedIBActionUsedOnOSX = true; - break; - } - break; - case 1: - // One argument, see above. - if (checkSingleArgument(fields[0].getPattern())) - Valid = false; - break; - case 2: - // (iOS/watchOS only) Two arguments, the second of which is a UIEvent. - // We don't currently enforce the UIEvent part. - if (!isRelaxedIBAction(TC)) { - relaxedIBActionUsedOnOSX = true; - break; - } - if (checkObjectOrOptionalObjectType(TC, D, fields[0].getPattern())) - Valid = false; - if (checkObjectOrOptionalObjectType(TC, D, fields[1].getPattern())) - Valid = false; - break; - default: - // No platform allows an action signature with more than two arguments. - TC.diagnose(D, diag::invalid_ibaction_argument_count, - isRelaxedIBAction(TC)); + if (checkObjectOrOptionalObjectType(TC, D, paramList->get(0))) Valid = false; + break; + case 2: + // (iOS/watchOS only) Two arguments, the second of which is a UIEvent. + // We don't currently enforce the UIEvent part. + if (!isRelaxedIBAction(TC)) { + relaxedIBActionUsedOnOSX = true; break; } - } else { - // One argument without a name. - if (checkSingleArgument(Arguments)) + if (checkObjectOrOptionalObjectType(TC, D, paramList->get(0))) + Valid = false; + if (checkObjectOrOptionalObjectType(TC, D, paramList->get(1))) Valid = false; + break; + default: + // No platform allows an action signature with more than two arguments. + TC.diagnose(D, diag::invalid_ibaction_argument_count, + isRelaxedIBAction(TC)); + Valid = false; + break; } if (relaxedIBActionUsedOnOSX) { @@ -1229,9 +1217,10 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) { // 'rethrows' only applies to functions that take throwing functions // as parameters. auto fn = cast(D); - for (auto param : fn->getBodyParamPatterns()) { - if (hasThrowingFunctionParameter(param->getType()->getCanonicalType())) - return; + for (auto paramList : fn->getParameterLists()) { + for (auto param : *paramList) + if (hasThrowingFunctionParameter(param->getType()->getCanonicalType())) + return; } TC.diagnose(attr->getLocation(), diag::rethrows_without_throwing_parameter); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7de87eb8b1abb..48c4473196d9b 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -46,9 +46,9 @@ using namespace swift; using namespace constraints; -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Type variable implementation. -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #pragma mark Type variable implementation void TypeVariableType::Implementation::print(llvm::raw_ostream &OS) { @@ -180,12 +180,15 @@ bool constraints::computeTupleShuffle(ArrayRef fromTuple, skipToNextAvailableInput(); } sources[i] = TupleShuffleExpr::Variadic; - break; + + // Keep looking at subsequent arguments. Non-variadic arguments may + // follow the variadic one. + continue; } // If there aren't any more inputs, we can use a default argument. if (fromNext == fromLast) { - if (elt2.hasInit()) { + if (elt2.hasDefaultArg()) { sources[i] = TupleShuffleExpr::DefaultInitialize; continue; } @@ -239,9 +242,9 @@ bool constraints::hasTrailingClosure(const ConstraintLocatorBuilder &locator) { return false; } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // High-level entry points. -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// static unsigned getNumArgs(ValueDecl *value) { if (!isa(value)) return ~0U; @@ -281,13 +284,160 @@ static bool matchesDeclRefKind(ValueDecl *value, DeclRefKind refKind) { llvm_unreachable("bad declaration reference kind"); } +static bool containsDeclRefKind(LookupResult &lookupResult, + DeclRefKind refKind) { + for (auto candidate : lookupResult) { + ValueDecl *D = candidate.Decl; + if (!D || !D->hasType()) + continue; + if (matchesDeclRefKind(D, refKind)) + return true; + } + return false; +} + +/// Emit a diagnostic with a fixit hint for an invalid binary operator, showing +/// how to split it according to splitCandidate. +static void diagnoseBinOpSplit(UnresolvedDeclRefExpr *UDRE, + std::pair splitCandidate, + Diag diagID, + TypeChecker &TC) { + + unsigned splitLoc = splitCandidate.first; + bool isBinOpFirst = splitCandidate.second; + StringRef nameStr = UDRE->getName().getBaseName().str(); + auto startStr = nameStr.substr(0, splitLoc); + auto endStr = nameStr.drop_front(splitLoc); + + // One valid split found, it is almost certainly the right answer. + auto diag = TC.diagnose(UDRE->getLoc(), diagID, + TC.Context.getIdentifier(startStr), + TC.Context.getIdentifier(endStr), isBinOpFirst); + // Highlight the whole operator. + diag.highlight(UDRE->getLoc()); + // Insert whitespace on the left if the binop is at the start, or to the + // right if it is end. + if (isBinOpFirst) + diag.fixItInsert(UDRE->getLoc(), " "); + else + diag.fixItInsertAfter(UDRE->getLoc(), " "); + + // Insert a space between the operators. + diag.fixItInsert(UDRE->getLoc().getAdvancedLoc(splitLoc), " "); +} + +/// If we failed lookup of a binary operator, check to see it to see if +/// it is a binary operator juxtaposed with a unary operator (x*-4) that +/// needs whitespace. If so, emit specific diagnostics for it and return true, +/// otherwise return false. +static bool diagnoseOperatorJuxtaposition(UnresolvedDeclRefExpr *UDRE, + DeclContext *DC, + TypeChecker &TC) { + Identifier name = UDRE->getName().getBaseName(); + StringRef nameStr = name.str(); + if (!name.isOperator() || nameStr.size() < 2) + return false; + + bool isBinOp = UDRE->getRefKind() == DeclRefKind::BinaryOperator; + + // If this is a binary operator, relex the token, to decide whether it has + // whitespace around it or not. If it does "x +++ y", then it isn't likely to + // be a case where a space was forgotten. + if (isBinOp) { + auto tok = Lexer::getTokenAtLocation(TC.Context.SourceMgr, UDRE->getLoc()); + if (tok.getKind() != tok::oper_binary_unspaced) + return false; + } + + // Okay, we have a failed lookup of a multicharacter operator. Check to see if + // lookup succeeds if part is split off, and record the matches found. + // + // In the case of a binary operator, the bool indicated is false if the + // first half of the split is the unary operator (x!*4) or true if it is the + // binary operator (x*+4). + std::vector> WorkableSplits; + + // Check all the potential splits. + for (unsigned splitLoc = 1, e = nameStr.size(); splitLoc != e; ++splitLoc) { + // For it to be a valid split, the start and end section must be valid + // operators, splitting a unicode code point isn't kosher. + auto startStr = nameStr.substr(0, splitLoc); + auto endStr = nameStr.drop_front(splitLoc); + if (!Lexer::isOperator(startStr) || !Lexer::isOperator(endStr)) + continue; + + auto startName = TC.Context.getIdentifier(startStr); + auto endName = TC.Context.getIdentifier(endStr); + + // Perform name lookup for the first and second pieces. If either fail to + // be found, then it isn't a valid split. + NameLookupOptions LookupOptions = defaultUnqualifiedLookupOptions; + // This is only used for diagnostics, so always use KnownPrivate. + LookupOptions |= NameLookupFlags::KnownPrivate; + auto startLookup = TC.lookupUnqualified(DC, startName, UDRE->getLoc(), + LookupOptions); + if (!startLookup) continue; + auto endLookup = TC.lookupUnqualified(DC, endName, UDRE->getLoc(), + LookupOptions); + if (!endLookup) continue; + + // If the overall operator is a binary one, then we're looking at + // juxtaposed binary and unary operators. + if (isBinOp) { + // Look to see if the candidates found could possibly match. + if (containsDeclRefKind(startLookup, DeclRefKind::PostfixOperator) && + containsDeclRefKind(endLookup, DeclRefKind::BinaryOperator)) + WorkableSplits.push_back({ splitLoc, false }); + + if (containsDeclRefKind(startLookup, DeclRefKind::BinaryOperator) && + containsDeclRefKind(endLookup, DeclRefKind::PrefixOperator)) + WorkableSplits.push_back({ splitLoc, true }); + } else { + // Otherwise, it is two of the same kind, e.g. "!!x" or "!~x". + if (containsDeclRefKind(startLookup, UDRE->getRefKind()) && + containsDeclRefKind(endLookup, UDRE->getRefKind())) + WorkableSplits.push_back({ splitLoc, false }); + } + } + + switch (WorkableSplits.size()) { + case 0: + // No splits found, can't produce this diagnostic. + return false; + case 1: + // One candidate: produce an error with a fixit on it. + if (isBinOp) + diagnoseBinOpSplit(UDRE, WorkableSplits[0], + diag::unspaced_binary_operator_fixit, TC); + else + TC.diagnose(UDRE->getLoc().getAdvancedLoc(WorkableSplits[0].first), + diag::unspaced_unary_operator); + return true; + + default: + // Otherwise, we have to produce a series of notes listing the various + // options. + TC.diagnose(UDRE->getLoc(), isBinOp ? diag::unspaced_binary_operator : + diag::unspaced_unary_operator) + .highlight(UDRE->getLoc()); + + if (isBinOp) { + for (auto candidateSplit : WorkableSplits) + diagnoseBinOpSplit(UDRE, candidateSplit, + diag::unspaced_binary_operators_candidate, TC); + } + return true; + } +} + + /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used /// for the lookup. Expr *TypeChecker:: resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { // Process UnresolvedDeclRefExpr by doing an unqualified lookup. - Identifier Name = UDRE->getName(); + DeclName Name = UDRE->getName(); SourceLoc Loc = UDRE->getLoc(); // Perform standard value name lookup. @@ -297,9 +447,15 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { auto Lookup = lookupUnqualified(DC, Name, Loc, LookupOptions); if (!Lookup) { - diagnose(Loc, diag::use_unresolved_identifier, Name) - .highlight(Loc); - return new (Context) ErrorExpr(Loc); + // If we failed lookup of an operator, check to see it to see if it is + // because two operators are juxtaposed e.g. (x*-4) that needs whitespace. + // If so, emit specific diagnostics for it. + if (!diagnoseOperatorJuxtaposition(UDRE, DC, *this)) { + diagnose(Loc, diag::use_unresolved_identifier, Name, + UDRE->getName().isOperator()) + .highlight(UDRE->getSourceRange()); + } + return new (Context) ErrorExpr(UDRE->getSourceRange()); } // FIXME: Need to refactor the way we build an AST node from a lookup result! @@ -321,7 +477,7 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { diagnose(Loc, diag::use_local_before_declaration, Name); diagnose(D->getLoc(), diag::decl_declared_here, Name); } - return new (Context) ErrorExpr(Loc); + return new (Context) ErrorExpr(UDRE->getSourceRange()); } if (matchesDeclRefKind(D, UDRE->getRefKind())) ResultValues.push_back(D); @@ -335,22 +491,24 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { isa(ResultValues[0])) { // FIXME: This is odd. if (isa(ResultValues[0])) { - return new (Context) DeclRefExpr(ResultValues[0], Loc, /*implicit=*/false, + return new (Context) DeclRefExpr(ResultValues[0], UDRE->getNameLoc(), + /*implicit=*/false, AccessSemantics::Ordinary, ResultValues[0]->getType()); } - return TypeExpr::createForDecl(Loc, cast(ResultValues[0])); + return TypeExpr::createForDecl(Loc, cast(ResultValues[0]), + UDRE->isImplicit()); } if (AllDeclRefs) { // Diagnose uses of operators that found no matching candidates. if (ResultValues.empty()) { assert(UDRE->getRefKind() != DeclRefKind::Ordinary); - diagnose(Loc, diag::use_nonmatching_operator, Name, + diagnose(Loc, diag::use_nonmatching_operator, Name.getBaseName(), UDRE->getRefKind() == DeclRefKind::BinaryOperator ? 0 : UDRE->getRefKind() == DeclRefKind::PrefixOperator ? 1 : 2); - return new (Context) ErrorExpr(Loc); + return new (Context) ErrorExpr(UDRE->getSourceRange()); } // For operators, sort the results so that non-generic operations come @@ -375,8 +533,8 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { }); } - return buildRefExpr(ResultValues, DC, Loc, UDRE->isImplicit(), - UDRE->isSpecialized()); + return buildRefExpr(ResultValues, DC, UDRE->getNameLoc(), + UDRE->isImplicit(), UDRE->isSpecialized()); } ResultValues.clear(); @@ -402,15 +560,17 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { if (AllMemberRefs) { Expr *BaseExpr; if (auto NTD = dyn_cast(Base)) { - BaseExpr = TypeExpr::createForDecl(Loc, NTD); + BaseExpr = TypeExpr::createForDecl(Loc, NTD, /*implicit=*/true); } else { - BaseExpr = new (Context) DeclRefExpr(Base, Loc, /*implicit=*/true); + BaseExpr = new (Context) DeclRefExpr(Base, UDRE->getNameLoc(), + /*implicit=*/true); } // Otherwise, form an UnresolvedDotExpr and sema will resolve it based on // type information. - return new (Context) UnresolvedDotExpr(BaseExpr, SourceLoc(), Name, Loc, + return new (Context) UnresolvedDotExpr(BaseExpr, SourceLoc(), Name, + UDRE->getNameLoc(), UDRE->isImplicit()); } @@ -418,7 +578,7 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { // very broken, but it's still conceivable that this may happen due to // invalid shadowed declarations. // llvm_unreachable("Can't represent lookup result"); - return new (Context) ErrorExpr(Loc); + return new (Context) ErrorExpr(UDRE->getSourceRange()); } /// If an expression references 'self.init' or 'super.init' in an @@ -426,10 +586,14 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { /// Otherwise, return nil. VarDecl * TypeChecker::getSelfForInitDelegationInConstructor(DeclContext *DC, - UnresolvedConstructorExpr *ctorRef) { + UnresolvedDotExpr *ctorRef) { + // If the reference isn't to a constructor, we're done. + if (ctorRef->getName().getBaseName() != Context.Id_init) + return nullptr; + if (auto ctorContext = dyn_cast_or_null(DC->getInnermostMethodContext())) { - auto nestedArg = ctorRef->getSubExpr(); + auto nestedArg = ctorRef->getBase(); if (auto inout = dyn_cast(nestedArg)) nestedArg = inout->getSubExpr(); if (nestedArg->isSuperExpr()) @@ -562,9 +726,9 @@ namespace { // determine where to place the RebindSelfInConstructorExpr node. // When updating this logic, also update // RebindSelfInConstructorExpr::getCalledConstructor. - if (auto nestedCtor = dyn_cast(expr)) { + if (auto unresolvedDot = dyn_cast(expr)) { if (auto self - = TC.getSelfForInitDelegationInConstructor(DC, nestedCtor)) { + = TC.getSelfForInitDelegationInConstructor(DC, unresolvedDot)) { // Walk our ancestor expressions looking for the appropriate place // to insert the RebindSelfInConstructorExpr. Expr *target = nullptr; @@ -577,7 +741,7 @@ namespace { foundRebind = true; break; } - + // Recognize applications. if (auto apply = dyn_cast(ancestor)) { // If we already saw an application, we're done. @@ -586,7 +750,7 @@ namespace { // If the function being called is not our unresolved initializer // reference, we're done. - if (apply->getFn()->getSemanticsProvidingExpr() != nestedCtor) + if (apply->getFn()->getSemanticsProvidingExpr() != unresolvedDot) break; foundApply = true; @@ -653,10 +817,9 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) { TypeResolutionOptions options; options |= TR_AllowUnspecifiedTypes; options |= TR_AllowUnboundGenerics; - options |= TR_ImmediateFunctionInput; options |= TR_InExpression; bool hadParameterError = false; - if (TC.typeCheckPattern(closure->getParams(), DC, options)) { + if (TC.typeCheckParameterList(closure->getParameters(), DC, options)) { closure->setType(ErrorType::get(TC.Context)); // If we encounter an error validating the parameter list, don't bail. @@ -693,52 +856,31 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) { /// as expressions due to the parser not knowing which identifiers are /// type names. TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) { - // Fold T[] into an array, it isn't a subscript on a metatype. - if (auto *SE = dyn_cast(E)) { - auto *TyExpr = dyn_cast(SE->getBase()); - if (!TyExpr) return nullptr; - - // We don't fold subscripts with indexes, just an empty subscript. - TupleExpr *Indexes = dyn_cast(SE->getIndex()); - if (!Indexes || Indexes->getNumElements() != 0) - return nullptr; - auto *InnerTypeRepr = TyExpr->getTypeRepr(); - assert(!TyExpr->isImplicit() && InnerTypeRepr && - "SubscriptExpr doesn't work on implicit TypeExpr's, " - "the TypeExpr should have been built correctly in the first place"); - - auto *NewTypeRepr = - new (TC.Context) ArrayTypeRepr(InnerTypeRepr, nullptr, - Indexes->getSourceRange(), - /*OldSyntax=*/true); - - TC.diagnose(Indexes->getStartLoc(), diag::new_array_syntax) - .fixItInsert(SE->getStartLoc(), "[") - .fixItRemove(Indexes->getStartLoc()); - - return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); - } - // Fold 'T.Type' or 'T.Protocol' into a metatype when T is a TypeExpr. if (auto *MRE = dyn_cast(E)) { auto *TyExpr = dyn_cast(MRE->getBase()); if (!TyExpr) return nullptr; auto *InnerTypeRepr = TyExpr->getTypeRepr(); - assert(!TyExpr->isImplicit() && InnerTypeRepr && - "This doesn't work on implicit TypeExpr's, " - "the TypeExpr should have been built correctly in the first place"); if (MRE->getName() == TC.Context.Id_Protocol) { + assert(!TyExpr->isImplicit() && InnerTypeRepr && + "This doesn't work on implicit TypeExpr's, " + "TypeExpr should have been built correctly in the first place"); auto *NewTypeRepr = - new (TC.Context) ProtocolTypeRepr(InnerTypeRepr, MRE->getNameLoc()); + new (TC.Context) ProtocolTypeRepr(InnerTypeRepr, + MRE->getNameLoc().getBaseNameLoc()); return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); } if (MRE->getName() == TC.Context.Id_Type) { + assert(!TyExpr->isImplicit() && InnerTypeRepr && + "This doesn't work on implicit TypeExpr's, " + "TypeExpr should have been built correctly in the first place"); auto *NewTypeRepr = - new (TC.Context) MetatypeTypeRepr(InnerTypeRepr, MRE->getNameLoc()); + new (TC.Context) MetatypeTypeRepr(InnerTypeRepr, + MRE->getNameLoc().getBaseNameLoc()); return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); } } @@ -845,10 +987,9 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) { return nullptr; auto *NewTypeRepr = - new (TC.Context) ArrayTypeRepr(TyExpr->getTypeRepr(), nullptr, + new (TC.Context) ArrayTypeRepr(TyExpr->getTypeRepr(), SourceRange(AE->getLBracketLoc(), - AE->getRBracketLoc()), - /*OldSyntax=*/false); + AE->getRBracketLoc())); return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); } @@ -1235,10 +1376,23 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, // Attempt to solve the constraint system. SmallVector viable; + const Type originalType = expr->getType(); + const bool needClearType = originalType && originalType->is(); + const auto recoverOriginalType = [&] () { + if (needClearType) + expr->setType(originalType); + }; + + // If the previous checking gives the expr error type, clear the result and + // re-check. + if (needClearType) + expr->setType(Type()); if (solveForExpression(expr, dc, /*convertType*/Type(), allowFreeTypeVariables, listener, cs, viable, - TypeCheckExprFlags::SuppressDiagnostics)) + TypeCheckExprFlags::SuppressDiagnostics)) { + recoverOriginalType(); return None; + } // Get the expression's simplified type. auto &solution = viable[0]; @@ -1248,6 +1402,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, assert(!exprType->hasTypeVariable() && "free type variable with FreeTypeVariableBinding::GenericParameters?"); + // Recover the original type if needed. + recoverOriginalType(); return exprType; } @@ -1436,10 +1592,9 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, InitType = solution.simplifyType(tc, InitType); // Convert the initializer to the type of the pattern. + // ignoreTopLevelInjection = Binding->isConditional() expr = solution.coerceToType(expr, InitType, Locator, - false - /*ignoreTopLevelInjection= - Binding->isConditional()*/); + false /* ignoreTopLevelInjection */); if (!expr) { return nullptr; } @@ -1853,10 +2008,7 @@ bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc, // If the pattern didn't get a type, it's because we ran into some // unknown types along the way. We'll need to check the initializer. auto init = elt.getInitializer(); - if (typeCheckBinding(pattern, init, dc)) { - hadError = true; - continue; - } + hadError |= typeCheckBinding(pattern, init, dc); elt.setPattern(pattern); elt.setInitializer(init); hadAnyFalsable |= pattern->isRefutablePattern(); @@ -1907,9 +2059,11 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, } // Build the 'expr ~= var' expression. - auto *matchOp = buildRefExpr(choices, DC, EP->getLoc(), /*Implicit=*/true); + // FIXME: Compound name locations. + auto *matchOp = buildRefExpr(choices, DC, DeclNameLoc(EP->getLoc()), + /*Implicit=*/true); auto *matchVarRef = new (Context) DeclRefExpr(matchVar, - EP->getLoc(), + DeclNameLoc(EP->getLoc()), /*Implicit=*/true); Expr *matchArgElts[] = {EP->getSubExpr(), matchVarRef}; @@ -2123,9 +2277,9 @@ bool TypeChecker::convertToType(Expr *&expr, Type type, DeclContext *dc) { return false; } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Debugging -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #pragma mark Debugging void Solution::dump() const { @@ -2317,7 +2471,7 @@ void ConstraintSystem::print(raw_ostream &out) { case OverloadChoiceKind::DeclViaUnwrappedOptional: if (choice.getBaseType()) out << choice.getBaseType()->getString() << "."; - out << choice.getDecl()->getName().str() << ": " + out << choice.getDecl()->getName() << ": " << resolved->BoundType->getString() << " == " << resolved->ImpliedType->getString() << "\n"; break; @@ -2589,7 +2743,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, return CheckedCastKind::ValueCast; } -/// If the expression is a an implicit call to _forceBridgeFromObjectiveC or +/// If the expression is an implicit call to _forceBridgeFromObjectiveC or /// _conditionallyBridgeFromObjectiveC, returns the argument of that call. static Expr *lookThroughBridgeFromObjCCall(ASTContext &ctx, Expr *expr) { auto call = dyn_cast(expr); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index eb9e9d1407dcb..0edd4a905fa69 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -224,8 +224,7 @@ static void addImplicitConformances( } /// Check that the declaration attributes are ok. -static void validateAttributes(TypeChecker &TC, Decl *VD); -static void validateFixedLayoutAttribute(TypeChecker &TC, NominalTypeDecl *D); +static void validateAttributes(TypeChecker &TC, Decl *D); void TypeChecker::resolveSuperclass(ClassDecl *classDecl) { IterativeTypeChecker ITC(*this); @@ -702,67 +701,6 @@ static void revertDependentTypeLoc(TypeLoc &tl) { tl.setType(Type(), /*validated=*/false); } -static void revertDependentPattern(Pattern *pattern) { - // Clear out the pattern's type. - if (pattern->hasType()) { - // If the type of the pattern was in error, we're done. - if (pattern->getType()->is()) - return; - - pattern->overwriteType(Type()); - } - - switch (pattern->getKind()) { -#define PATTERN(Id, Parent) -#define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: -#include "swift/AST/PatternNodes.def" - // Do nothing for refutable patterns. - break; - - case PatternKind::Any: - // Do nothing; - break; - - case PatternKind::Named: { - // Clear out the type of the variable. - auto named = cast(pattern); - if (named->getDecl()->hasType() && - !named->getDecl()->isInvalid()) - named->getDecl()->overwriteType(Type()); - break; - } - - case PatternKind::Paren: - // Recurse into parentheses patterns. - revertDependentPattern(cast(pattern)->getSubPattern()); - break; - - case PatternKind::Var: - // Recurse into var patterns. - revertDependentPattern(cast(pattern)->getSubPattern()); - break; - - case PatternKind::Tuple: { - // Recurse into tuple elements. - auto tuple = cast(pattern); - for (auto &field : tuple->getElements()) { - revertDependentPattern(field.getPattern()); - } - break; - } - - case PatternKind::Typed: { - // Revert the type annotation. - auto typed = cast(pattern); - revertDependentTypeLoc(typed->getTypeLoc()); - - // Revert the subpattern. - revertDependentPattern(typed->getSubPattern()); - break; - } - } -} - /// Revert the dependent types within the given generic parameter list. void TypeChecker::revertGenericParamList(GenericParamList *genericParams) { // Revert the inherited clause of the generic parameter list. @@ -778,19 +716,16 @@ void TypeChecker::revertGenericParamList(GenericParamList *genericParams) { continue; switch (req.getKind()) { - case RequirementKind::Conformance: { + case RequirementReprKind::TypeConstraint: { revertDependentTypeLoc(req.getSubjectLoc()); revertDependentTypeLoc(req.getConstraintLoc()); break; } - case RequirementKind::SameType: + case RequirementReprKind::SameType: revertDependentTypeLoc(req.getFirstTypeLoc()); revertDependentTypeLoc(req.getSecondTypeLoc()); break; - - case RequirementKind::WitnessMarker: - llvm_unreachable("value witness markers in syntactic requirement?"); } } } @@ -810,9 +745,8 @@ static void markInvalidGenericSignature(ValueDecl *VD, DeclContext *DC = VD->getDeclContext(); ArchetypeBuilder builder = TC.createArchetypeBuilder(DC->getParentModule()); - if (DC->isTypeContext()) - if (auto sig = DC->getGenericSignatureOfContext()) - builder.addGenericSignature(sig, true); + if (auto sig = DC->getGenericSignatureOfContext()) + builder.addGenericSignature(sig, true); // Visit each of the generic parameters. for (auto param : *genericParams) @@ -868,7 +802,7 @@ static void finalizeGenericParamList(ArchetypeBuilder &builder, continue; switch (Req.getKind()) { - case RequirementKind::Conformance: { + case RequirementReprKind::TypeConstraint: { revertDependentTypeLoc(Req.getSubjectLoc()); if (TC.validateType(Req.getSubjectLoc(), dc)) { Req.setInvalid(); @@ -883,7 +817,7 @@ static void finalizeGenericParamList(ArchetypeBuilder &builder, break; } - case RequirementKind::SameType: + case RequirementReprKind::SameType: revertDependentTypeLoc(Req.getFirstTypeLoc()); if (TC.validateType(Req.getFirstTypeLoc(), dc)) { Req.setInvalid(); @@ -896,9 +830,6 @@ static void finalizeGenericParamList(ArchetypeBuilder &builder, continue; } break; - - case RequirementKind::WitnessMarker: - llvm_unreachable("value witness markers in syntactic requirement?"); } } } @@ -939,16 +870,18 @@ bool TypeChecker::handleSILGenericParams( void TypeChecker::revertGenericFuncSignature(AbstractFunctionDecl *func) { // Revert the result type. - if (auto fn = dyn_cast(func)) { - if (!fn->getBodyResultTypeLoc().isNull()) { + if (auto fn = dyn_cast(func)) + if (!fn->getBodyResultTypeLoc().isNull()) revertDependentTypeLoc(fn->getBodyResultTypeLoc()); - } - } - // Revert the body patterns. - ArrayRef bodyPatterns = func->getBodyParamPatterns(); - for (auto bodyPattern : bodyPatterns) { - revertDependentPattern(bodyPattern); + // Revert the body parameter types. + for (auto paramList : func->getParameterLists()) { + for (auto ¶m : *paramList) { + // Clear out the type of the decl. + if (param->hasType() && !param->isInvalid()) + param->overwriteType(Type()); + revertDependentTypeLoc(param->getTypeLoc()); + } } // Revert the generic parameter list. @@ -1107,7 +1040,7 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) { ArrayRef otherDefinitions; if (currentDC->isTypeContext()) { // Look within a type context. - if (auto nominal = currentDC->getDeclaredTypeOfContext()->getAnyNominal()) { + if (auto nominal = currentDC->isNominalTypeOrNominalTypeExtensionContext()) { otherDefinitions = nominal->lookupDirect(current->getBaseName()); if (tracker) tracker->addUsedMember({nominal, current->getName()}, isCascading); @@ -1391,18 +1324,14 @@ Type swift::configureImplicitSelf(TypeChecker &tc, Type selfTy = func->computeSelfType(); assert(selfDecl && selfTy && "Not a method"); - if (selfDecl->hasType()) - return selfDecl->getType(); - // 'self' is 'let' for reference types (i.e., classes) or when 'self' is // neither inout. selfDecl->setLet(!selfTy->is()); - selfDecl->setType(selfTy); - - auto bodyPattern = cast(func->getBodyParamPatterns()[0]); - if (!bodyPattern->getTypeLoc().getTypeRepr()) - bodyPattern->getTypeLoc() = TypeLoc::withoutLoc(selfTy); - + selfDecl->overwriteType(selfTy); + + // Install the self type on the Parameter that contains it. This ensures that + // we don't lose it when generic types get reverted. + selfDecl->getTypeLoc() = TypeLoc::withoutLoc(selfTy); return selfTy; } @@ -1420,10 +1349,6 @@ void swift::configureConstructorType(ConstructorDecl *ctor, resultType = OptionalType::get(ctor->getFailability(), resultType); } - // Use the argument names in the argument type. - argType = argType->getRelabeledType(ctor->getASTContext(), - ctor->getFullName().getArgumentNames()); - auto extInfo = AnyFunctionType::ExtInfo().withThrows(throws); GenericParamList *outerGenericParams = @@ -1535,16 +1460,14 @@ void TypeChecker::computeDefaultAccessibility(ExtensionDecl *ED) { // from the extended type and have already been checked. for (const RequirementRepr &req : genericParams->getTrailingRequirements()){ switch (req.getKind()) { - case RequirementKind::Conformance: + case RequirementReprKind::TypeConstraint: maxAccess = std::min(getTypeAccess(req.getSubjectLoc()), maxAccess); maxAccess = std::min(getTypeAccess(req.getConstraintLoc()), maxAccess); break; - case RequirementKind::SameType: + case RequirementReprKind::SameType: maxAccess = std::min(getTypeAccess(req.getFirstTypeLoc()), maxAccess); maxAccess = std::min(getTypeAccess(req.getSecondTypeLoc()), maxAccess); break; - case RequirementKind::WitnessMarker: - break; } } } @@ -1600,6 +1523,7 @@ void TypeChecker::computeAccessibility(ValueDecl *D) { case DeclContextKind::Initializer: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: D->setAccessibility(Accessibility::Private); break; case DeclContextKind::Module: @@ -1761,20 +1685,18 @@ static void checkGenericParamAccessibility(TypeChecker &TC, } }; switch (requirement.getKind()) { - case RequirementKind::Conformance: + case RequirementReprKind::TypeConstraint: checkTypeAccessibility(TC, requirement.getSubjectLoc(), contextAccess, callback); checkTypeAccessibility(TC, requirement.getConstraintLoc(), contextAccess, callback); break; - case RequirementKind::SameType: + case RequirementReprKind::SameType: checkTypeAccessibility(TC, requirement.getFirstTypeLoc(), contextAccess, callback); checkTypeAccessibility(TC, requirement.getSecondTypeLoc(), contextAccess, callback); break; - case RequirementKind::WitnessMarker: - break; } } @@ -2054,12 +1976,8 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) { Optional minAccess; const TypeRepr *complainRepr = nullptr; bool problemIsElement = false; - SD->getIndices()->forEachNode([&](const Pattern *P) { - auto *TP = dyn_cast(P); - if (!TP) - return; - - checkTypeAccessibility(TC, TP->getTypeLoc(), SD, + for (auto &P : *SD->getIndices()) { + checkTypeAccessibility(TC, P->getTypeLoc(), SD, [&](Accessibility typeAccess, const TypeRepr *thisComplainRepr) { if (!minAccess || *minAccess > typeAccess) { @@ -2067,7 +1985,7 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) { complainRepr = thisComplainRepr; } }); - }); + } checkTypeAccessibility(TC, SD->getElementTypeLoc(), SD, [&](Accessibility typeAccess, @@ -2112,16 +2030,9 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) { Optional minAccess; const TypeRepr *complainRepr = nullptr; - bool problemIsResult = false; - std::for_each(fn->getBodyParamPatterns().begin() + isTypeContext, - fn->getBodyParamPatterns().end(), - [&](const Pattern *paramList) { - paramList->forEachNode([&](const Pattern *P) { - auto *TP = dyn_cast(P); - if (!TP) - return; - - checkTypeAccessibility(TC, TP->getTypeLoc(), fn, + for (auto *PL : fn->getParameterLists().slice(isTypeContext)) { + for (auto &P : *PL) { + checkTypeAccessibility(TC, P->getTypeLoc(), fn, [&](Accessibility typeAccess, const TypeRepr *thisComplainRepr) { if (!minAccess || *minAccess > typeAccess) { @@ -2129,9 +2040,10 @@ static void checkAccessibility(TypeChecker &TC, const Decl *D) { complainRepr = thisComplainRepr; } }); - }); - }); + } + } + bool problemIsResult = false; if (auto FD = dyn_cast(fn)) { checkTypeAccessibility(TC, FD->getBodyResultTypeLoc(), FD, [&](Accessibility typeAccess, @@ -2303,16 +2215,24 @@ static void checkBridgedFunctions(TypeChecker &TC) { #include "swift/SIL/BridgedTypes.def" if (Module *module = TC.Context.getLoadedModule(ID_Foundation)) { - checkObjCBridgingFunctions(TC, module, "NSArray", + checkObjCBridgingFunctions(TC, module, + TC.Context.getSwiftName( + KnownFoundationEntity::NSArray), "_convertNSArrayToArray", "_convertArrayToNSArray"); - checkObjCBridgingFunctions(TC, module, "NSDictionary", + checkObjCBridgingFunctions(TC, module, + TC.Context.getSwiftName( + KnownFoundationEntity::NSDictionary), "_convertNSDictionaryToDictionary", "_convertDictionaryToNSDictionary"); - checkObjCBridgingFunctions(TC, module, "NSSet", + checkObjCBridgingFunctions(TC, module, + TC.Context.getSwiftName( + KnownFoundationEntity::NSSet), "_convertNSSetToSet", "_convertSetToNSSet"); - checkObjCBridgingFunctions(TC, module, "NSError", + checkObjCBridgingFunctions(TC, module, + TC.Context.getSwiftName( + KnownFoundationEntity::NSError), "_convertNSErrorToErrorType", "_convertErrorTypeToNSError"); } @@ -2466,6 +2386,14 @@ void swift::markAsObjC(TypeChecker &TC, ValueDecl *D, method->setForeignErrorConvention(*errorConvention); } } + + // Record this method in the source-file-specific Objective-C method + // table. + if (auto method = dyn_cast(D)) { + if (auto sourceFile = method->getParentSourceFile()) { + sourceFile->ObjCMethods[method->getObjCSelector()].push_back(method); + } + } } namespace { @@ -2742,8 +2670,24 @@ class DeclChecker : public DeclVisitor { DeclVisitor::visit(decl); - if (auto valueDecl = dyn_cast(decl)) { - checkRedeclaration(TC, valueDecl); + if (auto VD = dyn_cast(decl)) { + checkRedeclaration(TC, VD); + + // If this is a member of a nominal type, don't allow it to have a name of + // "Type" or "Protocol" since we reserve the X.Type and X.Protocol + // expressions to mean something builtin to the language. We *do* allow + // these if they are escaped with backticks though. + auto &Context = TC.Context; + if (VD->getDeclContext()->isTypeContext() && + (VD->getFullName().isSimpleName(Context.Id_Type) || + VD->getFullName().isSimpleName(Context.Id_Protocol)) && + VD->getNameLoc().isValid() && + Context.SourceMgr.extractText({VD->getNameLoc(), 1}) != "`") { + TC.diagnose(VD->getNameLoc(), diag::reserved_member_name, + VD->getFullName(), VD->getNameStr()); + TC.diagnose(VD->getNameLoc(), diag::backticks_to_escape) + .fixItReplace(VD->getNameLoc(), "`"+VD->getNameStr().str()+"`"); + } } if ((IsSecondPass && !IsFirstPass) || @@ -2890,8 +2834,7 @@ class DeclChecker : public DeclVisitor { // Synthesize materializeForSet in non-protocol contexts. if (auto materializeForSet = VD->getMaterializeForSetFunc()) { - Type containerTy = VD->getDeclContext()->getDeclaredTypeOfContext(); - if (!containerTy || !containerTy->is()) { + if (!VD->getDeclContext()->isProtocolOrProtocolExtensionContext()) { synthesizeMaterializeForSet(materializeForSet, VD, TC); TC.typeCheckDecl(materializeForSet, true); TC.typeCheckDecl(materializeForSet, false); @@ -2912,9 +2855,6 @@ class DeclChecker : public DeclVisitor { for (unsigned i = 0, e = PBD->getNumPatternEntries(); i != e; ++i) validatePatternBindingDecl(TC, PBD, i); - // Note: The Else body is type checked when the enclosing BraceStmt is - // checked. - if (PBD->isInvalid() || PBD->isBeingTypeChecked()) return; @@ -3038,8 +2978,8 @@ class DeclChecker : public DeclVisitor { auto dc = SD->getDeclContext(); bool isInvalid = TC.validateType(SD->getElementTypeLoc(), dc); - isInvalid |= TC.typeCheckPattern(SD->getIndices(), dc, - TR_ImmediateFunctionInput); + isInvalid |= TC.typeCheckParameterList(SD->getIndices(), dc, + TypeResolutionOptions()); if (isInvalid) { SD->overwriteType(ErrorType::get(TC.Context)); @@ -3051,7 +2991,7 @@ class DeclChecker : public DeclVisitor { return; // Relabel the indices according to the subscript name. - auto indicesType = SD->getIndices()->getType(); + auto indicesType = SD->getIndices()->getType(TC.Context); SD->setType(FunctionType::get(indicesType, SD->getElementType())); // If we're in a generic context, set the interface type. @@ -3125,8 +3065,7 @@ class DeclChecker : public DeclVisitor { // Synthesize materializeForSet in non-protocol contexts. if (auto materializeForSet = SD->getMaterializeForSetFunc()) { - Type containerTy = SD->getDeclContext()->getDeclaredTypeOfContext(); - if (!containerTy || !containerTy->is()) { + if (!SD->getDeclContext()->isProtocolOrProtocolExtensionContext()) { synthesizeMaterializeForSet(materializeForSet, SD, TC); TC.typeCheckDecl(materializeForSet, true); TC.typeCheckDecl(materializeForSet, false); @@ -3350,10 +3289,9 @@ class DeclChecker : public DeclVisitor { if (!IsFirstPass) { checkAccessibility(TC, SD); - } - if (!(IsFirstPass || SD->isInvalid())) { - checkExplicitConformance(SD, SD->getDeclaredTypeInContext()); + if (!SD->isInvalid()) + checkExplicitConformance(SD, SD->getDeclaredTypeInContext()); } // Visit each of the members. @@ -3365,7 +3303,7 @@ class DeclChecker : public DeclVisitor { TC.checkDeclAttributes(SD); } - /// Check whether the given propertes can be @NSManaged in this class. + /// Check whether the given properties can be @NSManaged in this class. static bool propertiesCanBeNSManaged(ClassDecl *classDecl, ArrayRef vars) { // Check whether we have an Objective-C-defined class in our @@ -3507,9 +3445,8 @@ class DeclChecker : public DeclVisitor { TC.addImplicitDestructor(CD); - if (!(IsFirstPass || CD->isInvalid())) { + if (!IsFirstPass && !CD->isInvalid()) checkExplicitConformance(CD, CD->getDeclaredTypeInContext()); - } for (Decl *Member : CD->getMembers()) visit(Member); @@ -3604,20 +3541,14 @@ class DeclChecker : public DeclVisitor { bool semaFuncParamPatterns(AbstractFunctionDecl *fd, GenericTypeResolver *resolver = nullptr) { - // Type check the body patterns. - bool badType = false; - auto bodyPatterns = fd->getBodyParamPatterns(); - for (unsigned i = 0, e = bodyPatterns.size(); i != e; ++i) { - auto *bodyPat = bodyPatterns[i]; - - if (bodyPat->hasType()) - continue; - - if (TC.typeCheckPattern(bodyPat, fd, TR_ImmediateFunctionInput, resolver)) - badType = true; + bool hadError = false; + for (auto paramList : fd->getParameterLists()) { + hadError |= TC.typeCheckParameterList(paramList, fd, + TypeResolutionOptions(), + resolver); } - return badType; + return hadError; } void semaFuncDecl(FuncDecl *FD, GenericTypeResolver *resolver) { @@ -3630,7 +3561,7 @@ class DeclChecker : public DeclVisitor { bool badType = false; if (!FD->getBodyResultTypeLoc().isNull()) { - TypeResolutionOptions options = TR_FunctionResult; + TypeResolutionOptions options; if (FD->hasDynamicSelf()) options |= TR_DynamicSelfResult; if (TC.validateType(FD->getBodyResultTypeLoc(), FD, options, @@ -3667,19 +3598,18 @@ class DeclChecker : public DeclVisitor { // patterns. GenericParamList *genericParams = FD->getGenericParams(); GenericParamList *outerGenericParams = nullptr; - auto patterns = FD->getBodyParamPatterns(); + auto paramLists = FD->getParameterLists(); bool hasSelf = FD->getDeclContext()->isTypeContext(); if (FD->getDeclContext()->isGenericTypeContext()) outerGenericParams = FD->getDeclContext()->getGenericParamsOfContext(); - for (unsigned i = 0, e = patterns.size(); i != e; ++i) { - if (!patterns[e - i - 1]->hasType()) { + for (unsigned i = 0, e = paramLists.size(); i != e; ++i) { + Type argTy = paramLists[e - i - 1]->getType(TC.Context); + if (!argTy) { FD->setType(ErrorType::get(TC.Context)); FD->setInvalid(); return; } - - Type argTy = patterns[e - i - 1]->getType(); // Determine the appropriate generic parameters at this level. GenericParamList *params = nullptr; @@ -3888,12 +3818,8 @@ class DeclChecker : public DeclVisitor { return false; } - auto containerTy = dc->getDeclaredTypeOfContext(); - if (containerTy->is()) - return true; - // 'Self' is only a dynamic self on class methods. - auto nominal = containerTy->getAnyNominal(); + auto nominal = dc->isNominalTypeOrNominalTypeExtensionContext(); assert(nominal && "Non-nominal container for method type?"); if (!isa(nominal) && !isa(nominal)) { int which; @@ -3995,11 +3921,8 @@ class DeclChecker : public DeclVisitor { Type valueTy = ASD->getType()->getReferenceStorageReferent(); if (FD->isObservingAccessor() || (FD->isSetter() && FD->isImplicit())) { unsigned firstParamIdx = FD->getParent()->isTypeContext(); - auto *firstParamPattern = FD->getBodyParamPatterns()[firstParamIdx]; - auto *tuplePattern = cast(firstParamPattern); - auto *paramPattern = tuplePattern->getElements().front().getPattern(); - auto *paramTypePattern = cast(paramPattern); - paramTypePattern->getTypeLoc().setType(valueTy, true); + auto *firstParamPattern = FD->getParameterList(firstParamIdx); + firstParamPattern->get(0)->getTypeLoc().setType(valueTy, true); } else if (FD->isGetter() && FD->isImplicit()) { FD->getBodyResultTypeLoc().setType(valueTy, true); } @@ -4023,7 +3946,7 @@ class DeclChecker : public DeclVisitor { TC.checkGenericParamList(&builder, gp, FD->getDeclContext()); // Infer requirements from parameter patterns. - for (auto pattern : FD->getBodyParamPatterns()) { + for (auto pattern : FD->getParameterLists()) { builder.inferRequirements(pattern, gp); } @@ -4152,41 +4075,36 @@ class DeclChecker : public DeclVisitor { // closure parameter; warn about such things, because the closure will not // be treated as a trailing closure. if (!FD->isImplicit()) { - auto paramPattern = FD->getBodyParamPatterns()[ - FD->getDeclContext()->isTypeContext() ? 1 : 0]; - if (auto paramTuple = dyn_cast(paramPattern)) { - ArrayRef fields = paramTuple->getElements(); - unsigned n = fields.size(); - bool anyDefaultArguments = false; - for (unsigned i = n; i > 0; --i) { - // Determine whether the parameter is of (possibly lvalue, possibly - // optional), non-autoclosure function type, which could receive a - // closure. We look at the type sugar directly, so that one can - // suppress this warning by adding parentheses. - auto paramType = fields[i-1].getPattern()->getType(); - - if (auto *funcTy = isUnparenthesizedTrailingClosure(paramType)) { - // If we saw any default arguments before this, complain. - // This doesn't apply to autoclosures. - if (anyDefaultArguments && !funcTy->getExtInfo().isAutoClosure()) { - TC.diagnose(fields[i-1].getPattern()->getStartLoc(), - diag::non_trailing_closure_before_default_args) - .highlight(SourceRange(fields[i].getPattern()->getStartLoc(), - fields[n-1].getPattern()->getEndLoc())); - } - - break; + auto paramList = FD->getParameterList(FD->getImplicitSelfDecl() ? 1 : 0); + bool anyDefaultArguments = false; + for (unsigned i = paramList->size(); i != 0; --i) { + // Determine whether the parameter is of (possibly lvalue, possibly + // optional), non-autoclosure function type, which could receive a + // closure. We look at the type sugar directly, so that one can + // suppress this warning by adding parentheses. + auto ¶m = paramList->get(i-1); + auto paramType = param->getType(); + + if (auto *funcTy = isUnparenthesizedTrailingClosure(paramType)) { + // If we saw any default arguments before this, complain. + // This doesn't apply to autoclosures. + if (anyDefaultArguments && !funcTy->getExtInfo().isAutoClosure()) { + TC.diagnose(param->getStartLoc(), + diag::non_trailing_closure_before_default_args) + .highlight(param->getSourceRange()); } - // If we have a default argument, keep going. - if (fields[i-1].getDefaultArgKind() != DefaultArgumentKind::None) { - anyDefaultArguments = true; - continue; - } - - // We're done. break; } + + // If we have a default argument, keep going. + if (param->isDefaultArgument()) { + anyDefaultArguments = true; + continue; + } + + // We're done. + break; } } } @@ -4243,10 +4161,6 @@ class DeclChecker : public DeclVisitor { return true; } - static const Pattern *getTupleElementPattern(const TuplePatternElt &elt) { - return elt.getPattern(); - } - /// Drop the optionality of the result type of the given function type. static Type dropResultOptionality(Type type, unsigned uncurryLevel) { // We've hit the result type. @@ -4285,28 +4199,22 @@ class DeclChecker : public DeclVisitor { parentTy = parentTy->getResult()->castTo(); // Check the parameter types. - auto checkParam = [&](const Pattern *paramPattern, Type parentParamTy) { - Type paramTy = paramPattern->getType(); + auto checkParam = [&](const ParamDecl *decl, Type parentParamTy) { + Type paramTy = decl->getType(); if (!paramTy || !paramTy->getImplicitlyUnwrappedOptionalObjectType()) return; if (!parentParamTy || parentParamTy->getAnyOptionalObjectType()) return; - if (auto parenPattern = dyn_cast(paramPattern)) - paramPattern = parenPattern->getSubPattern(); - if (auto varPattern = dyn_cast(paramPattern)) - paramPattern = varPattern->getSubPattern(); - auto typedParamPattern = dyn_cast(paramPattern); - if (!typedParamPattern) + TypeLoc TL = decl->getTypeLoc(); + if (!TL.getTypeRepr()) return; - TypeLoc TL = typedParamPattern->getTypeLoc(); - // Allow silencing this warning using parens. if (isa(TL.getType().getPointer())) return; - TC.diagnose(paramPattern->getLoc(), diag::override_unnecessary_IUO, + TC.diagnose(decl->getStartLoc(), diag::override_unnecessary_IUO, method->getDescriptiveKind(), parentParamTy, paramTy) .highlight(TL.getSourceRange()); @@ -4324,33 +4232,17 @@ class DeclChecker : public DeclVisitor { .fixItInsertAfter(TL.getSourceRange().End, ")"); }; - auto rawParamPatterns = method->getBodyParamPatterns()[1]; - auto paramPatterns = dyn_cast(rawParamPatterns); - + auto paramList = method->getParameterList(1); auto parentInput = parentTy->getInput(); - auto parentTupleInput = parentInput->getAs(); - if (parentTupleInput) { - if (paramPatterns) { - // FIXME: If we ever allow argument reordering, this is incorrect. - ArrayRef sharedParams = paramPatterns->getElements(); - sharedParams = sharedParams.slice(0, - parentTupleInput->getNumElements()); - - using PatternView = ArrayRefView; - for_each(PatternView(sharedParams), parentTupleInput->getElementTypes(), - checkParam); - } else if (parentTupleInput->getNumElements() > 0) { - checkParam(rawParamPatterns, parentTupleInput->getElementType(0)); - } + + if (auto parentTupleInput = parentInput->getAs()) { + // FIXME: If we ever allow argument reordering, this is incorrect. + ArrayRef sharedParams = paramList->getArray(); + sharedParams = sharedParams.slice(0, parentTupleInput->getNumElements()); + for_each(sharedParams, parentTupleInput->getElementTypes(), checkParam); } else { // Otherwise, the parent has a single parameter with no label. - if (paramPatterns) { - checkParam(paramPatterns->getElements().front().getPattern(), - parentInput); - } else { - checkParam(rawParamPatterns, parentInput); - } + checkParam(paramList->get(0), parentInput); } auto methodAsFunc = dyn_cast(method); @@ -4895,6 +4787,19 @@ class DeclChecker : public DeclVisitor { Override->getAttrs().add( new (TC.Context) DynamicAttr(/*implicit*/true)); } + + void visitSwift3MigrationAttr(Swift3MigrationAttr *attr) { + if (!Override->getAttrs().hasAttribute()) { + // Inherit swift3_migration attribute. + Override->getAttrs().add(new (TC.Context) Swift3MigrationAttr( + SourceLoc(), SourceLoc(), + SourceLoc(), + attr->getRenamed(), + attr->getMessage(), + SourceLoc(), + /*implicit=*/true)); + } + } }; /// Determine whether overriding the given declaration requires a keyword. @@ -4906,7 +4811,7 @@ class DeclChecker : public DeclVisitor { return true; } - /// Returns true if a diagnostic about an accessor being less available + /// Returns true if a diagnostic about an accessor being less available /// than the accessor it overrides would be redundant because we will /// already emit another diagnostic. static bool @@ -5406,7 +5311,7 @@ class DeclChecker : public DeclVisitor { TC.checkGenericParamList(&builder, gp, CD->getDeclContext()); // Infer requirements from the parameters of the constructor. - builder.inferRequirements(CD->getBodyParamPatterns()[1], gp); + builder.inferRequirements(CD->getParameterList(1), gp); // Revert the types within the signature so it can be type-checked with // archetypes below. @@ -5430,7 +5335,7 @@ class DeclChecker : public DeclVisitor { CD->setInvalid(); } else { configureConstructorType(CD, SelfTy, - CD->getBodyParamPatterns()[1]->getType(), + CD->getParameterList(1)->getType(TC.Context), CD->getThrowsLoc().isValid()); } @@ -5447,7 +5352,7 @@ class DeclChecker : public DeclVisitor { if (!CD->getOverriddenDecl()) { TC.diagnose(CD, diag::initializer_does_not_override) .highlight(attr->getLocation()); - CD->setInvalid(); + attr->setInvalid(); } else if (!overrideRequiresKeyword(CD->getOverriddenDecl())) { // Special case: we are overriding a 'required' initializer, so we // need (only) the 'required' keyword. @@ -5618,7 +5523,7 @@ bool TypeChecker::isAvailabilitySafeForConformance( return true; NominalTypeDecl *conformingDecl = DC->isNominalTypeOrNominalTypeExtensionContext(); - assert(conformingDecl && "Must have conformining declaration"); + assert(conformingDecl && "Must have conforming declaration"); // Make sure that any access of the witness through the protocol // can only occur when the witness is available. That is, make sure that @@ -5711,7 +5616,7 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) { validateExtension(ext); } } - + switch (D->getKind()) { case DeclKind::Import: case DeclKind::Extension: @@ -5769,14 +5674,37 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) { case DeclContextKind::FileUnit: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::Initializer: + case DeclContextKind::SubscriptDecl: llvm_unreachable("cannot have type params"); case DeclContextKind::NominalTypeDecl: { auto nominal = cast(DC); + typeCheckDecl(nominal, true); - if (auto assocType = dyn_cast(typeParam)) - if (!assocType->hasType()) - assocType->computeType(); + + // If this is an associated type that still has no type, then our type + // check of the nominal protocol type failed because it was invalid. This + // happens in various cases where sema of the protocol gives up on the + // invalid protocol decl. Install a type so that downstream things won't + // die due to getType() crashing on it. + // + // TODO: This is all really gross. If type checking the protocol is what + // is supposed to set up the archetype for the associated types, then it + // should guarantee that it happens. + // + if (auto assocType = dyn_cast(typeParam)) { + if (!assocType->hasType()) { + // Otherwise, fallback to setting it to error type. + if (nominal->isInvalid()) { + assocType->setType(Context.TheErrorType); + } else { + // Otherwise, we're in a recursive type checking situation, and + // the archetype for this AssocType may still be set. Compute a + // type even though we don't have it yet. + assocType->computeType(); + } + } + } if (!typeParam->hasAccessibility()) typeParam->setAccessibility(nominal->getFormalAccess()); break; @@ -5840,7 +5768,6 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) { checkInheritanceClause(D); validateAttributes(*this, D); - validateFixedLayoutAttribute(*this, nominal); // Mark a class as @objc. This must happen before checking its members. if (auto CD = dyn_cast(nominal)) { @@ -5914,9 +5841,9 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) { if (!archetype) return; + assocType->setArchetype(archetype); if (!assocType->hasType()) assocType->computeType(); - assocType->setArchetype(archetype); } } @@ -5966,13 +5893,12 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) { if (VD->getParentInitializer() && !VD->getParentInitializer()->getType()) { diagnose(parentPattern->getLoc(), diag::identifier_init_failure, - parentPattern->getBodyName()); + parentPattern->getBoundName()); } return; } - } else if (VD->isImplicit() && - (VD->getName() == Context.Id_self)) { + } else if (VD->isSelfParameter()) { // If the variable declaration is for a 'self' parameter, it may be // because the self variable was reverted whilst validating the function // signature. In that case, reset the type. @@ -6421,7 +6347,7 @@ static Optional buildDefaultInitializerString(TypeChecker &tc, return std::string(String); \ } CHECK_LITERAL_PROTOCOL(ArrayLiteralConvertible, "[]") - CHECK_LITERAL_PROTOCOL(DictionaryLiteralConvertible, "[]") + CHECK_LITERAL_PROTOCOL(DictionaryLiteralConvertible, "[:]") CHECK_LITERAL_PROTOCOL(UnicodeScalarLiteralConvertible, "\"\"") CHECK_LITERAL_PROTOCOL(ExtendedGraphemeClusterLiteralConvertible, "\"\"") CHECK_LITERAL_PROTOCOL(FloatLiteralConvertible, "0.0") @@ -6910,40 +6836,34 @@ void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) { if (!ctor || ctor->isInvalid()) continue; - auto paramTuple = ctor->getArgumentType()->getAs(); - if (!paramTuple) { - // A designated initializer other than a default initializer - // means we can't call super.init(). - if (ctor->isDesignatedInit()) - return; - - continue; - } - - // Check whether any of the tuple elements are missing an initializer. + // Check to see if this ctor has zero arguments, or if they all have + // default values. + auto params = ctor->getParameters(); + bool missingInit = false; - for (auto &elt : paramTuple->getElements()) { - if (elt.hasInit()) - continue; - - missingInit = true; - break; + for (auto param : *params) { + if (!param->isDefaultArgument()) { + missingInit = true; + break; + } } + + // Check to see if this is an impossible candidate. if (missingInit) { - // A designated initializer other than a default initializer - // means we can't call super.init(). + // If we found an impossible designated initializer, then we cannot + // call super.init(), even if there is a match. if (ctor->isDesignatedInit()) return; + // Otherwise, keep looking. continue; } - // We found a constructor that can be invoked with an empty tuple. - if (foundDefaultConstructor) { - // We found two constructors that can be invoked with an empty tuple. - foundDefaultConstructor = false; - break; - } + // Ok, we found a constructor that can be invoked with an empty tuple. + // If this is our second, then we bail out, because we don't want to + // pick one arbitrarily. + if (foundDefaultConstructor) + return; foundDefaultConstructor = true; } @@ -6965,23 +6885,6 @@ void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) { ctor->setBody(BraceStmt::create(Context, SourceLoc(), { }, SourceLoc())); } -static void validateFixedLayoutAttribute(TypeChecker &TC, - NominalTypeDecl *D) { - DeclAttributes &Attrs = D->getAttrs(); - - // FIXME: Add a per-module serialized HasFixedLayout flag, instead of - // giving every decl this attribute. - - if (Attrs.hasAttribute() || - TC.Context.LangOpts.EnableResilience) - return; - - // Since -enable-resilience should not change how we call into - // existing compiled modules, make all value types @_fixed_layout - // when the frontend is not run with the -enable-resilience flag. - Attrs.add(new (TC.Context) FixedLayoutAttr(/*IsImplicit*/ true)); -} - static void validateAttributes(TypeChecker &TC, Decl *D) { DeclAttributes &Attrs = D->getAttrs(); @@ -7004,6 +6907,12 @@ static void validateAttributes(TypeChecker &TC, Decl *D) { } else if (auto ED = dyn_cast(D)) { if (ED->isGenericContext()) error = diag::objc_enum_generic; + } else if (auto EED = dyn_cast(D)) { + auto ED = EED->getParentEnum(); + if (!ED->getAttrs().hasAttribute()) + error = diag::objc_enum_case_req_objc_enum; + else if (objcAttr->hasName() && EED->getParentCase()->getElements().size() > 1) + error = diag::objc_enum_case_multi; } else if (isa(D)) { auto func = cast(D); if (!checkObjCDeclContext(D)) @@ -7033,14 +6942,17 @@ static void validateAttributes(TypeChecker &TC, Decl *D) { // If there is a name, check whether the kind of name is // appropriate. if (auto objcName = objcAttr->getName()) { - if (isa(D) || isa(D) || isa(D)) { + if (isa(D) || isa(D) || isa(D) + || isa(D) || isa(D)) { // Types and properties can only have nullary // names. Complain and recover by chopping off everything // after the first name. if (objcName->getNumArgs() > 0) { - int which = isa(D)? 0 + int which = isa(D)? 0 : isa(D)? 1 - : 2; + : isa(D)? 2 + : isa(D)? 3 + : 4; SourceLoc firstNameLoc = objcAttr->getNameLocs().front(); SourceLoc afterFirstNameLoc = Lexer::getLocForEndOfToken(TC.Context.SourceMgr, firstNameLoc); @@ -7050,10 +6962,6 @@ static void validateAttributes(TypeChecker &TC, Decl *D) { ObjCSelector(TC.Context, 0, objcName->getSelectorPieces()[0]), /*implicit=*/false); } - } else if (isa(D)) { - // Enums don't have runtime names. - TC.diagnose(objcAttr->getLParenLoc(), diag::objc_name_enum); - const_cast(objcAttr)->clearName(); } else if (isa(D)) { // Subscripts can never have names. TC.diagnose(objcAttr->getLParenLoc(), diag::objc_name_subscript); @@ -7062,15 +6970,11 @@ static void validateAttributes(TypeChecker &TC, Decl *D) { // We have a function. Make sure that the number of parameters // matches the "number of colons" in the name. auto func = cast(D); - auto bodyPattern = func->getBodyParamPatterns()[1]; - unsigned numParameters; - if (isa(func) && - cast(func)->isObjCZeroParameterWithLongSelector()) - numParameters = 0; - else if (auto tuple = dyn_cast(bodyPattern)) - numParameters = tuple->getNumElements(); - else - numParameters = 1; + auto params = func->getParameterList(1); + unsigned numParameters = params->size(); + if (auto CD = dyn_cast(func)) + if (CD->isObjCZeroParameterWithLongSelector()) + numParameters = 0; // Something like "init(foo: ())" // A throwing method has an error parameter. if (func->isBodyThrowing()) @@ -7093,6 +6997,11 @@ static void validateAttributes(TypeChecker &TC, Decl *D) { D->getAttrs().removeAttribute(objcAttr); } } + } else if (isa(D)) { + // Enum elements require names. + TC.diagnose(objcAttr->getLocation(), diag::objc_enum_case_req_name) + .fixItRemove(objcAttr->getRangeWithAt()); + objcAttr->setInvalid(); } } @@ -7167,10 +7076,7 @@ void TypeChecker::fixAbstractFunctionNames(InFlightDiagnostic &diag, // Fix the argument names that need fixing. assert(name.getArgumentNames().size() == targetName.getArgumentNames().size()); - auto pattern - = func->getBodyParamPatterns()[func->getDeclContext()->isTypeContext()]; - auto tuplePattern = dyn_cast( - pattern->getSemanticsProvidingPattern()); + auto params = func->getParameterList(func->getDeclContext()->isTypeContext()); for (unsigned i = 0, n = name.getArgumentNames().size(); i != n; ++i) { auto origArg = name.getArgumentNames()[i]; auto targetArg = targetName.getArgumentNames()[i]; @@ -7178,68 +7084,34 @@ void TypeChecker::fixAbstractFunctionNames(InFlightDiagnostic &diag, if (origArg == targetArg) continue; - // Find the location to update or insert. - SourceLoc loc; - if (tuplePattern) { - auto origPattern = tuplePattern->getElement(i).getPattern(); - if (auto param = cast_or_null(origPattern->getSingleVar())) { - // The parameter has an explicitly-specified API name, and it's wrong. - if (param->getArgumentNameLoc() != param->getLoc() && - param->getArgumentNameLoc().isValid()) { - // ... but the internal parameter name was right. Just zap the - // incorrect explicit specialization. - if (param->getName() == targetArg) { - diag.fixItRemoveChars(param->getArgumentNameLoc(), - param->getLoc()); - continue; - } - - // Fix the API name. - StringRef targetArgStr = targetArg.empty()? "_" : targetArg.str(); - diag.fixItReplace(param->getArgumentNameLoc(), targetArgStr); - continue; - } - - // The parameter did not specify a separate API name. Insert one. - if (targetArg.empty()) - diag.fixItInsert(param->getLoc(), "_ "); - else { - llvm::SmallString<8> targetArgStr; - targetArgStr += targetArg.str(); - targetArgStr += ' '; - diag.fixItInsert(param->getLoc(), targetArgStr); - } - - if (param->isImplicit()) { - loc = origPattern->getLoc(); - } else { - continue; - } + auto *param = params->get(i); + + // The parameter has an explicitly-specified API name, and it's wrong. + if (param->getArgumentNameLoc() != param->getLoc() && + param->getArgumentNameLoc().isValid()) { + // ... but the internal parameter name was right. Just zap the + // incorrect explicit specialization. + if (param->getName() == targetArg) { + diag.fixItRemoveChars(param->getArgumentNameLoc(), + param->getLoc()); + continue; } - if (auto any = dyn_cast( - origPattern->getSemanticsProvidingPattern())) { - if (any->isImplicit()) { - loc = origPattern->getLoc(); - } else { - loc = any->getLoc(); - } - } else { - loc = origPattern->getLoc(); - } - } else if (auto paren = dyn_cast(pattern)) { - loc = paren->getSubPattern()->getLoc(); - } else { - loc = pattern->getLoc(); + // Fix the API name. + StringRef targetArgStr = targetArg.empty()? "_" : targetArg.str(); + diag.fixItReplace(param->getArgumentNameLoc(), targetArgStr); + continue; } - StringRef replacement; + // The parameter did not specify a separate API name. Insert one. if (targetArg.empty()) - replacement = "_"; - else - replacement = targetArg.str(); - - diag.fixItInsert(loc, replacement); + diag.fixItInsert(param->getLoc(), "_ "); + else { + llvm::SmallString<8> targetArgStr; + targetArgStr += targetArg.str(); + targetArgStr += ' '; + diag.fixItInsert(param->getLoc(), targetArgStr); + } } // FIXME: Update the AST accordingly. diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckError.cpp index 7e25a32aae7a4..85187c4a2203f 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckError.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -82,9 +82,6 @@ class AbstractFunction { /// Whether the function is marked 'rethrows'. bool isBodyRethrows() const { return IsRethrows; } - /// The uncurry level that 'rethrows' applies to. - unsigned getNumBodyParameters() const { return ParamCount; } - unsigned getNumArgumentsForFullApply() const { return (ParamCount - unsigned(IsProtocolMethod)); } @@ -213,6 +210,8 @@ class ErrorHandlingWalker : public ASTWalker { recurse = asImpl().checkDoCatch(doCatch); } else if (auto thr = dyn_cast(S)) { recurse = asImpl().checkThrow(thr); + } else if (auto ic = dyn_cast(S)) { + recurse = asImpl().checkIfConfig(ic); } else { assert(!isa(S)); } @@ -303,7 +302,7 @@ enum class ThrowingKind { Throws, }; -/// A type expressing the result of classifying whether an call or function +/// A type expressing the result of classifying whether a call or function /// throws. class Classification { ThrowingKind Result; @@ -572,6 +571,11 @@ class ApplyClassifier { Result = ThrowingKind::Throws; return ShouldRecurse; } + + ShouldRecurse_t checkIfConfig(IfConfigStmt *S) { + return ShouldRecurse; + } + void checkExhaustiveDoBody(DoCatchStmt *S) {} void checkNonExhaustiveDoBody(DoCatchStmt *S) { S->getBody()->walk(*this); @@ -1328,6 +1332,37 @@ class CheckErrorCoverage : public ErrorHandlingWalker { return ShouldRecurse; } + ShouldRecurse_t checkIfConfig(IfConfigStmt *S) { + // Check the inactive regions of a #if block to disable warnings that may + // be due to platform specific code. + struct ConservativeThrowChecker : public ASTWalker { + CheckErrorCoverage &CEC; + ConservativeThrowChecker(CheckErrorCoverage &CEC) : CEC(CEC) {} + + Expr *walkToExprPost(Expr *E) override { + if (isa(E)) + CEC.Flags.set(ContextFlags::HasAnyThrowSite); + return E; + } + + Stmt *walkToStmtPost(Stmt *S) override { + if (isa(S)) + CEC.Flags.set(ContextFlags::HasAnyThrowSite); + + return S; + } + }; + + for (auto &clause : S->getClauses()) { + // Active clauses are handled by the normal AST walk. + if (clause.isActive) continue; + + for (auto elt : clause.Elements) + elt.walk(ConservativeThrowChecker(*this)); + } + return ShouldRecurse; + } + ShouldRecurse_t checkThrow(ThrowStmt *S) { checkThrowSite(S, /*requiresTry*/ false, Classification::forThrow(PotentialReason::forThrow())); @@ -1382,7 +1417,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // Warn about 'try' expressions that weren't actually needed. if (!Flags.has(ContextFlags::HasTryThrowSite)) { - TC.diagnose(E->getTryLoc(), diag::no_throw_in_try); + if (!E->isImplicit()) + TC.diagnose(E->getTryLoc(), diag::no_throw_in_try); // Diagnose all the call sites within a single unhandled 'try' // at the same time. diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index d5b6016bd36ec..0c1009d645c7b 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -105,8 +105,7 @@ Expr *TypeChecker::substituteInputSugarTypeForResult(ApplyExpr *E) { // sugar on it. If so, propagate the sugar to the curried result function // type. if (isa(E) && isa(E->getArg())) { - auto resultSugar = - E->getArg()->getType()->castTo()->getInstanceType(); + auto resultSugar = cast(E->getArg())->getInstanceType(); // The result of this apply is "(args) -> T" where T is the type being // constructed. Apply the sugar onto it. @@ -142,7 +141,9 @@ static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { Associativity::Right, /*assignment*/ false); - } else if (auto *assign = dyn_cast(E)) { + } + + if (auto *assign = dyn_cast(E)) { // Assignment has fixed precedence. assert(!assign->isFolded() && "already folded assign expr in sequence?!"); (void)assign; @@ -150,7 +151,9 @@ static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { Associativity::Right, /*assignment*/ true); - } else if (auto *as = dyn_cast(E)) { + } + + if (auto *as = dyn_cast(E)) { // 'as' and 'is' casts have fixed precedence. assert(!as->isFolded() && "already folded 'as' expr in sequence?!"); (void)as; @@ -158,7 +161,9 @@ static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { Associativity::None, /*assignment*/ false); - } else if (DeclRefExpr *DRE = dyn_cast(E)) { + } + + if (DeclRefExpr *DRE = dyn_cast(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = DRE->getDecl()->getName(); bool isCascading = DC->isCascadingContextForLookup(true); @@ -166,7 +171,9 @@ static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { E->getLoc())) return op->getInfixData(); - } else if (OverloadedDeclRefExpr *OO = dyn_cast(E)) { + } + + if (OverloadedDeclRefExpr *OO = dyn_cast(E)) { SourceFile *SF = DC->getParentSourceFile(); Identifier name = OO->getDecls()[0]->getName(); bool isCascading = DC->isCascadingContextForLookup(true); @@ -174,8 +181,12 @@ static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) { E->getLoc())) return op->getInfixData(); } - - TC.diagnose(E->getLoc(), diag::unknown_binop); + + // If E is already an ErrorExpr, then we've diagnosed it as invalid already, + // otherwise emit an error. + if (!isa(E)) + TC.diagnose(E->getLoc(), diag::unknown_binop); + // Recover with an infinite-precedence left-associative operator. return InfixData((unsigned char)~0U, Associativity::Left, /*assignment*/ false); @@ -302,7 +313,7 @@ static Expr *makeBinOp(TypeChecker &TC, Expr *Op, Expr *LHS, Expr *RHS, SourceLoc(), ArgElts2, { }, { }, SourceLoc(), /*hasTrailingClosure=*/false, - LHS->isImplicit() && RHS->isImplicit()); + /*Implicit=*/true); @@ -550,14 +561,14 @@ Type TypeChecker::getUnopenedTypeOfReference(ValueDecl *value, Type baseType, } Expr *TypeChecker::buildCheckedRefExpr(ValueDecl *value, DeclContext *UseDC, - SourceLoc loc, bool Implicit) { + DeclNameLoc loc, bool Implicit) { auto type = getUnopenedTypeOfReference(value, Type(), UseDC); AccessSemantics semantics = value->getAccessSemanticsFromContext(UseDC); return new (Context) DeclRefExpr(value, loc, Implicit, semantics, type); } Expr *TypeChecker::buildRefExpr(ArrayRef Decls, - DeclContext *UseDC, SourceLoc NameLoc, + DeclContext *UseDC, DeclNameLoc NameLoc, bool Implicit, bool isSpecialized) { assert(!Decls.empty() && "Must have at least one declaration"); @@ -837,7 +848,7 @@ namespace { TC.diagnose(NTD->getLoc(), diag::type_declared_here); TC.diagnose(D->getLoc(), diag::decl_declared_here, - D->getName()); + D->getFullName()); return { false, DRE }; } @@ -917,7 +928,7 @@ namespace { } } TC.diagnose(capturedDecl->getLoc(), diag::decl_declared_here, - capturedDecl->getName()); + capturedDecl->getFullName()); } return false; }; @@ -974,8 +985,14 @@ namespace { bool walkToDeclPre(Decl *D) override { if (auto *AFD = dyn_cast(D)) { propagateCaptures(AFD, AFD->getLoc()); - for (auto *paramPattern : AFD->getBodyParamPatterns()) - paramPattern->walk(*this); + + // Can default parameter initializers capture state? That seems like + // a really bad idea. + for (auto *paramList : AFD->getParameterLists()) + for (auto param : *paramList) { + if (auto E = param->getDefaultValue()) + E->getExpr()->walk(*this); + } return false; } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index cfa88ac1d6ca0..6bb7d1292371d 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -31,8 +31,7 @@ Type DependentGenericTypeResolver::resolveDependentMemberType( SourceRange baseRange, ComponentIdentTypeRepr *ref) { auto archetype = Builder.resolveArchetype(baseTy); - if (!archetype) - return ErrorType::get(DC->getASTContext()); + assert(archetype && "Bad generic context nesting?"); return archetype->getRepresentative() ->getNestedType(ref->getIdentifier(), Builder) @@ -44,8 +43,7 @@ Type DependentGenericTypeResolver::resolveSelfAssociatedType( DeclContext *DC, AssociatedTypeDecl *assocType) { auto archetype = Builder.resolveArchetype(selfTy); - if (!archetype) - return ErrorType::get(DC->getASTContext()); + assert(archetype && "Bad generic context nesting?"); return archetype->getRepresentative() ->getNestedType(assocType->getName(), Builder) @@ -218,20 +216,6 @@ Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) { return ext->getExtendedType()->getAnyNominal()->getDeclaredInterfaceType(); } -/// Add the generic parameters and requirements from the parent context to the -/// archetype builder. -static void addContextParamsAndRequirements(ArchetypeBuilder &builder, - DeclContext *dc, - bool adoptArchetypes) { - if (!dc->isTypeContext()) - return; - - if (auto sig = dc->getGenericSignatureOfContext()) { - // Add generic signature from this context. - builder.addGenericSignature(sig, adoptArchetypes); - } -} - /// Check the generic parameters in the given generic parameter list (and its /// parent generic parameter lists) according to the given resolver. bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, @@ -244,7 +228,8 @@ bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, // If there is a parent context, add the generic parameters and requirements // from that context. if (builder && parentDC) - addContextParamsAndRequirements(*builder, parentDC, adoptArchetypes); + if (auto sig = parentDC->getGenericSignatureOfContext()) + builder->addGenericSignature(sig, adoptArchetypes); // If there aren't any generic parameters at this level, we're done. if (!genericParams) @@ -297,7 +282,7 @@ bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, continue; switch (req.getKind()) { - case RequirementKind::Conformance: { + case RequirementReprKind::TypeConstraint: { // Validate the types. if (validateType(req.getSubjectLoc(), lookupDC, options, resolver)) { invalid = true; @@ -327,7 +312,7 @@ bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, break; } - case RequirementKind::SameType: + case RequirementReprKind::SameType: if (validateType(req.getFirstTypeLoc(), lookupDC, options, resolver)) { invalid = true; @@ -343,9 +328,6 @@ bool TypeChecker::checkGenericParamList(ArchetypeBuilder *builder, } break; - - case RequirementKind::WitnessMarker: - llvm_unreachable("value witness markers in syntactic requirement?"); } if (builder && builder->addRequirement(req)) { @@ -363,15 +345,12 @@ static void collectGenericParamTypes( GenericParamList *genericParams, DeclContext *parentDC, SmallVectorImpl &allParams) { - // If the parent context is a generic type (or nested type thereof), - // add its generic parameters. - if (parentDC->isTypeContext()) { - if (auto parentSig = parentDC->getGenericSignatureOfContext()) { - allParams.append(parentSig->getGenericParams().begin(), - parentSig->getGenericParams().end()); - } + // If the parent context has a generic signature, add its generic parameters. + if (auto parentSig = parentDC->getGenericSignatureOfContext()) { + allParams.append(parentSig->getGenericParams().begin(), + parentSig->getGenericParams().end()); } - + if (genericParams) { // Add our parameters. for (auto param : *genericParams) { @@ -381,186 +360,6 @@ static void collectGenericParamTypes( } } -namespace { - /// \brief Function object that orders potential archetypes by name. - struct OrderPotentialArchetypeByName { - using PotentialArchetype = ArchetypeBuilder::PotentialArchetype; - - bool operator()(std::pair X, - std::pair Y) const { - return X.first.str() < Y.second->getName().str(); - } - - bool operator()(std::pair X, - Identifier Y) const { - return X.first.str() < Y.str(); - } - - bool operator()(Identifier X, - std::pair Y) const { - return X.str() < Y.first.str(); - } - - bool operator()(Identifier X, Identifier Y) const { - return X.str() < Y.str(); - } - }; -} - -/// Add the requirements for the given potential archetype and its nested -/// potential archetypes to the set of requirements. -static void -addRequirements( - Module &mod, Type type, - ArchetypeBuilder::PotentialArchetype *pa, - llvm::SmallPtrSet &knownPAs, - SmallVectorImpl &requirements) { - // If the potential archetype has been bound away to a concrete type, - // it needs no requirements. - if (pa->isConcreteType()) - return; - - // Add a value witness marker. - requirements.push_back(Requirement(RequirementKind::WitnessMarker, - type, Type())); - - // Add superclass requirement, if needed. - if (auto superclass = pa->getSuperclass()) { - // FIXME: Distinguish superclass from conformance? - // FIXME: What if the superclass type involves a type parameter? - requirements.push_back(Requirement(RequirementKind::Conformance, - type, superclass)); - } - - // Add conformance requirements. - SmallVector protocols; - for (const auto &conforms : pa->getConformsTo()) { - protocols.push_back(conforms.first); - } - - ProtocolType::canonicalizeProtocols(protocols); - for (auto proto : protocols) { - requirements.push_back(Requirement(RequirementKind::Conformance, - type, proto->getDeclaredType())); - } -} - -static void -addNestedRequirements( - Module &mod, Type type, - ArchetypeBuilder::PotentialArchetype *pa, - llvm::SmallPtrSet &knownPAs, - SmallVectorImpl &requirements) { - using PotentialArchetype = ArchetypeBuilder::PotentialArchetype; - - // Collect the nested types, sorted by name. - // FIXME: Could collect these from the conformance requirements, above. - SmallVector, 16> nestedTypes; - for (const auto &nested : pa->getNestedTypes()) { - // FIXME: Dropping requirements among different associated types of the - // same name. - nestedTypes.push_back(std::make_pair(nested.first, nested.second.front())); - } - std::sort(nestedTypes.begin(), nestedTypes.end(), - OrderPotentialArchetypeByName()); - - // Add requirements for associated types. - for (const auto &nested : nestedTypes) { - auto rep = nested.second->getRepresentative(); - if (knownPAs.insert(rep).second) { - // Form the dependent type that refers to this archetype. - auto assocType = nested.second->getResolvedAssociatedType(); - if (!assocType) - continue; // FIXME: If we do this late enough, there will be no failure. - - // Skip nested types bound to concrete types. - if (rep->isConcreteType()) - continue; - - auto nestedType = DependentMemberType::get(type, assocType, - mod.getASTContext()); - - addRequirements(mod, nestedType, rep, knownPAs, requirements); - addNestedRequirements(mod, nestedType, rep, knownPAs, requirements); - } - } -} - -/// Collect the set of requirements placed on the given generic parameters and -/// their associated types. -static void collectRequirements(ArchetypeBuilder &builder, - ArrayRef params, - SmallVectorImpl &requirements) { - typedef ArchetypeBuilder::PotentialArchetype PotentialArchetype; - - // Find the "primary" potential archetypes, from which we'll collect all - // of the requirements. - llvm::SmallPtrSet knownPAs; - llvm::SmallVector primary; - for (auto param : params) { - auto pa = builder.resolveArchetype(param); - assert(pa && "Missing potential archetype for generic parameter"); - - // We only care about the representative. - pa = pa->getRepresentative(); - - if (knownPAs.insert(pa).second) - primary.push_back(param); - } - - // Add all of the conformance and superclass requirements placed on the given - // generic parameters and their associated types. - unsigned primaryIdx = 0, numPrimary = primary.size(); - while (primaryIdx < numPrimary) { - unsigned depth = primary[primaryIdx]->getDepth(); - - // For each of the primary potential archetypes, add the requirements. - // Stop when we hit a parameter at a different depth. - // FIXME: This algorithm falls out from the way the "all archetypes" lists - // are structured. Once those lists no longer exist or are no longer - // "the truth", we can simplify this algorithm considerably. - unsigned lastPrimaryIdx = primaryIdx; - for (unsigned idx = primaryIdx; - idx < numPrimary && primary[idx]->getDepth() == depth; - ++idx, ++lastPrimaryIdx) { - auto param = primary[idx]; - auto pa = builder.resolveArchetype(param)->getRepresentative(); - - // Add other requirements. - addRequirements(builder.getModule(), param, pa, knownPAs, - requirements); - } - - // For each of the primary potential archetypes, add the nested requirements. - for (unsigned idx = primaryIdx; idx < lastPrimaryIdx; ++idx) { - auto param = primary[idx]; - auto pa = builder.resolveArchetype(param)->getRepresentative(); - addNestedRequirements(builder.getModule(), param, pa, knownPAs, - requirements); - } - - primaryIdx = lastPrimaryIdx; - } - - - // Add all of the same-type requirements. - for (auto req : builder.getSameTypeRequirements()) { - auto firstType = req.first->getDependentType(builder, false); - Type secondType; - if (auto concrete = req.second.dyn_cast()) - secondType = concrete; - else if (auto secondPA = req.second.dyn_cast()) - secondType = secondPA->getDependentType(builder, false); - - if (firstType->is() || secondType->is() || - firstType->isEqual(secondType)) - continue; - - requirements.push_back(Requirement(RequirementKind::SameType, - firstType, secondType)); - } -} - /// Check the signature of a generic function. static bool checkGenericFuncSignature(TypeChecker &tc, ArchetypeBuilder *builder, @@ -577,15 +376,15 @@ static bool checkGenericFuncSignature(TypeChecker &tc, false, &resolver); // Check the parameter patterns. - for (auto pattern : func->getBodyParamPatterns()) { + for (auto params : func->getParameterLists()) { // Check the pattern. - if (tc.typeCheckPattern(pattern, func, TR_ImmediateFunctionInput, - &resolver)) + if (tc.typeCheckParameterList(params, func, TypeResolutionOptions(), + &resolver)) badType = true; // Infer requirements from the pattern. if (builder) { - builder->inferRequirements(pattern, genericParams); + builder->inferRequirements(params, genericParams); } } @@ -593,7 +392,7 @@ static bool checkGenericFuncSignature(TypeChecker &tc, if (auto fn = dyn_cast(func)) { if (!fn->getBodyResultTypeLoc().isNull()) { // Check the result type of the function. - TypeResolutionOptions options = TR_FunctionResult; + TypeResolutionOptions options; if (fn->hasDynamicSelf()) options |= TR_DynamicSelfResult; @@ -693,12 +492,8 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) { func->getDeclContext(), allGenericParams); - // Collect the requirements placed on the generic parameter types. - SmallVector requirements; - collectRequirements(builder, allGenericParams, requirements); - - auto sig = GenericSignature::get(allGenericParams, requirements); - + auto sig = builder.getGenericSignature(allGenericParams); + // Debugging of the archetype builder and generic signature generation. if (sig && Context.LangOpts.DebugGenericSignatures) { func->dumpRef(llvm::errs()); @@ -755,23 +550,20 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) { funcTy = TupleType::getEmpty(Context); } - auto patterns = func->getBodyParamPatterns(); - SmallVector storedPatterns; + auto paramLists = func->getParameterLists(); + SmallVector storedParamLists; // FIXME: Destructors don't have the '()' pattern in their signature, so // paste it here. if (isa(func)) { - storedPatterns.append(patterns.begin(), patterns.end()); - - Pattern *pattern = TuplePattern::create(Context, SourceLoc(), { }, - SourceLoc(), /*Implicit=*/true); - pattern->setType(TupleType::getEmpty(Context)); - storedPatterns.push_back(pattern); - patterns = storedPatterns; + assert(paramLists.size() == 1 && "Only the self paramlist"); + storedParamLists.push_back(paramLists[0]); + storedParamLists.push_back(ParameterList::createEmpty(Context)); + paramLists = storedParamLists; } bool hasSelf = func->getDeclContext()->isTypeContext(); - for (unsigned i = 0, e = patterns.size(); i != e; ++i) { + for (unsigned i = 0, e = paramLists.size(); i != e; ++i) { Type argTy; Type initArgTy; @@ -785,7 +577,7 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) { initArgTy = func->computeInterfaceSelfType(/*isInitializingCtor=*/true); } } else { - argTy = patterns[e - i - 1]->getType(); + argTy = paramLists[e - i - 1]->getType(Context); // For an implicit declaration, our argument type will be in terms of // archetypes rather than dependent types. Replace the @@ -928,14 +720,8 @@ GenericSignature *TypeChecker::validateGenericSignature( SmallVector allGenericParams; collectGenericParamTypes(genericParams, dc, allGenericParams); - // Collect the requirements placed on the generic parameter types. - // FIXME: This ends up copying all of the requirements from outer scopes, - // which is mostly harmless (but quite annoying). - SmallVector requirements; - collectRequirements(builder, allGenericParams, requirements); - // Record the generic type parameter types and the requirements. - auto sig = GenericSignature::get(allGenericParams, requirements); + auto sig = builder.getGenericSignature(allGenericParams); // Debugging of the archetype builder and generic signature generation. if (Context.LangOpts.DebugGenericSignatures) { @@ -1071,18 +857,20 @@ bool TypeChecker::checkGenericArguments(DeclContext *dc, SourceLoc loc, switch (req.getKind()) { case RequirementKind::Conformance: { // Protocol conformance requirements. - if (auto proto = secondType->getAs()) { - // FIXME: This should track whether this should result in a private - // or non-private dependency. - // FIXME: Do we really need "used" at this point? - // FIXME: Poor location information. How much better can we do here? - if (!conformsToProtocol(firstType, proto->getDecl(), dc, - ConformanceCheckFlags::Used, nullptr, loc)) - return true; - - continue; + auto proto = secondType->castTo(); + // FIXME: This should track whether this should result in a private + // or non-private dependency. + // FIXME: Do we really need "used" at this point? + // FIXME: Poor location information. How much better can we do here? + if (!conformsToProtocol(firstType, proto->getDecl(), dc, + ConformanceCheckFlags::Used, nullptr, loc)) { + return true; } + continue; + } + + case RequirementKind::Superclass: // Superclass requirements. if (!isSubtypeOf(firstType, secondType, dc)) { // FIXME: Poor source-location information. @@ -1096,9 +884,7 @@ bool TypeChecker::checkGenericArguments(DeclContext *dc, SourceLoc loc, genericParams, substitutions)); return true; } - continue; - } case RequirementKind::SameType: if (!firstType->isEqual(secondType)) { diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 14ed9159ad102..544f577db3fbb 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -239,6 +239,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::DynamicLookup)) subOptions |= NL_DynamicLookup; + if (options.contains(NameLookupFlags::IgnoreAccessibility)) + subOptions |= NL_IgnoreAccessibility; // Dig out the type that we'll actually be looking into, and determine // whether it is a nominal type. @@ -325,7 +327,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, if (options.contains(NameLookupFlags::KnownPrivate)) subOptions |= NL_KnownNonCascadingDependency; if (options.contains(NameLookupFlags::ProtocolMembers)) - subOptions |= NL_ProtocolMembers; + subOptions |= NL_ProtocolMembers; + if (options.contains(NameLookupFlags::IgnoreAccessibility)) + subOptions |= NL_IgnoreAccessibility; if (!dc->lookupQualified(type, name, subOptions, this, decls)) return result; diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 957f3458356a4..c27cbd79c2a94 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,6 +19,7 @@ #include "GenericTypeResolver.h" #include "swift/AST/Attr.h" #include "swift/AST/ExprHandle.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/NameLookup.h" #include "llvm/Support/SaveAndRestore.h" @@ -155,7 +156,8 @@ struct ExprToIdentTypeRepr : public ASTVisitor assert(components.empty() && "decl ref should be root element of expr"); // Track the AST location of the component. components.push_back( - new (C) SimpleIdentTypeRepr(udre->getLoc(), udre->getName())); + new (C) SimpleIdentTypeRepr(udre->getLoc(), + udre->getName().getBaseName())); return true; } @@ -167,7 +169,7 @@ struct ExprToIdentTypeRepr : public ASTVisitor // Track the AST location of the new component. components.push_back( - new (C) SimpleIdentTypeRepr(ude->getLoc(), ude->getName())); + new (C) SimpleIdentTypeRepr(ude->getLoc(), ude->getName().getBaseName())); return true; } @@ -368,8 +370,7 @@ class ResolvePattern : public ASTVisitorgetElement(i)); patternElts.push_back(TuplePatternElt(E->getElementName(i), E->getElementNameLoc(i), - pattern, - false)); + pattern)); } return TuplePattern::create(TC.Context, E->getLoc(), @@ -405,11 +406,13 @@ class ResolvePattern : public ASTVisitorgetDotLoc(), - ume->getNameLoc(), - ume->getName(), - nullptr, - subPattern); + // FIXME: Compound names. + return new (TC.Context) EnumElementPattern( + TypeLoc(), ume->getDotLoc(), + ume->getNameLoc().getBaseNameLoc(), + ume->getName().getBaseName(), + nullptr, + subPattern); } // Member syntax 'T.Element' forms a pattern if 'T' is an enum and the @@ -431,16 +434,19 @@ class ResolvePattern : public ASTVisitorgetName()); + = lookupEnumMemberElement(TC, DC, ty, ude->getName().getBaseName()); // Build a TypeRepr from the head of the full path. + // FIXME: Compound names. TypeLoc loc(repr); loc.setType(ty); return new (TC.Context) EnumElementPattern(loc, ude->getDotLoc(), - ude->getNameLoc(), - ude->getName(), + ude->getNameLoc() + .getBaseNameLoc(), + ude->getName().getBaseName(), referencedElement, nullptr); } @@ -467,14 +473,15 @@ class ResolvePattern : public ASTVisitorgetName())) { + = lookupUnqualifiedEnumMemberElement(TC, DC, + ude->getName().getBaseName())) { auto *enumDecl = referencedElement->getParentEnum(); auto enumTy = enumDecl->getDeclaredTypeInContext(); TypeLoc loc = TypeLoc::withoutLoc(enumTy); return new (TC.Context) EnumElementPattern(loc, SourceLoc(), ude->getLoc(), - ude->getName(), + ude->getName().getBaseName(), referencedElement, nullptr); } @@ -692,37 +699,93 @@ static bool validateTypedPattern(TypeChecker &TC, DeclContext *DC, TypedPattern *TP, TypeResolutionOptions options, GenericTypeResolver *resolver) { - if (TP->hasType()) { + if (TP->hasType()) return TP->getType()->is(); - } - bool hadError = false; TypeLoc &TL = TP->getTypeLoc(); - if (TC.validateType(TL, DC, options, resolver)) - hadError = true; - Type Ty = TL.getType(); + bool hadError = TC.validateType(TL, DC, options, resolver); + + if (hadError) + TP->setType(ErrorType::get(TC.Context)); + else + TP->setType(TL.getType()); + return hadError; +} + - if ((options & TR_Variadic) && !hadError) { +static bool validateParameterType(ParamDecl *decl, DeclContext *DC, + TypeResolutionOptions options, + GenericTypeResolver *resolver, + TypeChecker &TC) { + if (auto ty = decl->getTypeLoc().getType()) + return ty->is(); + + bool hadError = TC.validateType(decl->getTypeLoc(), DC, + options|TR_FunctionInput, resolver); + + Type Ty = decl->getTypeLoc().getType(); + if (decl->isVariadic() && !hadError) { // If isn't legal to declare something both inout and variadic. if (Ty->is()) { - TC.diagnose(TP->getLoc(), diag::inout_cant_be_variadic); + TC.diagnose(decl->getStartLoc(), diag::inout_cant_be_variadic); hadError = true; } else { - // FIXME: Use ellipsis loc for diagnostic. - Ty = TC.getArraySliceType(TP->getLoc(), Ty); - if (Ty.isNull()) + Ty = TC.getArraySliceType(decl->getStartLoc(), Ty); + if (Ty.isNull()) { hadError = true; + } } + decl->getTypeLoc().setType(Ty); } - if (hadError) { - TP->setType(ErrorType::get(TC.Context)); - } else { - TP->setType(Ty); + if (hadError) + decl->getTypeLoc().setType(ErrorType::get(TC.Context), /*validated*/true); + + return hadError; +} + +/// Type check a parameter list. +bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC, + TypeResolutionOptions options, + GenericTypeResolver *resolver) { + bool hadError = false; + + for (auto param : *PL) { + if (param->getTypeLoc().getTypeRepr()) + hadError |= validateParameterType(param, DC, options, resolver, *this); + + auto type = param->getTypeLoc().getType(); + if (!type && param->hasType()) { + type = param->getType(); + param->getTypeLoc().setType(type); + } + + // If there was no type specified, and if we're not looking at a + // ClosureExpr, then we have a parse error (no type was specified). The + // parser will have already diagnosed this, but treat this as a type error + // as well to get the ParamDecl marked invalid and to get an ErrorType. + if (!type) { + // Closure argument lists are allowed to be missing types. + if (options & TR_InExpression) + continue; + param->setInvalid(); + } + + if (param->isInvalid()) { + param->overwriteType(ErrorType::get(Context)); + hadError = true; + } else + param->overwriteType(type); + + checkTypeModifyingDeclAttributes(param); + if (param->getType()->is()) + param->setLet(false); } + return hadError; } + bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, TypeResolutionOptions options, GenericTypeResolver *resolver) { @@ -731,7 +794,6 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, if (!resolver) resolver = &defaultResolver; - TypeResolutionOptions subOptions = options - TR_Variadic; switch (P->getKind()) { // Type-check paren patterns by checking the sub-pattern and // propagating that type out. @@ -742,7 +804,7 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, SP = PP->getSubPattern(); else SP = cast(P)->getSubPattern(); - if (typeCheckPattern(SP, dc, subOptions, resolver)) { + if (typeCheckPattern(SP, dc, options, resolver)) { P->setType(ErrorType::get(Context)); return true; } @@ -798,19 +860,15 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, // If this is the top level of a function input list, peel off the // ImmediateFunctionInput marker and install a FunctionInput one instead. - auto elementOptions = withoutContext(subOptions); - if (subOptions & TR_ImmediateFunctionInput) + auto elementOptions = withoutContext(options); + if (options & TR_ImmediateFunctionInput) elementOptions |= TR_FunctionInput; bool missingType = false; for (unsigned i = 0, e = tuplePat->getNumElements(); i != e; ++i) { TuplePatternElt &elt = tuplePat->getElement(i); Pattern *pattern = elt.getPattern(); - bool hasEllipsis = elt.hasEllipsis(); - TypeResolutionOptions eltOptions = elementOptions; - if (hasEllipsis) - eltOptions |= TR_Variadic; - if (typeCheckPattern(pattern, dc, eltOptions, resolver)){ + if (typeCheckPattern(pattern, dc, elementOptions, resolver)){ hadError = true; continue; } @@ -819,10 +877,7 @@ bool TypeChecker::typeCheckPattern(Pattern *P, DeclContext *dc, continue; } - typeElts.push_back(TupleTypeElt(pattern->getType(), - elt.getLabel(), - elt.getDefaultArgKind(), - hasEllipsis)); + typeElts.push_back(TupleTypeElt(pattern->getType(), elt.getLabel())); } if (hadError) { @@ -884,7 +939,8 @@ static bool coercePatternViaConditionalDowncast(TypeChecker &tc, matchVar->setHasNonPatternBindingInit(); // Form the cast $match as? T, which produces an optional. - Expr *matchRef = new (tc.Context) DeclRefExpr(matchVar, pattern->getLoc(), + Expr *matchRef = new (tc.Context) DeclRefExpr(matchVar, + DeclNameLoc(pattern->getLoc()), /*Implicit=*/true); Expr *cast = new (tc.Context) ConditionalCheckedCastExpr( matchRef, @@ -909,8 +965,7 @@ static bool coercePatternViaConditionalDowncast(TypeChecker &tc, bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, TypeResolutionOptions options, GenericTypeResolver *resolver) { - TypeResolutionOptions subOptions - = options - TR_Variadic - TR_EnumPatternPayload; + TypeResolutionOptions subOptions = options - TR_EnumPatternPayload; switch (P->getKind()) { // For parens and vars, just set the type annotation and propagate inwards. case PatternKind::Paren: { @@ -1043,10 +1098,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, // TODO: permit implicit conversions? case PatternKind::Tuple: { TuplePattern *TP = cast(P); - bool hadError = false; - - if (type->is()) - hadError = true; + bool hadError = type->is(); // Sometimes a paren is just a paren. If the tuple pattern has a single // element, we can reduce it to a paren pattern. @@ -1079,7 +1131,6 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, } // The number of elements must match exactly. - // TODO: incomplete tuple patterns, with some syntax. if (!hadError && tupleTy->getNumElements() != TP->getNumElements()) { if (canDecayToParen) return decayToParen(); @@ -1094,7 +1145,6 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, for (unsigned i = 0, e = TP->getNumElements(); i != e; ++i) { TuplePatternElt &elt = TP->getElement(i); Pattern *pattern = elt.getPattern(); - bool hasEllipsis = elt.hasEllipsis(); Type CoercionType; if (hadError) @@ -1104,52 +1154,17 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, // If the tuple pattern had a label for the tuple element, it must match // the label for the tuple type being matched. - // TODO: detect and diagnose shuffling - // TODO: permit shuffling if (!hadError && !elt.getLabel().empty() && - i < tupleTy->getNumElements() && elt.getLabel() != tupleTy->getElement(i).getName()) { diagnose(elt.getLabelLoc(), diag::tuple_pattern_label_mismatch, elt.getLabel(), tupleTy->getElement(i).getName()); hadError = true; } - TypeResolutionOptions subOptions = options - TR_Variadic; - if (hasEllipsis) - subOptions |= TR_Variadic; - hadError |= coercePatternToType(pattern, dc, CoercionType, subOptions, - resolver); + hadError |= coercePatternToType(pattern, dc, CoercionType, + options, resolver); if (!hadError) elt.setPattern(pattern); - - // Type-check the initialization expression. - assert(!elt.getInit() && - "Tuples cannot have default values, only parameters"); - } - - // For Swift 2.0, we ban single-element tuple patterns that have labels. - // They are too confusingly similar to parenthesized typed patterns that - // were allowed in Swift 1.x, and it is always safe to just remove the tuple - // label if it was desired. We can relax this limitation later if necessary. - // - // Note that we allow these in enum contexts and in function/closure - // argument lists, since being able to name the first argument of a function - // is still considered to be important. - if (!hadError && TP->getNumElements() == 1 && - !TP->getElement(0).getLabel().empty() && - !(options & TR_EnumPatternPayload) && - !(options & TR_FunctionInput) && - !(options & TR_ImmediateFunctionInput)) { - SourceLoc LabelLoc = TP->getElement(0).getLabelLoc(); - diagnose(LabelLoc, diag::label_single_entry_tuple); - // Emit two notes with fixits offering help to resolve this ambiguity. - diagnose(TP->getLParenLoc(), diag::remove_parens_for_type_annotation) - .fixItRemove(TP->getLParenLoc()).fixItRemove(TP->getRParenLoc()); - unsigned LabelLen = TP->getElement(0).getLabel().getLength(); - diagnose(LabelLoc, diag::remove_label_for_tuple_pattern) - .fixItRemove(SourceRange(LabelLoc, - LabelLoc.getAdvancedLocOrInvalid(LabelLen))); - hadError = true; } return hadError; @@ -1229,7 +1244,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, IP->getLoc(), IP->getLoc(),IP->getCastTypeLoc().getSourceRange(), [](Type) { return false; }, - /*suppressDiagnostics=*/ false); + /*suppressDiagnostics=*/ type->is()); switch (castKind) { case CheckedCastKind::Unresolved: return false; @@ -1288,8 +1303,9 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, if (type->getAnyNominal()) elt = lookupEnumMemberElement(*this, dc, type, EEP->getName()); if (!elt) { - diagnose(EEP->getLoc(), diag::enum_element_pattern_member_not_found, - EEP->getName().str(), type); + if (!type->is()) + diagnose(EEP->getLoc(), diag::enum_element_pattern_member_not_found, + EEP->getName().str(), type); return true; } enumTy = type; @@ -1533,3 +1549,85 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type, } llvm_unreachable("bad pattern kind!"); } + + +/// Coerce the specified parameter list of a ClosureExpr to the specified +/// contextual type. +/// +/// \returns true if an error occurred, false otherwise. +/// +/// TODO: These diagnostics should be a lot better now that we know this is +/// all specific to closures. +/// +bool TypeChecker::coerceParameterListToType(ParameterList *P, DeclContext *DC, + Type paramListType) { + bool hadError = paramListType->is(); + + // Sometimes a scalar type gets applied to a single-argument parameter list. + auto handleParameter = [&](ParamDecl *param, Type ty) -> bool { + bool hadError = false; + + // Check that the type, if explicitly spelled, is ok. + if (param->getTypeLoc().getTypeRepr()) { + hadError |= validateParameterType(param, DC, TypeResolutionOptions(), + nullptr, *this); + + // Now that we've type checked the explicit argument type, see if it + // agrees with the contextual type. + if (!hadError && !ty->isEqual(param->getTypeLoc().getType()) && + !ty->is()) + param->overwriteType(ty); + } + + if (param->isInvalid()) + param->overwriteType(ErrorType::get(Context)); + else + param->overwriteType(ty); + + checkTypeModifyingDeclAttributes(param); + if (ty->is()) + param->setLet(false); + return hadError; + }; + + + // The context type must be a tuple. + TupleType *tupleTy = paramListType->getAs(); + if (!tupleTy && !hadError) { + if (P->size() == 1) + return handleParameter(P->get(0), paramListType); + diagnose(P->getStartLoc(), diag::tuple_pattern_in_non_tuple_context, + paramListType); + hadError = true; + } + + // The number of elements must match exactly. + // TODO: incomplete tuple patterns, with some syntax. + if (!hadError && tupleTy->getNumElements() != P->size()) { + if (P->size() == 1) + return handleParameter(P->get(0), paramListType); + + diagnose(P->getStartLoc(), diag::tuple_pattern_length_mismatch, + paramListType); + hadError = true; + } + + // Coerce each parameter to the respective type. + for (unsigned i = 0, e = P->size(); i != e; ++i) { + auto ¶m = P->get(i); + + Type CoercionType; + if (hadError) + CoercionType = ErrorType::get(Context); + else + CoercionType = tupleTy->getElement(i).getType(); + + assert(param->getArgumentName().empty() && + "Closures cannot have API names"); + + hadError |= handleParameter(param, CoercionType); + assert(!param->isDefaultArgument() && "Closures cannot have default args"); + } + + return hadError; +} diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index a17dfa26d0560..4cde96eb1491e 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -561,37 +561,20 @@ SourceLoc OptionalAdjustment::getOptionalityLoc(ValueDecl *witness) const { } // For parameter adjustments, dig out the pattern. - Pattern *pattern = nullptr; + ParameterList *params = nullptr; if (auto func = dyn_cast(witness)) { - auto bodyPatterns = func->getBodyParamPatterns(); + auto bodyParamLists = func->getParameterLists(); if (func->getDeclContext()->isTypeContext()) - bodyPatterns = bodyPatterns.slice(1); - pattern = bodyPatterns[0]; + bodyParamLists = bodyParamLists.slice(1); + params = bodyParamLists[0]; } else if (auto subscript = dyn_cast(witness)) { - pattern = subscript->getIndices(); + params = subscript->getIndices(); } else { return SourceLoc(); } - // Handle parentheses. - if (auto paren = dyn_cast(pattern)) { - assert(getParameterIndex() == 0 && "just the one parameter"); - if (auto typed = dyn_cast(paren->getSubPattern())) { - return getOptionalityLoc(typed->getTypeLoc().getTypeRepr()); - } - return SourceLoc(); - } - - // Handle tuples. - auto tuple = dyn_cast(pattern); - if (!tuple) - return SourceLoc(); - - const auto &tupleElt = tuple->getElement(getParameterIndex()); - if (auto typed = dyn_cast(tupleElt.getPattern())) { - return getOptionalityLoc(typed->getTypeLoc().getTypeRepr()); - } - return SourceLoc(); + return getOptionalityLoc(params->get(getParameterIndex())->getTypeLoc() + .getTypeRepr()); } SourceLoc OptionalAdjustment::getOptionalityLoc(TypeRepr *tyR) const { @@ -669,74 +652,26 @@ static SmallVector decomposeIntoTupleElements(Type type) { return result; } -namespace { - /// Dependent type opener that maps the type of a requirement, replacing - /// already-known associated types to their type witnesses and inner generic - /// parameters to their archetypes. - class RequirementTypeOpener : public constraints::DependentTypeOpener { - /// The type variable that represents the 'Self' type. - constraints::ConstraintSystem &CS; - NormalProtocolConformance *Conformance; - DeclContext *DC; - ProtocolDecl *Proto; - - public: - RequirementTypeOpener(constraints::ConstraintSystem &cs, - NormalProtocolConformance *conformance, - DeclContext *dc) - : CS(cs), Conformance(conformance), DC(dc), - Proto(conformance->getProtocol()) - { - } - - virtual void openedGenericParameter(GenericTypeParamType *param, - TypeVariableType *typeVar, - Type &replacementType) { - // If this is the 'Self' type, record it. - if (param->getDepth() == 0 && param->getIndex() == 0) - CS.SelfTypeVar = typeVar; - else - replacementType = ArchetypeBuilder::mapTypeIntoContext(DC, param); - } - - virtual bool shouldBindAssociatedType(Type baseType, - TypeVariableType *baseTypeVar, - AssociatedTypeDecl *assocType, - TypeVariableType *memberTypeVar, - Type &replacementType) { - // If the base is our 'Self' type, we have a witness for this - // associated type already. - if (baseTypeVar == CS.SelfTypeVar && - cast(assocType->getDeclContext()) == Proto) { - replacementType = Conformance->getTypeWitness(assocType, nullptr) - .getReplacement(); - - // Let the member type variable float; we don't want to - // resolve it as a member. - return false; - } - - // If the base is somehow derived from our 'Self' type, we can go ahead - // and bind it. There's nothing more to do. - auto rootBaseType = baseType; - while (auto dependentMember = rootBaseType->getAs()) - rootBaseType = dependentMember->getBase(); - if (auto rootGP = rootBaseType->getAs()) { - if (rootGP->getDepth() == 0 && rootGP->getIndex() == 0) - return true; - } else { - return true; +/// If the given type is a direct reference to an associated type of +/// the given protocol, return the referenced associated type. +static AssociatedTypeDecl * +getReferencedAssocTypeOfProtocol(Type type, ProtocolDecl *proto) { + if (auto dependentMember = type->getAs()) { + if (auto genericParam + = dependentMember->getBase()->getAs()) { + if (genericParam->getDepth() == 0 && genericParam->getIndex() == 0) { + if (auto assocType = dependentMember->getAssocType()) { + if (assocType->getDeclContext() == proto) + return assocType; + } } - - // We have a dependent member type based on a generic parameter; map it - // to an archetype. - auto memberType = DependentMemberType::get(baseType, assocType, - DC->getASTContext()); - replacementType = ArchetypeBuilder::mapTypeIntoContext(DC, memberType); - return true; } - }; + } + return nullptr; +} + +namespace { /// The kind of variance (none, covariance, contravariance) to apply /// when comparing types from a witness to types in the requirement /// we're matching it against. @@ -875,7 +810,8 @@ static bool checkMutating(FuncDecl *requirement, FuncDecl *witness, // stored property accessor, it may not be synthesized yet. bool witnessMutating; if (witness) - witnessMutating = witness->isMutating(); + witnessMutating = (requirement->isInstanceMember() && + witness->isMutating()); else { assert(requirement->isAccessor()); auto storage = cast(witnessDecl); @@ -1241,23 +1177,54 @@ matchWitness(ConformanceChecker &cc, TypeChecker &tc, /*isTypeReference=*/false, /*isDynamicResult=*/false, witnessLocator, - /*base=*/nullptr, - /*opener=*/nullptr); + /*base=*/nullptr); } openWitnessType = openWitnessType->getRValueType(); // Open up the type of the requirement. We only truly open 'Self' and // its associated types (recursively); inner generic type parameters get // mapped to their archetypes directly. - DeclContext *reqDC = req->getPotentialGenericDeclContext(); - RequirementTypeOpener reqTypeOpener(*cs, conformance, reqDC); + DeclContext *reqDC = req->getInnermostDeclContext(); + llvm::DenseMap replacements; std::tie(openedFullReqType, reqType) = cs->getTypeOfMemberReference(model, req, /*isTypeReference=*/false, /*isDynamicResult=*/false, locator, /*base=*/nullptr, - &reqTypeOpener); + &replacements); + + // Bind the associated types. + auto proto = conformance->getProtocol(); + for (const auto &replacement : replacements) { + if (auto gpType = replacement.first->getAs()) { + // Record the type variable for 'Self'. + if (gpType->getDepth() == 0 && gpType->getIndex() == 0) { + cs->SelfTypeVar = replacement.second; + continue; + } + + // Replace any other type variable with the archetype within + // the requirement's context. + cs->addConstraint(ConstraintKind::Bind, + replacement.second, + ArchetypeBuilder::mapTypeIntoContext(reqDC, gpType), + locator); + + continue; + } + + // Associated type of 'self'. + if (auto assocType = getReferencedAssocTypeOfProtocol(replacement.first, + proto)) { + cs->addConstraint(ConstraintKind::Bind, + replacement.second, + conformance->getTypeWitness(assocType, nullptr) + .getReplacement(), + locator); + continue; + } + } reqType = reqType->getRValueType(); return std::make_tuple(None, reqType, openWitnessType); @@ -1292,7 +1259,7 @@ matchWitness(ConformanceChecker &cc, TypeChecker &tc, if (openedFullWitnessType->hasTypeVariable()) { // Figure out the context we're substituting into. - auto witnessDC = witness->getPotentialGenericDeclContext(); + auto witnessDC = witness->getInnermostDeclContext(); // Compute the set of substitutions we'll need for the witness. solution->computeSubstitutions(witness->getInterfaceType(), @@ -1399,7 +1366,7 @@ static Type getRequirementTypeForDisplay(TypeChecker &tc, Module *module, } } - // Replace 'Self' with the conforming type type. + // Replace 'Self' with the conforming type. if (type->isEqual(selfTy)) return conformance->getType(); @@ -1538,10 +1505,9 @@ static Substitution getArchetypeSubstitution(TypeChecker &tc, DeclContext *dc, ArchetypeType *archetype, Type replacement) { - ArchetypeType *resultArchetype = archetype; Type resultReplacement = replacement; assert(!resultReplacement->isTypeParameter() && "Can't be dependent"); - SmallVector conformances; + SmallVector conformances; bool isError = replacement->is(); for (auto proto : archetype->getConformsTo()) { @@ -1552,35 +1518,15 @@ static Substitution getArchetypeSubstitution(TypeChecker &tc, "Conformance should already have been verified"); (void)isError; (void)conforms; - conformances.push_back(conformance); + conformances.push_back(ProtocolConformanceRef(proto, conformance)); } return Substitution{ - resultArchetype, resultReplacement, tc.Context.AllocateCopy(conformances), }; } -/// If the given type is a direct reference to an associated type of -/// the given protocol, return the referenced associated type. -static AssociatedTypeDecl * -getReferencedAssocTypeOfProtocol(Type type, ProtocolDecl *proto) { - if (auto dependentMember = type->getAs()) { - if (auto genericParam - = dependentMember->getBase()->getAs()) { - if (genericParam->getDepth() == 0 && genericParam->getIndex() == 0) { - if (auto assocType = dependentMember->getAssocType()) { - if (assocType->getDeclContext() == proto) - return assocType; - } - } - } - } - - return nullptr; -} - ArrayRef ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { // Check whether we've already cached this information. @@ -2263,7 +2209,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) { }); } - // An non-failable initializer requirement cannot be satisfied + // A non-failable initializer requirement cannot be satisfied // by a failable initializer. if (ctor->getFailability() == OTK_None) { switch (witnessCtor->getFailability()) { @@ -3036,7 +2982,7 @@ void ConformanceChecker::resolveTypeWitnesses() { if (Adoptee->is()) return Type(); - // UnresolvedTypes propagated their unresolveness to any witnesses. + // UnresolvedTypes propagated their unresolvedness to any witnesses. if (Adoptee->is()) return Adoptee; @@ -3732,7 +3678,7 @@ void ConformanceChecker::checkConformance() { } // Ensure that all of the requirements of the protocol have been satisfied. - // Note: the odd check for one generic parameter parameter copes with + // Note: the odd check for one generic parameter copes with // protocols nested within other generic contexts, which is ill-formed. SourceLoc noteLoc = Proto->getLoc(); if (noteLoc.isInvalid()) @@ -3936,6 +3882,12 @@ checkConformsToProtocol(TypeChecker &TC, conformance->setState(ProtocolConformanceState::Checking); defer { conformance->setState(ProtocolConformanceState::Complete); }; + // If the protocol itself is invalid, there's nothing we can do. + if (Proto->isInvalid()) { + conformance->setInvalid(); + return conformance; + } + // If the protocol requires a class, non-classes are a non-starter. if (Proto->requiresClass() && !canT->getClassOrBoundGenericClass()) { TC.diagnose(ComplainLoc, diag::non_class_cannot_conform_to_class_protocol, @@ -4212,8 +4164,7 @@ bool TypeChecker::isProtocolExtensionUsable(DeclContext *dc, Type type, cs.openGeneric(protocolExtension, genericSig->getGenericParams(), genericSig->getRequirements(), false, protocolExtension->getGenericTypeContextDepth(), - nullptr, ConstraintLocatorBuilder(nullptr), - replacements); + ConstraintLocatorBuilder(nullptr), replacements); // Bind the 'Self' type variable to the provided type. CanType selfType = genericSig->getGenericParams().back()->getCanonicalType(); diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp index 60141e307a335..36dd0093ef4df 100644 --- a/lib/Sema/TypeCheckREPL.cpp +++ b/lib/Sema/TypeCheckREPL.cpp @@ -1,8 +1,8 @@ -//===--- TypeCheckREPL.cpp - Type Checking for the REPL -----------------===// +//===--- TypeCheckREPL.cpp - Type Checking for the REPL -------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -95,12 +95,14 @@ class StmtBuilder { Expr *buildPrintRefExpr(SourceLoc loc) { assert(!C.PrintDecls.empty()); - return TC.buildRefExpr(C.PrintDecls, DC, loc, /*Implicit=*/true); + return TC.buildRefExpr(C.PrintDecls, DC, DeclNameLoc(loc), + /*Implicit=*/true); } Expr *buildDebugPrintlnRefExpr(SourceLoc loc) { assert(!C.DebugPrintlnDecls.empty()); - return TC.buildRefExpr(C.DebugPrintlnDecls, DC, loc, /*Implicit=*/true); + return TC.buildRefExpr(C.DebugPrintlnDecls, DC, DeclNameLoc(loc), + /*Implicit=*/true); } }; } // unnamed namespace @@ -113,7 +115,7 @@ void StmtBuilder::printLiteralString(StringRef Str, SourceLoc Loc) { void StmtBuilder::printReplExpr(VarDecl *Arg, SourceLoc Loc) { Expr *DebugPrintlnFn = buildDebugPrintlnRefExpr(Loc); - Expr *ArgRef = TC.buildRefExpr(Arg, DC, Loc, /*Implicit=*/true); + Expr *ArgRef = TC.buildRefExpr(Arg, DC, DeclNameLoc(Loc), /*Implicit=*/true); addToBody(new (Context) CallExpr(DebugPrintlnFn, ArgRef, /*Implicit=*/true)); } @@ -166,7 +168,7 @@ struct PatternBindingPrintLHS : public ASTVisitor { ResultString += ")"; } void visitNamedPattern(NamedPattern *P) { - ResultString += P->getBodyName().str(); + ResultString += P->getBoundName().str(); } void visitAnyPattern(AnyPattern *P) { ResultString += "_"; @@ -222,31 +224,23 @@ void REPLChecker::generatePrintOfExpression(StringRef NameStr, Expr *E) { if (requirePrintDecls()) return; + TopLevelCodeDecl *newTopLevel = new (Context) TopLevelCodeDecl(&SF); + // Build function of type T->() which prints the operand. - VarDecl *Arg = new (Context) ParamDecl(/*isLet=*/true, + auto *Arg = new (Context) ParamDecl(/*isLet=*/true, SourceLoc(), SourceLoc(), Identifier(), Loc, Context.getIdentifier("arg"), - E->getType(), /*DC*/ nullptr); - Pattern *ParamPat = new (Context) NamedPattern(Arg); - ParamPat = new (Context) TypedPattern(ParamPat, - TypeLoc::withoutLoc(Arg->getType())); - TuplePatternElt elt{ParamPat}; - ParamPat = TuplePattern::create(Context, SourceLoc(), elt, SourceLoc()); - TC.typeCheckPattern(ParamPat, Arg->getDeclContext(), - TR_ImmediateFunctionInput); + E->getType(), /*DC*/ newTopLevel); + auto params = ParameterList::createWithoutLoc(Arg); - TopLevelCodeDecl *newTopLevel = new (Context) TopLevelCodeDecl(&SF); unsigned discriminator = TLC.claimNextClosureDiscriminator(); ClosureExpr *CE = - new (Context) ClosureExpr(ParamPat, SourceLoc(), SourceLoc(), SourceLoc(), + new (Context) ClosureExpr(params, SourceLoc(), SourceLoc(), SourceLoc(), TypeLoc(), discriminator, newTopLevel); - Type ParamTy = ParamPat->getType(); - ParamTy = ParamTy->getRelabeledType(TC.Context, { Identifier() }); - Type FuncTy = FunctionType::get(ParamTy, TupleType::getEmpty(Context)); - CE->setType(FuncTy); - + CE->setType(ParameterList::getFullType(TupleType::getEmpty(Context), params)); + // Convert the pattern to a string we can print. llvm::SmallString<16> PrefixString; PrefixString += "// "; @@ -338,7 +332,8 @@ void REPLChecker::processREPLTopLevelExpr(Expr *E) { /*implicit*/true)); // Finally, print the variable's value. - E = TC.buildCheckedRefExpr(vd, &SF, E->getStartLoc(), /*Implicit=*/true); + E = TC.buildCheckedRefExpr(vd, &SF, DeclNameLoc(E->getStartLoc()), + /*Implicit=*/true); generatePrintOfExpression(vd->getName().str(), E); } @@ -366,7 +361,8 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) { // underlying Decl to print it. if (auto *NP = dyn_cast(pattern-> getSemanticsProvidingPattern())) { - Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, PBD->getStartLoc(), + Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, + DeclNameLoc(PBD->getStartLoc()), /*Implicit=*/true); generatePrintOfExpression(PatternString, E); continue; @@ -411,14 +407,15 @@ void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) { // Replace the initializer of PBD with a reference to our repl temporary. - Expr *E = TC.buildCheckedRefExpr(vd, &SF, - vd->getStartLoc(), /*Implicit=*/true); + Expr *E = TC.buildCheckedRefExpr(vd, &SF, DeclNameLoc(vd->getStartLoc()), + /*Implicit=*/true); E = TC.coerceToMaterializable(E); PBD->setInit(entryIdx, E); SF.Decls.push_back(PBTLCD); // Finally, print out the result, by referring to the repl temp. - E = TC.buildCheckedRefExpr(vd, &SF, vd->getStartLoc(), /*Implicit=*/true); + E = TC.buildCheckedRefExpr(vd, &SF, DeclNameLoc(vd->getStartLoc()), + /*Implicit=*/true); generatePrintOfExpression(PatternString, E); } } diff --git a/lib/Sema/TypeCheckRequest.cpp b/lib/Sema/TypeCheckRequest.cpp index b61246246d1f2..9e0511d4a0daa 100644 --- a/lib/Sema/TypeCheckRequest.cpp +++ b/lib/Sema/TypeCheckRequest.cpp @@ -1,8 +1,8 @@ -//===--- TypeCheckRequest.h - Type Checking Request -----------------------===// +//===--- TypeCheckRequest.cpp - Type Checking Request ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index f1886317b62fc..c16e99c83c77d 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -331,7 +331,7 @@ class StmtChecker : public StmtVisitor { /// Type-check an entire function body. bool typeCheckBody(BraceStmt *&S) { - if (typeCheckStmt(S)) return true; + typeCheckStmt(S); setAutoClosureDiscriminators(DC, S); return false; } @@ -396,13 +396,12 @@ class StmtChecker : public StmtVisitor { RS->isImplicit()); } - auto failed = TC.typeCheckExpression(E, DC, ResultTy, CTP_ReturnStmt); + auto hadTypeError = TC.typeCheckExpression(E, DC, ResultTy, CTP_ReturnStmt); RS->setResult(E); - if (failed) { + if (hadTypeError) { tryDiagnoseUnnecessaryCastOverOptionSet(TC.Context, E, ResultTy, DC->getParentModule()); - return nullptr; } return RS; @@ -415,10 +414,8 @@ class StmtChecker : public StmtVisitor { Type exnType = TC.getExceptionType(DC, TS->getThrowLoc()); if (!exnType) return TS; - auto failed = TC.typeCheckExpression(E, DC, exnType, CTP_ThrowStmt); + TC.typeCheckExpression(E, DC, exnType, CTP_ThrowStmt); TS->setSubExpr(E); - - if (failed) return nullptr; return TS; } @@ -427,8 +424,7 @@ class StmtChecker : public StmtVisitor { TC.typeCheckDecl(DS->getTempDecl(), /*isFirstPass*/false); Expr *theCall = DS->getCallExpr(); - if (!TC.typeCheckExpression(theCall, DC)) - return nullptr; + TC.typeCheckExpression(theCall, DC); DS->setCallExpr(theCall); return DS; @@ -436,18 +432,17 @@ class StmtChecker : public StmtVisitor { Stmt *visitIfStmt(IfStmt *IS) { StmtCondition C = IS->getCond(); - - if (TC.typeCheckStmtCondition(C, DC, diag::if_always_true)) return 0; + TC.typeCheckStmtCondition(C, DC, diag::if_always_true); IS->setCond(C); AddLabeledStmt ifNest(*this, IS); Stmt *S = IS->getThenStmt(); - if (typeCheckStmt(S)) return 0; + typeCheckStmt(S); IS->setThenStmt(S); if ((S = IS->getElseStmt())) { - if (typeCheckStmt(S)) return 0; + typeCheckStmt(S); IS->setElseStmt(S); } @@ -456,14 +451,13 @@ class StmtChecker : public StmtVisitor { Stmt *visitGuardStmt(GuardStmt *GS) { StmtCondition C = GS->getCond(); - if (TC.typeCheckStmtCondition(C, DC, diag::guard_always_succeeds)) - return 0; + TC.typeCheckStmtCondition(C, DC, diag::guard_always_succeeds); GS->setCond(C); AddLabeledStmt ifNest(*this, GS); Stmt *S = GS->getBody(); - if (typeCheckStmt(S)) return 0; + typeCheckStmt(S); GS->setBody(S); return GS; } @@ -479,19 +473,19 @@ class StmtChecker : public StmtVisitor { Stmt *visitDoStmt(DoStmt *DS) { AddLabeledStmt loopNest(*this, DS); Stmt *S = DS->getBody(); - if (typeCheckStmt(S)) return 0; + typeCheckStmt(S); DS->setBody(S); return DS; } Stmt *visitWhileStmt(WhileStmt *WS) { StmtCondition C = WS->getCond(); - if (TC.typeCheckStmtCondition(C, DC, diag::while_always_true)) return 0; + TC.typeCheckStmtCondition(C, DC, diag::while_always_true); WS->setCond(C); AddLabeledStmt loopNest(*this, WS); Stmt *S = WS->getBody(); - if (typeCheckStmt(S)) return 0; + typeCheckStmt(S); WS->setBody(S); return WS; @@ -500,12 +494,12 @@ class StmtChecker : public StmtVisitor { { AddLabeledStmt loopNest(*this, RWS); Stmt *S = RWS->getBody(); - if (typeCheckStmt(S)) return nullptr; + typeCheckStmt(S); RWS->setBody(S); } Expr *E = RWS->getCond(); - if (TC.typeCheckCondition(E, DC)) return nullptr; + TC.typeCheckCondition(E, DC); RWS->setCond(E); return RWS; } @@ -515,30 +509,27 @@ class StmtChecker : public StmtVisitor { TC.typeCheckDecl(D, /*isFirstPass*/false); if (auto *Initializer = FS->getInitializer().getPtrOrNull()) { - if (TC.typeCheckExpression(Initializer, DC, Type(), CTP_Unused, - TypeCheckExprFlags::IsDiscarded)) - return nullptr; + TC.typeCheckExpression(Initializer, DC, Type(), CTP_Unused, + TypeCheckExprFlags::IsDiscarded); FS->setInitializer(Initializer); TC.checkIgnoredExpr(Initializer); } if (auto *Cond = FS->getCond().getPtrOrNull()) { - if (TC.typeCheckCondition(Cond, DC)) - return nullptr; + TC.typeCheckCondition(Cond, DC); FS->setCond(Cond); } if (auto *Increment = FS->getIncrement().getPtrOrNull()) { - if (TC.typeCheckExpression(Increment, DC, Type(), CTP_Unused, - TypeCheckExprFlags::IsDiscarded)) - return nullptr; + TC.typeCheckExpression(Increment, DC, Type(), CTP_Unused, + TypeCheckExprFlags::IsDiscarded); FS->setIncrement(Increment); TC.checkIgnoredExpr(Increment); } AddLabeledStmt loopNest(*this, FS); Stmt *S = FS->getBody(); - if (typeCheckStmt(S)) return nullptr; + typeCheckStmt(S); FS->setBody(S); return FS; @@ -667,7 +658,8 @@ class StmtChecker : public StmtVisitor { // Compute the expression that advances the generator. Expr *genNext - = TC.callWitness(TC.buildCheckedRefExpr(generator, DC, S->getInLoc(), + = TC.callWitness(TC.buildCheckedRefExpr(generator, DC, + DeclNameLoc(S->getInLoc()), /*implicit*/true), DC, generatorProto, genConformance, TC.Context.Id_next, {}, diag::generator_protocol_broken); @@ -691,7 +683,7 @@ class StmtChecker : public StmtVisitor { // Type-check the body of the loop. AddLabeledStmt loopNest(*this, S); BraceStmt *Body = S->getBody(); - if (typeCheckStmt(Body)) return nullptr; + typeCheckStmt(Body); S->setBody(Body); return S; @@ -810,14 +802,11 @@ class StmtChecker : public StmtVisitor { Stmt *visitSwitchStmt(SwitchStmt *S) { // Type-check the subject expression. Expr *subjectExpr = S->getSubjectExpr(); - bool hadTypeError = TC.typeCheckExpression(subjectExpr, DC); - subjectExpr = TC.coerceToMaterializable(subjectExpr); - - if (!subjectExpr) - return nullptr; - + TC.typeCheckExpression(subjectExpr, DC); + if (Expr *newSubjectExpr = TC.coerceToMaterializable(subjectExpr)) + subjectExpr = newSubjectExpr; S->setSubjectExpr(subjectExpr); - Type subjectType = subjectExpr->getType(); + Type subjectType = S->getSubjectExpr()->getType(); // Type-check the case blocks. AddSwitchNest switchNest(*this); @@ -835,40 +824,33 @@ class StmtChecker : public StmtVisitor { if (auto *newPattern = TC.resolvePattern(pattern, DC, /*isStmtCondition*/false)) { pattern = newPattern; - } else { - hadTypeError = true; - continue; - } - - // Coerce the pattern to the subject's type. - if (TC.coercePatternToType(pattern, DC, subjectType, TR_InExpression)) { - // If that failed, mark any variables binding pieces of the pattern - // as invalid to silence follow-on errors. - pattern->forEachVariable([&](VarDecl *VD) { - VD->overwriteType(ErrorType::get(TC.Context)); - VD->setInvalid(); - }); - hadTypeError = true; + // Coerce the pattern to the subject's type. + if (TC.coercePatternToType(pattern, DC, subjectType, + TR_InExpression)) { + // If that failed, mark any variables binding pieces of the pattern + // as invalid to silence follow-on errors. + pattern->forEachVariable([&](VarDecl *VD) { + VD->overwriteType(ErrorType::get(TC.Context)); + VD->setInvalid(); + }); + } + labelItem.setPattern(pattern); } - labelItem.setPattern(pattern); // Check the guard expression, if present. if (auto *guard = labelItem.getGuardExpr()) { - if (TC.typeCheckCondition(guard, DC)) - hadTypeError = true; - else - labelItem.setGuardExpr(guard); + TC.typeCheckCondition(guard, DC); + labelItem.setGuardExpr(guard); } } // Type-check the body statements. Stmt *body = caseBlock->getBody(); - if (typeCheckStmt(body)) - hadTypeError = true; + typeCheckStmt(body); caseBlock->setBody(body); } - return hadTypeError ? nullptr : S; + return S; } Stmt *visitCaseStmt(CaseStmt *S) { @@ -881,22 +863,20 @@ class StmtChecker : public StmtVisitor { llvm_unreachable("catch stmt outside of do-catch?!"); } - bool checkCatchStmt(CatchStmt *S) { + void checkCatchStmt(CatchStmt *S) { // Check the catch pattern. - bool hadTypeError = TC.typeCheckCatchPattern(S, DC); + TC.typeCheckCatchPattern(S, DC); // Check the guard expression, if present. if (Expr *guard = S->getGuardExpr()) { - hadTypeError |= TC.typeCheckCondition(guard, DC); + TC.typeCheckCondition(guard, DC); S->setGuardExpr(guard); } // Type-check the clause body. Stmt *body = S->getBody(); - hadTypeError |= typeCheckStmt(body); + typeCheckStmt(body); S->setBody(body); - - return hadTypeError; } Stmt *visitDoCatchStmt(DoCatchStmt *S) { @@ -905,23 +885,18 @@ class StmtChecker : public StmtVisitor { // entire construct. AddLabeledStmt loopNest(*this, S); - bool hadTypeError = false; - // Type-check the 'do' body. Type failures in here will generally // not cause type failures in the 'catch' clauses. Stmt *newBody = S->getBody(); - if (typeCheckStmt(newBody)) { - hadTypeError = true; - } else { - S->setBody(newBody); - } + typeCheckStmt(newBody); + S->setBody(newBody); // Check all the catch clauses independently. for (auto clause : S->getCatches()) { - hadTypeError |= checkCatchStmt(clause); + checkCatchStmt(clause); } - return hadTypeError ? nullptr : S; + return S; } Stmt *visitFailStmt(FailStmt *S) { @@ -934,8 +909,6 @@ class StmtChecker : public StmtVisitor { } // end anonymous namespace bool TypeChecker::typeCheckCatchPattern(CatchStmt *S, DeclContext *DC) { - bool hadTypeError = false; - // Grab the standard exception type. Type exnType = getExceptionType(DC, S->getCatchLoc()); @@ -954,15 +927,11 @@ bool TypeChecker::typeCheckCatchPattern(CatchStmt *S, DeclContext *DC) { var->overwriteType(ErrorType::get(Context)); var->setInvalid(); }); - hadTypeError = true; } S->setErrorPattern(pattern); - } else { - hadTypeError = true; } - - return hadTypeError; + return false; } void TypeChecker::checkIgnoredExpr(Expr *E) { @@ -1082,14 +1051,10 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) { if (isDiscarded) options |= TypeCheckExprFlags::IsDiscarded; - if (TC.typeCheckExpression(SubExpr, DC, Type(), CTP_Unused, options)) { - elem = SubExpr; - continue; - } - - if (isDiscarded) + bool hadTypeError = TC.typeCheckExpression(SubExpr, DC, Type(), + CTP_Unused, options); + if (isDiscarded && !hadTypeError) TC.checkIgnoredExpr(SubExpr); - elem = SubExpr; continue; } @@ -1100,8 +1065,8 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) { (Loc == EndTypeCheckLoc || SM.isBeforeInBuffer(EndTypeCheckLoc, Loc))) break; - if (!typeCheckStmt(SubStmt)) - elem = SubStmt; + typeCheckStmt(SubStmt); + elem = SubStmt; continue; } @@ -1118,75 +1083,51 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) { } /// Check the default arguments that occur within this pattern. -static void checkDefaultArguments(TypeChecker &tc, Pattern *pattern, - unsigned &nextArgIndex, - DeclContext *dc) { +static void checkDefaultArguments(TypeChecker &tc, ParameterList *params, + unsigned &nextArgIndex, DeclContext *dc) { assert(dc->isLocalContext()); - switch (pattern->getKind()) { - case PatternKind::Tuple: - for (auto &field : cast(pattern)->getElements()) { - unsigned curArgIndex = nextArgIndex++; - if (field.getInit() && - field.getPattern()->hasType() && - !field.getPattern()->getType()->is()) { - - Expr *e = field.getInit()->getExpr(); - - // Re-use an existing initializer context if possible. - auto existingContext = e->findExistingInitializerContext(); - DefaultArgumentInitializer *initContext; - if (existingContext) { - initContext = cast(existingContext); - assert(initContext->getIndex() == curArgIndex); - assert(initContext->getParent() == dc); - - // Otherwise, allocate one temporarily. - } else { - initContext = - tc.Context.createDefaultArgumentContext(dc, curArgIndex); - } - - // Type-check the initializer, then flag that we did so. - if (tc.typeCheckExpression(e, initContext,field.getPattern()->getType(), - CTP_DefaultParameter)) - field.getInit()->setExpr(field.getInit()->getExpr(), true); - else - field.getInit()->setExpr(e, true); + for (auto ¶m : *params) { + unsigned curArgIndex = nextArgIndex++; + if (!param->getDefaultValue() || !param->hasType() || + param->getType()->is()) + continue; + + auto defaultValueHandle = param->getDefaultValue(); + Expr *e = defaultValueHandle->getExpr(); + + // Re-use an existing initializer context if possible. + auto existingContext = e->findExistingInitializerContext(); + DefaultArgumentInitializer *initContext; + if (existingContext) { + initContext = cast(existingContext); + assert(initContext->getIndex() == curArgIndex); + assert(initContext->getParent() == dc); + + // Otherwise, allocate one temporarily. + } else { + initContext = + tc.Context.createDefaultArgumentContext(dc, curArgIndex); + } - tc.checkInitializerErrorHandling(initContext, e); + // Type-check the initializer, then flag that we did so. + if (tc.typeCheckExpression(e, initContext, param->getType(), + CTP_DefaultParameter)) + defaultValueHandle->setExpr(defaultValueHandle->getExpr(), true); + else + defaultValueHandle->setExpr(e, true); - // Walk the checked initializer and contextualize any closures - // we saw there. - bool hasClosures = tc.contextualizeInitializer(initContext, e); + tc.checkInitializerErrorHandling(initContext, e); - // If we created a new context and didn't run into any autoclosures - // during the walk, give the context back to the ASTContext. - if (!hasClosures && !existingContext) - tc.Context.destroyDefaultArgumentContext(initContext); - } - } - return; - case PatternKind::Paren: - return checkDefaultArguments(tc, - cast(pattern)->getSubPattern(), - nextArgIndex, - dc); - case PatternKind::Var: - return checkDefaultArguments(tc, cast(pattern)->getSubPattern(), - nextArgIndex, - dc); - case PatternKind::Typed: - case PatternKind::Named: - case PatternKind::Any: - return; + // Walk the checked initializer and contextualize any closures + // we saw there. + bool hasClosures = tc.contextualizeInitializer(initContext, e); -#define PATTERN(Id, Parent) -#define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: -#include "swift/AST/PatternNodes.def" - llvm_unreachable("pattern can't appear in argument list!"); + // If we created a new context and didn't run into any autoclosures + // during the walk, give the context back to the ASTContext. + if (!hasClosures && !existingContext) + tc.Context.destroyDefaultArgumentContext(initContext); } - llvm_unreachable("bad pattern kind!"); } bool TypeChecker::typeCheckAbstractFunctionBodyUntil(AbstractFunctionDecl *AFD, @@ -1222,9 +1163,8 @@ bool TypeChecker::typeCheckFunctionBodyUntil(FuncDecl *FD, SourceLoc EndTypeCheckLoc) { // Check the default argument definitions. unsigned nextArgIndex = 0; - for (auto pattern : FD->getBodyParamPatterns()) { - checkDefaultArguments(*this, pattern, nextArgIndex, FD); - } + for (auto paramList : FD->getParameterLists()) + checkDefaultArguments(*this, paramList, nextArgIndex, FD); // Clang imported inline functions do not have a Swift body to // typecheck. @@ -1246,10 +1186,9 @@ Expr* TypeChecker::constructCallToSuperInit(ConstructorDecl *ctor, ClassDecl *ClDecl) { Expr *superRef = new (Context) SuperRefExpr(ctor->getImplicitSelfDecl(), SourceLoc(), /*Implicit=*/true); - Expr *r = new (Context) UnresolvedConstructorExpr(superRef, - SourceLoc(), - SourceLoc(), - /*Implicit=*/true); + Expr *r = new (Context) UnresolvedDotExpr(superRef, SourceLoc(), + Context.Id_init, DeclNameLoc(), + /*Implicit=*/true); Expr *args = TupleExpr::createEmpty(Context, SourceLoc(), SourceLoc(), /*Implicit=*/true); r = new (Context) CallExpr(r, args, /*Implicit=*/true); @@ -1323,8 +1262,8 @@ bool TypeChecker::typeCheckConstructorBodyUntil(ConstructorDecl *ctor, SourceLoc EndTypeCheckLoc) { // Check the default argument definitions. unsigned nextArgIndex = 0; - for (auto pattern : ctor->getBodyParamPatterns()) - checkDefaultArguments(*this, pattern, nextArgIndex, ctor); + for (auto paramList : ctor->getParameterLists()) + checkDefaultArguments(*this, paramList, nextArgIndex, ctor); BraceStmt *body = ctor->getBody(); if (!body) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index d4a96aec19430..8bfd5911b6611 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,6 +30,7 @@ #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporter.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" @@ -110,11 +111,11 @@ Type TypeChecker::getExceptionType(DeclContext *dc, SourceLoc loc) { return Type(); } -static Type getObjectiveCClassType(TypeChecker &TC, - Type &cache, - Identifier ModuleName, - Identifier TypeName, - DeclContext *dc) { +static Type getObjectiveCNominalType(TypeChecker &TC, + Type &cache, + Identifier ModuleName, + Identifier TypeName, + DeclContext *dc) { if (cache) return cache; @@ -141,13 +142,24 @@ static Type getObjectiveCClassType(TypeChecker &TC, } Type TypeChecker::getNSObjectType(DeclContext *dc) { - return getObjectiveCClassType(*this, NSObjectType, Context.Id_ObjectiveC, - Context.Id_NSObject, dc); + return getObjectiveCNominalType(*this, NSObjectType, Context.Id_ObjectiveC, + Context.getSwiftId( + KnownFoundationEntity::NSObject), + dc); } Type TypeChecker::getNSErrorType(DeclContext *dc) { - return getObjectiveCClassType(*this, NSObjectType, Context.Id_Foundation, - Context.Id_NSError, dc); + return getObjectiveCNominalType(*this, NSObjectType, Context.Id_Foundation, + Context.getSwiftId( + KnownFoundationEntity::NSError), + dc); +} + +Type TypeChecker::getObjCSelectorType(DeclContext *dc) { + return getObjectiveCNominalType(*this, ObjCSelectorType, + Context.Id_ObjectiveC, + Context.Id_Selector, + dc); } Type TypeChecker::getBridgedToObjC(const DeclContext *dc, Type type) { @@ -165,7 +177,7 @@ TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc, !dynamicType->getClassOrBoundGenericClass()) return Type(); - // If the value type canot be bridged, we're done. + // If the value type cannot be bridged, we're done. if (!valueType->isPotentiallyBridgedValueType()) return Type(); @@ -184,6 +196,23 @@ void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) { } } +static Optional +resolveAssociatedTypeInContext(TypeChecker &TC, AssociatedTypeDecl *assocType, + DeclContext *DC, GenericTypeResolver *resolver) { + auto protoSelf = DC->getProtocolSelf(); + auto selfTy = protoSelf->getDeclaredType()->castTo(); + auto baseTy = resolver->resolveGenericTypeParamType(selfTy); + + if (baseTy->isTypeParameter()) + return resolver->resolveSelfAssociatedType(baseTy, DC, assocType); + + if (assocType->getDeclContext() != DC) + return TC.substMemberTypeWithBase(DC->getParentModule(), assocType, + protoSelf->getArchetype(), + /*isTypeReference=*/true); + return None; +} + Type TypeChecker::resolveTypeInContext( TypeDecl *typeDecl, DeclContext *fromDC, @@ -206,107 +235,106 @@ Type TypeChecker::resolveTypeInContext( genericParam->getDeclaredType()->castTo()); } - // If we are referring to a type within its own context, and we have either - // a generic type with no generic arguments or a non-generic type, use the - // type within the context. - if (auto nominal = dyn_cast(typeDecl)) { - - this->forceExternalDeclMembers(nominal); - - if (!nominal->getGenericParams() || !isSpecialized) { - for (DeclContext *dc = fromDC; dc; dc = dc->getParent()) { - switch (dc->getContextKind()) { - case DeclContextKind::Module: - case DeclContextKind::FileUnit: - case DeclContextKind::TopLevelCodeDecl: - case DeclContextKind::Initializer: - break; - - case DeclContextKind::NominalTypeDecl: - // If this is our nominal type, return its type within its context. - // FIXME: Just produce the type structure when TR_ResolveStructure. - if (cast(dc) == nominal) - return resolver->resolveTypeOfContext(nominal); - continue; - - case DeclContextKind::ExtensionDecl: - // If this is an extension of our nominal type, return the type - // within the context of its extension. - // FIXME: Just produce the type structure when TR_ResolveStructure. - if (cast(dc)->getExtendedType()->getAnyNominal() - == nominal) - return resolver->resolveTypeOfContext(dc); - continue; - - case DeclContextKind::AbstractClosureExpr: - case DeclContextKind::AbstractFunctionDecl: - continue; - case DeclContextKind::SerializedLocal: - llvm_unreachable("should not be typechecking deserialized things"); - } - - break; - } - } - } - - // If the type declaration itself is in a non-type context, no type - // substitution is needed. - DeclContext *ownerDC = typeDecl->getDeclContext(); - if (!ownerDC->isTypeContext()) { - // FIXME: Just produce the type structure when TR_ResolveStructure. - return typeDecl->getDeclaredType(); - } - - // Find the nearest enclosing type context around the context from which - // we started our search. - while (!fromDC->isTypeContext()) { - fromDC = fromDC->getParent(); - assert(!fromDC->isModuleContext()); - } - - // If we found an associated type in an inherited protocol, the base - // for our reference to this associated type is our own 'Self'. - auto assocType = dyn_cast(typeDecl); - if (assocType) { - // If we found an associated type from within its protocol, resolve it - // as a dependent member relative to Self if Self is still dependent. - if (fromDC->isProtocolOrProtocolExtensionContext()) { - auto selfTy = fromDC->getProtocolSelf()->getDeclaredType() - ->castTo(); - auto baseTy = resolver->resolveGenericTypeParamType(selfTy); - - if (baseTy->isTypeParameter()) { - return resolver->resolveSelfAssociatedType(baseTy, fromDC, assocType); - } - } - - if (typeDecl->getDeclContext() != fromDC) { - if (fromDC->isProtocolOrProtocolExtensionContext()) { - return substMemberTypeWithBase(fromDC->getParentModule(), - typeDecl, - fromDC->getProtocolSelf() - ->getArchetype(), - /*isTypeReference=*/true); - } - } + auto nominalType = dyn_cast(typeDecl); + if (nominalType && (!nominalType->getGenericParams() || !isSpecialized)) { + forceExternalDeclMembers(nominalType); + } else { + nominalType = nullptr; } // Walk up through the type scopes to find the context where the type // declaration was found. When we find it, substitute the appropriate base // type. + auto ownerDC = typeDecl->getDeclContext(); + bool nonTypeOwner = !ownerDC->isTypeContext(); auto ownerNominal = ownerDC->isNominalTypeOrNominalTypeExtensionContext(); - assert(ownerNominal && "Owner must be a nominal type"); + auto assocType = dyn_cast(typeDecl); + DeclContext *typeParent = nullptr; + assert((ownerNominal || nonTypeOwner) && + "Owner must be a nominal type or a non type context"); + for (auto parentDC = fromDC; !parentDC->isModuleContext(); parentDC = parentDC->getParent()) { - // Skip non-type contexts. - if (!parentDC->isTypeContext()) + + // If we are referring to a type within its own context, and we have either + // a generic type with no generic arguments or a non-generic type, use the + // type within the context. + if (nominalType) { + if (parentDC->isNominalTypeOrNominalTypeExtensionContext() == nominalType) + return resolver->resolveTypeOfContext(parentDC); + if (!parentDC->isModuleScopeContext() && !isa(parentDC)) + continue; + + // If we didn't find a matching declaration, the iteration is restarted + // but we won't look anymore for the specific nominal type declaration + parentDC = fromDC; + nominalType = nullptr; + } + + if (nonTypeOwner) + return typeDecl->getDeclaredType(); + + // For the next steps we need our parentDC to be a type context + if (!parentDC->isTypeContext()) { continue; + } else if (!typeParent) { + // Remember the first type decl context in the hierarchy for later use + typeParent = parentDC; + } + + // If we found an associated type in an inherited protocol, the base for our + // reference to this associated type is our own `Self`. If we can't resolve + // the associated type during this iteration, try again on the next. + if (assocType) { + if (auto proto = parentDC->isProtocolOrProtocolExtensionContext()) { + auto assocProto = assocType->getProtocol(); + if (proto == assocProto || proto->inheritsFrom(assocProto)) { + // If the associated type is from our own protocol or we inherit from + // the associated type's protocol, resolve it + if (auto resolved = resolveAssociatedTypeInContext( + *this, assocType, parentDC, resolver)) + return *resolved; + + } else if (auto ED = dyn_cast(parentDC)) { + // Otherwise, if we are in an extension there might be other + // associated types brought into the context through + // `extension ... where Self : SomeProtocol` + for (auto req : ED->getGenericParams()->getTrailingRequirements()) { + // Reject requirements other than constraints with an subject other + // than `Self` + if (req.getKind() != RequirementReprKind::TypeConstraint || + !req.getSubject()->castTo()->isSelfDerived()) + continue; + + // If the associated type is defined in the same protocol which is + // required for this extension, or if the required protocol inherits + // from the protocol the associated type is declared in, we can + // resolve the associated type with our `Self` as the reference + // point. + auto reqProto = + req.getConstraint()->castTo()->getDecl(); + if (reqProto == assocProto || reqProto->inheritsFrom(assocProto)) { + if (auto resolved = resolveAssociatedTypeInContext( + *this, assocType, parentDC, resolver)) + return *resolved; + break; + } + } + } + } + } // Search the type of this context and its supertypes. + llvm::SmallPtrSet visited; for (auto fromType = resolver->resolveTypeOfContext(parentDC); fromType; fromType = getSuperClassOf(fromType)) { + // If we hit circularity, we will diagnose at some point in typeCheckDecl(). + // However we have to explicitly guard against that here because we get + // called as part of validateDecl(). + if (!visited.insert(fromType->getAnyNominal()).second) + break; + // If the nominal type declaration of the context type we're looking at // matches the owner's nominal type declaration, this is how we found // the member type declaration. Substitute the type we're coming from as @@ -338,56 +366,77 @@ Type TypeChecker::resolveTypeInContext( } } + // At this point by iterating through the decl context hierarchy we should + // have encountered the first type context in the stack. + assert(typeParent && "incomplete iteration"); + assert(!typeParent->isModuleContext()); + // Substitute in the appropriate type for 'Self'. // FIXME: We shouldn't have to guess here; the caller should tell us. Type fromType; - if (fromDC->isProtocolOrProtocolExtensionContext()) - fromType = fromDC->getProtocolSelf()->getArchetype(); + if (typeParent->isProtocolOrProtocolExtensionContext()) + fromType = typeParent->getProtocolSelf()->getArchetype(); else - fromType = resolver->resolveTypeOfContext(fromDC); + fromType = resolver->resolveTypeOfContext(typeParent); // Perform the substitution. - return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, + return substMemberTypeWithBase(typeParent->getParentModule(), typeDecl, fromType, /*isTypeReference=*/true); } -/// Apply generic arguments to the given type. -Type TypeChecker::applyGenericArguments(Type type, - SourceLoc loc, +Type TypeChecker::applyGenericArguments(Type type, SourceLoc loc, DeclContext *dc, - MutableArrayRef genericArgs, + GenericIdentTypeRepr *generic, bool isGenericSignature, GenericTypeResolver *resolver) { - // Make sure we always have a resolver to use. - PartialGenericTypeToArchetypeResolver defaultResolver(*this); - if (!resolver) - resolver = &defaultResolver; auto unbound = type->getAs(); if (!unbound) { - // FIXME: Highlight generic arguments and introduce a Fix-It to remove - // them. - diagnose(loc, diag::not_a_generic_type, type); - - // Just return the type; this provides better recovery anyway. + if (!type->is()) + diagnose(loc, diag::not_a_generic_type, type) + .fixItRemove(generic->getAngleBrackets()); return type; } // Make sure we have the right number of generic arguments. // FIXME: If we have fewer arguments than we need, that might be okay, if // we're allowed to deduce the remaining arguments from context. - auto genericParams = unbound->getDecl()->getGenericParams(); + auto unboundDecl = unbound->getDecl(); + auto genericArgs = generic->getGenericArgs(); + auto genericParams = unboundDecl->getGenericParams(); if (genericParams->size() != genericArgs.size()) { - // FIXME: Highlight <...>. - diagnose(loc, diag::type_parameter_count_mismatch, - unbound->getDecl()->getName(), + diagnose(loc, diag::type_parameter_count_mismatch, unboundDecl->getName(), genericParams->size(), genericArgs.size(), - genericArgs.size() < genericParams->size()); - diagnose(unbound->getDecl(), diag::generic_type_declared_here, - unbound->getDecl()->getName()); + genericArgs.size() < genericParams->size()) + .highlight(generic->getAngleBrackets()); + diagnose(unboundDecl, diag::generic_type_declared_here, + unboundDecl->getName()); return nullptr; } + SmallVector args; + for (auto tyR : genericArgs) + args.push_back(tyR); + + return applyUnboundGenericArguments(unbound, loc, dc, args, + isGenericSignature, resolver); +} + +/// Apply generic arguments to the given type. +Type TypeChecker::applyUnboundGenericArguments( + UnboundGenericType *unbound, SourceLoc loc, DeclContext *dc, + MutableArrayRef genericArgs, bool isGenericSignature, + GenericTypeResolver *resolver) { + + assert(unbound && + genericArgs.size() == unbound->getDecl()->getGenericParams()->size() && + "invalid arguments, use applyGenericArguments for diagnostic emitting"); + + // Make sure we always have a resolver to use. + PartialGenericTypeToArchetypeResolver defaultResolver(*this); + if (!resolver) + resolver = &defaultResolver; + TypeResolutionOptions options; if (isGenericSignature) options |= TR_GenericSignature; @@ -436,20 +485,17 @@ Type TypeChecker::applyGenericArguments(Type type, static Type applyGenericTypeReprArgs(TypeChecker &TC, Type type, SourceLoc loc, DeclContext *dc, - ArrayRef genericArgs, + GenericIdentTypeRepr *generic, bool isGenericSignature, GenericTypeResolver *resolver) { - SmallVector args; - for (auto tyR : genericArgs) - args.push_back(tyR); - Type ty = TC.applyGenericArguments(type, loc, dc, args, - isGenericSignature, resolver); + + Type ty = TC.applyGenericArguments(type, loc, dc, generic, isGenericSignature, + resolver); if (!ty) return ErrorType::get(TC.Context); return ty; } - /// \brief Diagnose a use of an unbound generic type. static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) { tc.diagnose(loc, diag::generic_type_requires_arguments, ty); @@ -461,7 +507,7 @@ static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) { /// \brief Returns a valid type or ErrorType in case of an error. static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, DeclContext *dc, - ArrayRef genericArgs, + GenericIdentTypeRepr *generic, TypeResolutionOptions options, GenericTypeResolver *resolver, UnsatisfiedDependency *unsatisfiedDependency) { @@ -478,15 +524,15 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. - Type type = TC.resolveTypeInContext(typeDecl, dc, options, - !genericArgs.empty(), resolver); + Type type = + TC.resolveTypeInContext(typeDecl, dc, options, generic, resolver); // FIXME: Defensive check that shouldn't be needed, but prevents a // huge number of crashes on ill-formed code. if (!type) return ErrorType::get(TC.Context); - if (type->is() && genericArgs.empty() && + if (type->is() && !generic && !options.contains(TR_AllowUnboundGenerics) && !options.contains(TR_ResolveStructure)) { diagnoseUnboundGenericType(TC, type, loc); @@ -506,9 +552,9 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, } } - if (!genericArgs.empty() && !options.contains(TR_ResolveStructure)) { + if (generic && !options.contains(TR_ResolveStructure)) { // Apply the generic arguments to the type. - type = applyGenericTypeReprArgs(TC, type, loc, dc, genericArgs, + type = applyGenericTypeReprArgs(TC, type, loc, dc, generic, options.contains(TR_GenericSignature), resolver); } @@ -555,7 +601,7 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, (nominal = getEnclosingNominalContext(dc))) { // Retrieve the nominal type and resolve it within this context. assert(!isa(nominal) && "Cannot be a protocol"); - auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, { }, + auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, nullptr, options, resolver, unsatisfiedDependency); if (type->is()) return type; @@ -587,7 +633,8 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, comp->overwriteIdentifier(tc.Context.getIdentifier(RemappedTy)); // HACK: 'NSUInteger' suggests both 'UInt' and 'Int'. - if (TypeName == "NSUInteger") { + if (TypeName + == tc.Context.getSwiftName(KnownFoundationEntity::NSUInteger)) { tc.diagnose(L, diag::note_remapped_type, "UInt") .fixItReplace(R, "UInt"); } @@ -648,15 +695,10 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, return ErrorType::get(TC.Context); } - // Retrieve the generic arguments, if there are any. - ArrayRef genericArgs; - if (auto genComp = dyn_cast(comp)) - genericArgs = genComp->getGenericArgs(); - // Resolve the type declaration within this context. return resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), DC, - genericArgs, options, resolver, - unsatisfiedDependency); + dyn_cast(comp), options, + resolver, unsatisfiedDependency); } // Resolve the first component, which is the only one that requires @@ -733,7 +775,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, } } - if (!DC->isCascadingContextForLookup(/*excludeFunctions*/true)) + if (!DC->isCascadingContextForLookup(/*excludeFunctions*/false)) options |= TR_KnownNonCascadingDependency; // The remaining lookups will be in the parent context. @@ -774,12 +816,10 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, TC.forceExternalDeclMembers(nomDecl); } - ArrayRef genericArgs; - if (auto genComp = dyn_cast(comp)) - genericArgs = genComp->getGenericArgs(); - Type type = resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), - DC, genericArgs, options, resolver, - unsatisfiedDependency); + Type type = resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), DC, + dyn_cast(comp), options, + resolver, unsatisfiedDependency); + if (!type || type->is()) return type; @@ -910,10 +950,8 @@ static Type resolveNestedIdentTypeComponent( // If there are generic arguments, apply them now. if (auto genComp = dyn_cast(comp)) { memberType = applyGenericTypeReprArgs( - TC, memberType, comp->getIdLoc(), DC, - genComp->getGenericArgs(), - options.contains(TR_GenericSignature), - resolver); + TC, memberType, comp->getIdLoc(), DC, genComp, + options.contains(TR_GenericSignature), resolver); // Propagate failure. if (!memberType || memberType->is()) return memberType; @@ -1028,8 +1066,8 @@ static Type resolveNestedIdentTypeComponent( // If there are generic arguments, apply them now. if (auto genComp = dyn_cast(comp)) memberType = applyGenericTypeReprArgs( - TC, memberType, comp->getIdLoc(), DC, genComp->getGenericArgs(), - options.contains(TR_GenericSignature), resolver); + TC, memberType, comp->getIdLoc(), DC, genComp, + options.contains(TR_GenericSignature), resolver); if (member) comp->setValue(member); @@ -1156,6 +1194,15 @@ static bool diagnoseAvailability(Type ty, IdentTypeRepr *IdType, SourceLoc Loc, return true; } + if (auto *GPT = dyn_cast(ty.getPointer())) { + if (auto GP = GPT->getDecl()) { + if (checkTypeDeclAvailability(GP, IdType, Loc, DC, TC, + AllowPotentiallyUnavailableProtocol)) { + return true; + } + } + } + // Look through substituted types to diagnose when the original // type is marked unavailable. if (auto *ST = dyn_cast(ty.getPointer())) { @@ -1207,7 +1254,7 @@ Type TypeChecker::resolveIdentifierType( // We allow a type to conform to a protocol that is less available than // the type itself. This enables a type to retroactively model or directly - // conform to a protocl only available on newer OSes and yet still be used on + // conform to a protocol only available on newer OSes and yet still be used on // older OSes. // To support this, inside inheritance clauses we allow references to // protocols that are unavailable in the current type refinement context. @@ -1339,7 +1386,13 @@ Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC, resolver = &defaultResolver; TypeResolver typeResolver(*this, DC, resolver, unsatisfiedDependency); - return typeResolver.resolveType(TyR, options); + auto result = typeResolver.resolveType(TyR, options); + + // If we resolved down to an error, make sure to mark the typeRepr as invalid + // so we don't produce a redundant diagnostic. + if (result && result->is()) + TyR->setInvalid(); + return result; } Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { @@ -1739,13 +1792,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.clearAttribute(TAK_box); } - // Diagnose @local_storage in nested positions. - if (attrs.has(TAK_local_storage)) { - assert(DC->getParentSourceFile()->Kind == SourceFileKind::SIL); - TC.diagnose(attrs.getLoc(TAK_local_storage),diag::sil_local_storage_nested); - attrs.clearAttribute(TAK_local_storage); - } - for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i) if (attrs.has((TypeAttrKind)i)) TC.diagnose(attrs.getLoc((TypeAttrKind)i), @@ -1761,8 +1807,7 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, options | TR_ImmediateFunctionInput); if (!inputTy || inputTy->is()) return inputTy; - Type outputTy = resolveType(repr->getResultTypeRepr(), - options | TR_FunctionResult); + Type outputTy = resolveType(repr->getResultTypeRepr(), options); if (!outputTy || outputTy->is()) return outputTy; extInfo = extInfo.withThrows(repr->throws()); @@ -1839,8 +1884,7 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, // For now, resolveSILResults only returns a single ordinary result. // FIXME: Deal with unsatisfied dependencies. SmallVector ordinaryResults; - if (resolveSILResults(repr->getResultTypeRepr(), - options | TR_FunctionResult, + if (resolveSILResults(repr->getResultTypeRepr(), options, ordinaryResults, errorResult)) { hasError = true; } else { @@ -2050,7 +2094,6 @@ bool TypeResolver::resolveSILResults(TypeRepr *repr, TypeResolutionOptions options, SmallVectorImpl &ordinaryResults, Optional &errorResult) { - assert(options & TR_FunctionResult && "Should be marked as a result"); // When we generalize SIL to handle multiple normal results, we // should always split up a tuple (a single level deep only). Until @@ -2078,6 +2121,7 @@ Type TypeResolver::resolveInOutType(InOutTypeRepr *repr, if (!(options & TR_FunctionInput) && !(options & TR_ImmediateFunctionInput)) { TC.diagnose(repr->getInOutLoc(), diag::inout_only_parameter); + repr->setInvalid(); return ErrorType::get(Context); } @@ -2090,14 +2134,6 @@ Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr, // FIXME: diagnose non-materializability of element type! Type baseTy = resolveType(repr->getBase(), withoutContext(options)); if (!baseTy || baseTy->is()) return baseTy; - - if (ExprHandle *sizeEx = repr->getSize()) { - // FIXME: We don't support fixed-length arrays yet. - // FIXME: We need to check Size! (It also has to be convertible to int). - TC.diagnose(repr->getBrackets().Start, diag::unsupported_fixed_length_array) - .highlight(sizeEx->getExpr()->getSourceRange()); - return ErrorType::get(Context); - } auto sliceTy = TC.getArraySliceType(repr->getBrackets().Start, baseTy); if (!sliceTy) @@ -2122,9 +2158,9 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, nullptr, TC.Context); TypeLoc args[2] = { TypeLoc(repr->getKey()), TypeLoc(repr->getValue()) }; - if (!TC.applyGenericArguments(unboundTy, repr->getStartLoc(), DC, args, - options.contains(TR_GenericSignature), - Resolver)) { + if (!TC.applyUnboundGenericArguments( + unboundTy, repr->getStartLoc(), DC, args, + options.contains(TR_GenericSignature), Resolver)) { return ErrorType::get(TC.Context); } @@ -2406,37 +2442,9 @@ static void describeObjCReason(TypeChecker &TC, const ValueDecl *VD, } } -static Type getFunctionParamType(const Pattern *P) { - if (auto *TP = dyn_cast(P)) - return TP->getType(); - return {}; -} - -static SourceRange getFunctionParamTypeSourceRange(const Pattern *P) { - if (auto *TP = dyn_cast(P)) - return TP->getTypeLoc().getTypeRepr()->getSourceRange(); - return {}; -} - -static bool isParamRepresentableInObjC(TypeChecker &TC, - const DeclContext *DC, - const Pattern *P) { - // Look through 'var' pattern. - if (auto VP = dyn_cast(P)) - P = VP->getSubPattern(); - - auto *TP = dyn_cast(P); - if (!TP) - return false; - if (!TC.isRepresentableInObjC(DC, TP->getType())) - return false; - auto *SubPattern = TP->getSubPattern(); - return isa(SubPattern) || isa(SubPattern); -} - static void diagnoseFunctionParamNotRepresentable( TypeChecker &TC, const AbstractFunctionDecl *AFD, unsigned NumParams, - unsigned ParamIndex, const Pattern *P, ObjCReason Reason) { + unsigned ParamIndex, const ParamDecl *P, ObjCReason Reason) { if (Reason == ObjCReason::DoNotDiagnose) return; @@ -2447,77 +2455,68 @@ static void diagnoseFunctionParamNotRepresentable( TC.diagnose(AFD->getLoc(), diag::objc_invalid_on_func_param_type, ParamIndex + 1, getObjCDiagnosticAttrKind(Reason)); } - if (Type ParamTy = getFunctionParamType(P)) { - SourceRange SR = getFunctionParamTypeSourceRange(P); + if (P->hasType()) { + Type ParamTy = P->getType(); + SourceRange SR; + if (auto typeRepr = P->getTypeLoc().getTypeRepr()) + SR = typeRepr->getSourceRange(); TC.diagnoseTypeNotRepresentableInObjC(AFD, ParamTy, SR); } describeObjCReason(TC, AFD, Reason); } -static bool isParamPatternRepresentableInObjC(TypeChecker &TC, - const AbstractFunctionDecl *AFD, - const Pattern *P, - ObjCReason Reason) { +static bool isParamListRepresentableInObjC(TypeChecker &TC, + const AbstractFunctionDecl *AFD, + const ParameterList *PL, + ObjCReason Reason) { // If you change this function, you must add or modify a test in PrintAsObjC. bool Diagnose = (Reason != ObjCReason::DoNotDiagnose); - if (auto *TP = dyn_cast(P)) { - auto Fields = TP->getElements(); - unsigned NumParams = Fields.size(); - // Varargs are not representable in Objective-C. - if (TP->hasAnyEllipsis()) { + bool IsObjC = true; + unsigned NumParams = PL->size(); + for (unsigned ParamIndex = 0; ParamIndex != NumParams; ParamIndex++) { + auto param = PL->get(ParamIndex); + + // Swift Varargs are not representable in Objective-C. + if (param->isVariadic()) { if (Diagnose && Reason != ObjCReason::DoNotDiagnose) { - TC.diagnose(TP->getAnyEllipsisLoc(), - diag::objc_invalid_on_func_variadic, - getObjCDiagnosticAttrKind(Reason)); + TC.diagnose(param->getStartLoc(), diag::objc_invalid_on_func_variadic, + getObjCDiagnosticAttrKind(Reason)) + .highlight(param->getSourceRange()); describeObjCReason(TC, AFD, Reason); } - + return false; } - - if (NumParams == 0) - return true; - - bool IsObjC = true; - for (unsigned ParamIndex = 0; ParamIndex != NumParams; ParamIndex++) { - auto &TupleElt = Fields[ParamIndex]; - if (!isParamRepresentableInObjC(TC, AFD, TupleElt.getPattern())) { - // Permit '()' when this method overrides a method with a - // foreign error convention that replaces NSErrorPointer with () - // and this is the replaced parameter. - AbstractFunctionDecl *overridden; - if (TupleElt.getPattern()->getType()->isVoid() && - AFD->isBodyThrowing() && - (overridden = AFD->getOverriddenDecl())) { - auto foreignError = overridden->getForeignErrorConvention(); - if (foreignError && - foreignError->isErrorParameterReplacedWithVoid() && - foreignError->getErrorParameterIndex() == ParamIndex) { - continue; - } - } - - IsObjC = false; - if (!Diagnose) { - // Save some work and return as soon as possible if we are not - // producing diagnostics. - return IsObjC; - } - diagnoseFunctionParamNotRepresentable(TC, AFD, NumParams, ParamIndex, - TupleElt.getPattern(), Reason); + + if (TC.isRepresentableInObjC(AFD, param->getType())) + continue; + + // Permit '()' when this method overrides a method with a + // foreign error convention that replaces NSErrorPointer with () + // and this is the replaced parameter. + AbstractFunctionDecl *overridden; + if (param->getType()->isVoid() && AFD->isBodyThrowing() && + (overridden = AFD->getOverriddenDecl())) { + auto foreignError = overridden->getForeignErrorConvention(); + if (foreignError && + foreignError->isErrorParameterReplacedWithVoid() && + foreignError->getErrorParameterIndex() == ParamIndex) { + continue; } } - return IsObjC; - } - auto *PP = cast(P); - if (!isParamRepresentableInObjC(TC, AFD, PP->getSubPattern())) { - diagnoseFunctionParamNotRepresentable(TC, AFD, 1, 1, PP->getSubPattern(), - Reason); - return false; + + IsObjC = false; + if (!Diagnose) { + // Save some work and return as soon as possible if we are not + // producing diagnostics. + return IsObjC; + } + diagnoseFunctionParamNotRepresentable(TC, AFD, NumParams, ParamIndex, + param, Reason); } - return true; + return IsObjC; } /// Check whether the given declaration occurs within a constrained @@ -2637,20 +2636,8 @@ static bool isBridgedToObjectiveCClass(DeclContext *dc, Type type) { // Allow anything that isn't bridged to NSNumber. // FIXME: This feels like a hack, but we don't have the right predicate // anywhere. - return classDecl->getName().str() != "NSNumber"; -} - -/// Determine whether this is a trailing closure type. -static AnyFunctionType *isTrailingClosure(Type type) { - // Only consider the rvalue type. - type = type->getRValueType(); - - // Look through one level of optionality. - if (auto objectType = type->getAnyOptionalObjectType()) - type = objectType; - - // Is it a function type? - return type->getAs(); + return classDecl->getName().str() + != ctx.getSwiftName(KnownFoundationEntity::NSNumber); } bool TypeChecker::isRepresentableInObjC( @@ -2695,7 +2682,7 @@ bool TypeChecker::isRepresentableInObjC( unsigned ExpectedParamPatterns = 1; if (FD->getImplicitSelfDecl()) ExpectedParamPatterns++; - if (FD->getBodyParamPatterns().size() != ExpectedParamPatterns) { + if (FD->getParameterLists().size() != ExpectedParamPatterns) { if (Diagnose) { diagnose(AFD->getLoc(), diag::objc_invalid_on_func_curried, getObjCDiagnosticAttrKind(Reason)); @@ -2731,9 +2718,8 @@ bool TypeChecker::isRepresentableInObjC( isSpecialInit = init->isObjCZeroParameterWithLongSelector(); if (!isSpecialInit && - !isParamPatternRepresentableInObjC(*this, AFD, - AFD->getBodyParamPatterns()[1], - Reason)) { + !isParamListRepresentableInObjC(*this, AFD, AFD->getParameterList(1), + Reason)) { if (!Diagnose) { // Return as soon as possible if we are not producing diagnostics. return false; @@ -2868,18 +2854,23 @@ bool TypeChecker::isRepresentableInObjC( // If the selector did not provide an index for the error, find // the last parameter that is not a trailing closure. if (!foundErrorParameterIndex) { - const Pattern *paramPattern = AFD->getBodyParamPatterns()[1]; - if (auto *tuple = dyn_cast(paramPattern)) { - errorParameterIndex = tuple->getNumElements(); - while (errorParameterIndex > 0 && - isTrailingClosure( - tuple->getElement(errorParameterIndex - 1).getPattern() - ->getType())) - --errorParameterIndex; - } else { - auto paren = cast(paramPattern); - errorParameterIndex - = isTrailingClosure(paren->getSubPattern()->getType()) ? 0 : 1; + auto *paramList = AFD->getParameterList(1); + errorParameterIndex = paramList->size(); + while (errorParameterIndex > 0) { + // Skip over trailing closures. + auto type = paramList->get(errorParameterIndex - 1)->getType(); + + // It can't be a trailing closure unless it has a specific form. + // Only consider the rvalue type. + type = type->getRValueType(); + + // Look through one level of optionality. + if (auto objectType = type->getAnyOptionalObjectType()) + type = objectType; + + // Is it a function type? + if (!type->is()) break; + --errorParameterIndex; } } @@ -2987,6 +2978,9 @@ bool TypeChecker::isRepresentableInObjC(const SubscriptDecl *SD, if (TupleTy->getNumElements() == 1 && !TupleTy->getElement(0).isVararg()) IndicesType = TupleTy->getElementType(0); } + + if (IndicesType->is()) + return false; bool IndicesResult = isRepresentableInObjC(SD->getDeclContext(), IndicesType); bool ElementResult = isRepresentableInObjC(SD->getDeclContext(), @@ -3390,7 +3384,8 @@ void TypeChecker::fillObjCRepresentableTypeCache(const DeclContext *DC) { StdlibTypeNames.clear(); StdlibTypeNames.push_back(Context.getIdentifier("Selector")); StdlibTypeNames.push_back(Context.getIdentifier("ObjCBool")); - StdlibTypeNames.push_back(Context.getIdentifier("NSZone")); + StdlibTypeNames.push_back( + Context.getSwiftId(KnownFoundationEntity::NSZone)); lookupAndAddLibraryTypes(*this, ObjCModule, StdlibTypeNames, ObjCMappedTypes); } @@ -3406,7 +3401,8 @@ void TypeChecker::fillObjCRepresentableTypeCache(const DeclContext *DC) { Identifier ID_Foundation = Context.Id_Foundation; if (auto FoundationModule = Context.getLoadedModule(ID_Foundation)) { StdlibTypeNames.clear(); - StdlibTypeNames.push_back(Context.getIdentifier("NSErrorPointer")); + StdlibTypeNames.push_back( + Context.getSwiftId(KnownFoundationEntity::NSErrorPointer)); lookupAndAddLibraryTypes(*this, FoundationModule, StdlibTypeNames, ObjCMappedTypes); } @@ -3435,28 +3431,66 @@ class UnsupportedProtocolVisitor : public TypeReprVisitor, public ASTWalker { TypeChecker &TC; - SmallPtrSet Diagnosed; - + bool recurseIntoSubstatements; + bool hitTopStmt; + public: - UnsupportedProtocolVisitor(TypeChecker &tc) : TC(tc) { } + UnsupportedProtocolVisitor(TypeChecker &tc) : TC(tc) { + recurseIntoSubstatements = true; + hitTopStmt = false; + } - SmallPtrSet &getDiagnosedProtocols() { return Diagnosed; } + void setRecurseIntoSubstatements(bool recurse) { + recurseIntoSubstatements = recurse; + } bool walkToTypeReprPre(TypeRepr *T) { visit(T); return true; } + + std::pair walkToStmtPre(Stmt *S) { + if (recurseIntoSubstatements) { + return { true, S }; + } else if (hitTopStmt) { + return { false, S }; + } else { + hitTopStmt = true; + return { true, S }; + } + } void visitIdentTypeRepr(IdentTypeRepr *T) { + if (T->isInvalid()) + return; + auto comp = T->getComponentRange().back(); if (auto proto = dyn_cast_or_null(comp->getBoundDecl())) { if (!proto->existentialTypeSupported(&TC)) { TC.diagnose(comp->getIdLoc(), diag::unsupported_existential_type, proto->getName()); - Diagnosed.insert(proto); + T->setInvalid(); } - - return; + } else if (auto alias = dyn_cast_or_null(comp->getBoundDecl())) { + if (!alias->hasUnderlyingType()) + return; + auto type = alias->getUnderlyingType(); + type.findIf([&](Type type) -> bool { + if (T->isInvalid()) + return false; + SmallVector protocols; + if (type->isExistentialType(protocols)) { + for (auto *proto : protocols) { + if (proto->existentialTypeSupported(&TC)) + continue; + + TC.diagnose(comp->getIdLoc(), diag::unsupported_existential_type, + proto->getName()); + T->setInvalid(); + } + } + return false; + }); } } }; @@ -3482,27 +3516,6 @@ void TypeChecker::checkUnsupportedProtocolType(Decl *decl) { UnsupportedProtocolVisitor visitor(*this); decl->walk(visitor); - if (auto valueDecl = dyn_cast(decl)) { - if (auto type = valueDecl->getType()) { - type.findIf([&](Type type) -> bool { - SmallVector protocols; - if (type->isExistentialType(protocols)) { - for (auto *proto : protocols) { - if (proto->existentialTypeSupported(this)) - continue; - - if (visitor.getDiagnosedProtocols().insert(proto).second) { - diagnose(valueDecl->getLoc(), - diag::unsupported_existential_type, - proto->getName()); - } - } - } - - return false; - }); - } - } } void TypeChecker::checkUnsupportedProtocolType(Stmt *stmt) { @@ -3510,5 +3523,9 @@ void TypeChecker::checkUnsupportedProtocolType(Stmt *stmt) { return; UnsupportedProtocolVisitor visitor(*this); + + // This method will already be called for all individual statements, so don't repeat + // that checking by walking into any statement inside this one. + visitor.setRecurseIntoSubstatements(false); stmt->walk(visitor); } diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 438f4d263ebdc..ed829723d18ba 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,6 +27,7 @@ #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/STLExtras.h" +#include "swift/Basic/Timer.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/Parse/Lexer.h" #include "swift/Sema/CodeCompletionTypeChecking.h" @@ -387,6 +388,11 @@ static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) { auto decl = TC.Context.ExternalDefinitions[currentExternalDef]; if (auto *AFD = dyn_cast(decl)) { + // HACK: don't type-check the same function body twice. This is + // supposed to be handled by just not enqueuing things twice, + // but that gets tricky with synthesized function bodies. + if (AFD->isBodyTypeChecked()) continue; + PrettyStackTraceDecl StackEntry("type-checking", AFD); TC.typeCheckAbstractFunctionBody(AFD); continue; @@ -463,11 +469,6 @@ static void typeCheckFunctionsAndExternalDecls(TypeChecker &TC) { } TC.UsedConformances.clear(); - TC.definedFunctions.insert(TC.definedFunctions.end(), - TC.implicitlyDefinedFunctions.begin(), - TC.implicitlyDefinedFunctions.end()); - TC.implicitlyDefinedFunctions.clear(); - } while (currentFunctionIdx < TC.definedFunctions.size() || currentExternalDef < TC.Context.ExternalDefinitions.size() || !TC.UsedConformances.empty()); @@ -511,14 +512,18 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // Make sure that name binding has been completed before doing any type // checking. - performNameBinding(SF, StartElem); + { + SharedTimer timer("Name binding"); + performNameBinding(SF, StartElem); + } auto &Ctx = SF.getASTContext(); { // NOTE: The type checker is scoped to be torn down before AST // verification. TypeChecker TC(Ctx); - auto &DefinedFunctions = TC.definedFunctions; + SharedTimer timer("Type checking / Semantic analysis"); + if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies)) TC.enableDebugTimeFunctionBodies(); @@ -587,11 +592,6 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, TC.contextualizeTopLevelCode(TLC, llvm::makeArrayRef(SF.Decls).slice(StartElem)); } - - DefinedFunctions.insert(DefinedFunctions.end(), - TC.implicitlyDefinedFunctions.begin(), - TC.implicitlyDefinedFunctions.end()); - TC.implicitlyDefinedFunctions.clear(); // If we're in REPL mode, inject temporary result variables and other stuff // that the REPL needs to synthesize. @@ -609,16 +609,19 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // Verify that we've checked types correctly. SF.ASTStage = SourceFile::TypeChecked; - // Verify the SourceFile. - verify(SF); + { + SharedTimer timer("AST verification"); + // Verify the SourceFile. + verify(SF); - // Verify imported modules. + // Verify imported modules. #ifndef NDEBUG - if (SF.Kind != SourceFileKind::REPL && - !Ctx.LangOpts.DebuggerSupport) { - Ctx.verifyAllLoadedModules(); - } + if (SF.Kind != SourceFileKind::REPL && + !Ctx.LangOpts.DebuggerSupport) { + Ctx.verifyAllLoadedModules(); + } #endif + } } void swift::performWholeModuleTypeChecking(SourceFile &SF) { @@ -633,6 +636,9 @@ bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T, bool isSILType, DeclContext *DC, bool ProduceDiagnostics) { TypeResolutionOptions options; + + // Fine to have unbound generic types. + options |= TR_AllowUnboundGenerics; if (isSILType) options |= TR_SILType; @@ -988,9 +994,17 @@ class TypeRefinementContextBuilder : private ASTWalker { if (auto *storageDecl = dyn_cast(D)) { // Use the declaration's availability for the context when checking // the bodies of its accessors. - if (storageDecl->hasAccessorFunctions()) { + + // HACK: For synthesized trivial accessors we may have not a valid + // location for the end of the braces, so in that case we will fall back + // to using the range for the storage declaration. The right fix here is + // to update AbstractStorageDecl::addTrivialAccessors() to take brace + // locations and have callers of that method provide appropriate source + // locations. + SourceLoc BracesEnd = storageDecl->getBracesRange().End; + if (storageDecl->hasAccessorFunctions() && BracesEnd.isValid()) { return SourceRange(storageDecl->getStartLoc(), - storageDecl->getBracesRange().End); + BracesEnd); } // For a variable declaration (without accessors) we use the range of the @@ -1386,7 +1400,7 @@ TypeChecker::overApproximateOSVersionsAtLocation(SourceLoc loc, SourceFile *SF = DC->getParentSourceFile(); // If our source location is invalid (this may be synthesized code), climb - // the decl context hierarchy until until we find a location that is valid, + // the decl context hierarchy until we find a location that is valid, // collecting availability ranges on the way up. // We will combine the version ranges from these annotations // with the TRC for the valid location to overapproximate the running @@ -1585,7 +1599,7 @@ class InnermostAncestorFinder : private ASTWalker { } /// Once we have found the target node, look for the innermost ancestor - /// matching our criteria on the way back up the spine of of the tree. + /// matching our criteria on the way back up the spine of the tree. bool walkToNodePost(ASTNode Node) { if (!InnermostMatchingNode.hasValue() && Predicate(Node, Parent)) { assert(Node.getSourceRange().isInvalid() || @@ -1790,11 +1804,11 @@ static const Decl *ancestorTypeLevelDeclForAvailabilityFixit(const Decl *D) { /// declaration context containing the reference, make a best effort find up to /// three locations for potential fixits. /// -/// \param FoundVersionCheckNode Returns a node that can be wrapped in a +/// \param FoundVersionCheckNode Returns a node that can be wrapped in a /// if #available(...) { ... } version check to fix the unavailable reference, -/// or None if such such a node cannot be found. +/// or None if such a node cannot be found. /// -/// \param FoundMemberLevelDecl Returns memember-level declaration (i.e., the +/// \param FoundMemberLevelDecl Returns member-level declaration (i.e., the /// child of a type DeclContext) for which an @available attribute would /// fix the unavailable reference. /// @@ -2205,8 +2219,9 @@ static bool isInsideDeprecatedDeclaration(SourceRange ReferenceRange, void TypeChecker::diagnoseDeprecated(SourceRange ReferenceRange, const DeclContext *ReferenceDC, const AvailableAttr *Attr, - DeclName Name) { - // We match the behavior of clang to not report deprecation warnigs + DeclName Name, + std::function extraInfoHandler) { + // We match the behavior of clang to not report deprecation warnings // inside declarations that are themselves deprecated on all deployment // targets. if (isInsideDeprecatedDeclaration(ReferenceRange, ReferenceDC, *this)) { @@ -2230,24 +2245,30 @@ void TypeChecker::diagnoseDeprecated(SourceRange ReferenceRange, DeprecatedVersion = Attr->Deprecated.getValue(); if (Attr->Message.empty() && Attr->Rename.empty()) { - diagnose(ReferenceRange.Start, diag::availability_deprecated, Name, - Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), - DeprecatedVersion) - .highlight(Attr->getRange()); + auto diagValue = std::move( + diagnose(ReferenceRange.Start, diag::availability_deprecated, Name, + Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), + DeprecatedVersion) + .highlight(Attr->getRange())); + extraInfoHandler(diagValue); return; } if (Attr->Message.empty()) { - diagnose(ReferenceRange.Start, diag::availability_deprecated_rename, Name, - Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), - DeprecatedVersion, Attr->Rename) - .highlight(Attr->getRange()); + auto diagValue = std::move( + diagnose(ReferenceRange.Start, diag::availability_deprecated_rename, Name, + Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), + DeprecatedVersion, Attr->Rename) + .highlight(Attr->getRange())); + extraInfoHandler(diagValue); } else { EncodedDiagnosticMessage EncodedMessage(Attr->Message); - diagnose(ReferenceRange.Start, diag::availability_deprecated_msg, Name, - Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), - DeprecatedVersion, EncodedMessage.Message) - .highlight(Attr->getRange()); + auto diagValue = std::move( + diagnose(ReferenceRange.Start, diag::availability_deprecated_msg, Name, + Attr->hasPlatform(), Platform, Attr->Deprecated.hasValue(), + DeprecatedVersion, EncodedMessage.Message) + .highlight(Attr->getRange())); + extraInfoHandler(diagValue); } if (!Attr->Rename.empty()) { @@ -2269,7 +2290,7 @@ void TypeChecker::checkForForbiddenPrefix(const Decl *D) { void TypeChecker::checkForForbiddenPrefix(const UnresolvedDeclRefExpr *E) { if (!hasEnabledForbiddenTypecheckPrefix()) return; - checkForForbiddenPrefix(E->getName()); + checkForForbiddenPrefix(E->getName().getBaseName()); } void TypeChecker::checkForForbiddenPrefix(Identifier Ident) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 4ca4c02a8f7bf..1ff7f4f80303a 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -158,18 +158,18 @@ enum ContextualTypePurpose { CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type. CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type. CTP_AssignSource, ///< AssignExpr source operand coerced to result type. - + CTP_CannotFail, ///< Conversion can never fail. abort() if it does. }; - + /// Flags that can be used to control name lookup. enum class TypeCheckExprFlags { /// Whether we know that the result of the expression is discarded. This /// disables constraints forcing an lvalue result to be loadable. IsDiscarded = 0x01, - + /// Whether the client wants to disable the structural syntactic restrictions /// that we force for style or other reasons. DisableStructuralChecks = 0x02, @@ -183,7 +183,7 @@ enum class TypeCheckExprFlags { /// system is not applied to the expression AST, but the ConstraintSystem is /// left in-tact. AllowUnresolvedTypeVariables = 0x08, - + /// If set, the 'convertType' specified to typeCheckExpression should not /// produce a conversion constraint, but it should be used to guide the /// solution in terms of performance optimizations of the solver, and in terms @@ -194,12 +194,12 @@ enum class TypeCheckExprFlags { /// statement. This should only be used for syntactic restrictions, and should /// not affect type checking itself. IsExprStmt = 0x20, - + /// If set, this expression is being re-type checked as part of diagnostics, /// and so we should not visit bodies of non-single expression closures. SkipMultiStmtClosures = 0x40, }; - + typedef OptionSet TypeCheckExprOptions; inline TypeCheckExprOptions operator|(TypeCheckExprFlags flag1, @@ -218,6 +218,9 @@ enum class NameLookupFlags { DynamicLookup = 0x04, /// Whether we're only looking for types. OnlyTypes = 0x08, + /// Whether to ignore access control for this lookup, allowing inaccessible + /// results to be returned. + IgnoreAccessibility = 0x10, }; /// A set of options that control name lookup. @@ -301,9 +304,6 @@ enum TypeResolutionFlags : unsigned { /// Whether to allow unspecified types within a pattern. TR_AllowUnspecifiedTypes = 0x01, - /// Whether the pattern is variadic. - TR_Variadic = 0x02, - /// Whether the given type can override the type of a typed pattern. TR_OverrideType = 0x04, @@ -316,23 +316,20 @@ enum TypeResolutionFlags : unsigned { /// Whether we are in the input type of a function, or under one level of /// tuple type. This is not set for multi-level tuple arguments. TR_FunctionInput = 0x20, - + /// Whether this is the immediate input type to a function type, TR_ImmediateFunctionInput = 0x40, - /// Whether we are in the result type of a function type. - TR_FunctionResult = 0x80, - /// Whether we are in the result type of a function body that is /// known to produce dynamic Self. TR_DynamicSelfResult = 0x100, - + /// Whether this is a resolution based on a non-inferred type pattern. TR_FromNonInferredPattern = 0x200, - + /// Whether we are the variable type in a for/in statement. TR_EnumerationVariable = 0x400, - + /// Whether we are looking only in the generic signature of the context /// we're searching, rather than the entire context. TR_GenericSignature = 0x800, @@ -348,13 +345,13 @@ enum TypeResolutionFlags : unsigned { /// This affects what sort of dependencies are recorded when resolving the /// type. TR_InExpression = 0x4000, - + /// Whether this type resolution is guaranteed not to affect downstream files. TR_KnownNonCascadingDependency = 0x8000, /// Whether we should allow references to unavailable types. TR_AllowUnavailable = 0x10000, - + /// Whether this is the payload subpattern of an enum pattern. TR_EnumPatternPayload = 0x20000, @@ -387,7 +384,6 @@ static inline TypeResolutionOptions withoutContext(TypeResolutionOptions options) { options -= TR_ImmediateFunctionInput; options -= TR_FunctionInput; - options -= TR_FunctionResult; options -= TR_EnumCase; return options; } @@ -439,10 +435,6 @@ class TypeChecker final : public LazyResolver { ASTContext &Context; DiagnosticEngine &Diags; - /// \brief The list of implicitly-defined functions created by the - /// type checker. - std::vector implicitlyDefinedFunctions; - /// \brief The list of function definitions we've encountered. std::vector definedFunctions; @@ -460,6 +452,10 @@ class TypeChecker final : public LazyResolver { /// This can't use CanTypes because typealiases may have more limited types /// than their underlying types. llvm::DenseMap TypeAccessibilityCache; + + // Caches whether a given declaration is "as specialized" as another. + llvm::DenseMap, bool> + specializedOverloadComparisonCache; // We delay validation of C and Objective-C type-bridging functions in the // standard library until we encounter a declaration that requires one. This @@ -491,7 +487,7 @@ class TypeChecker final : public LazyResolver { /// use(x) /// } /// } - + llvm::SmallDenseMap, 4> ForwardCapturedFuncs; @@ -519,17 +515,18 @@ class TypeChecker final : public LazyResolver { Type UInt8Type; Type NSObjectType; Type NSErrorType; + Type ObjCSelectorType; Type ExceptionType; /// The \c Swift.UnsafeMutablePointer declaration. Optional ArrayDecl; - + /// A set of types that can be trivially mapped to Objective-C types. llvm::DenseSet ObjCMappedTypes; /// A set of types that can be mapped to C integer types. llvm::DenseSet CIntegerTypes; - + /// The set of expressions currently being analyzed for failures. llvm::DenseMap DiagnosedExprs; @@ -578,7 +575,7 @@ class TypeChecker final : public LazyResolver { void setInImmediateMode(bool InImmediateMode) { this->InImmediateMode = InImmediateMode; } - + template InFlightDiagnostic diagnose(ArgTypes &&...Args) { return Diags.diagnose(std::forward(Args)...); @@ -593,6 +590,7 @@ class TypeChecker final : public LazyResolver { Type getUInt8Type(DeclContext *dc); Type getNSObjectType(DeclContext *dc); Type getNSErrorType(DeclContext *dc); + Type getObjCSelectorType(DeclContext *dc); Type getExceptionType(DeclContext *dc, SourceLoc loc); /// \brief Try to resolve an IdentTypeRepr, returning either the referenced @@ -603,12 +601,12 @@ class TypeChecker final : public LazyResolver { bool diagnoseErrors, GenericTypeResolver *resolver, UnsatisfiedDependency *unsatisfiedDependency); - + /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used /// for the lookup. Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context); - + /// \brief Validate the given type. /// /// Type validation performs name binding, checking of generic arguments, @@ -702,25 +700,54 @@ class TypeChecker final : public LazyResolver { UnsatisfiedDependency *unsatisfiedDependency = nullptr); - /// \brief Apply generic arguments to the given type. + /// Apply generic arguments to the given type. + /// + /// This function emits diagnostics about an invalid type or the wrong number + /// of generic arguments, whereas applyUnboundGenericArguments requires this + /// to be in a correct and valid form. /// - /// \param type The unbound generic type to which to apply arguments. + /// \param type The generic type to which to apply arguments. /// \param loc The source location for diagnostic reporting. /// \param dc The context where the arguments are applied. - /// \param genericArgs The list of generic arguments to apply to the type. + /// \param generic The arguments to apply with the angle bracket range for + /// diagnostics. /// \param isGenericSignature True if we are looking only in the generic /// signature of the context. /// \param resolver The generic type resolver. /// /// \returns A BoundGenericType bound to the given arguments, or null on /// error. - Type applyGenericArguments(Type type, - SourceLoc loc, - DeclContext *dc, - MutableArrayRef genericArgs, + /// + /// \see applyUnboundGenericArguments + Type applyGenericArguments(Type type, SourceLoc loc, DeclContext *dc, + GenericIdentTypeRepr *generic, bool isGenericSignature, GenericTypeResolver *resolver); + /// Apply generic arguments to the given type. + /// + /// This function requires a valid unbound generic type with the correct + /// number of generic arguments given, whereas applyGenericArguments emits + /// diagnostics in those cases. + /// + /// \param unbound The unbound generic type to which to apply arguments. + /// \param loc The source location for diagnostic reporting. + /// \param dc The context where the arguments are applied. + /// \param genericArgs The list of generic arguments to apply to the type. + /// \param isGenericSignature True if we are looking only in the generic + /// signature of the context. + /// \param resolver The generic type resolver. + /// + /// \returns A BoundGenericType bound to the given arguments, or null on + /// error. + /// + /// \see applyGenericArguments + Type applyUnboundGenericArguments(UnboundGenericType *unbound, SourceLoc loc, + DeclContext *dc, + MutableArrayRef genericArgs, + bool isGenericSignature, + GenericTypeResolver *resolver); + /// \brief Substitute the given base type into the type of the given member, /// producing the effective type that the member will have. /// @@ -781,7 +808,7 @@ class TypeChecker final : public LazyResolver { /// \returns true if a checked cast from \c t1 to \c t2 may succeed, and /// false if it will certainly fail, e.g. because the types are unrelated. bool checkedCastMaySucceed(Type t1, Type t2, DeclContext *dc); - + /// \brief Determine whether a constraint of the given kind can be satisfied /// by the two types. /// @@ -916,7 +943,7 @@ class TypeChecker final : public LazyResolver { GenericSignature *outerSignature, std::function inferRequirements, bool &invalid); - + /// Validate the signature of a generic type. /// /// \param nominal The generic type. @@ -993,7 +1020,7 @@ class TypeChecker final : public LazyResolver { /// \brief Add the RawOptionSet (todo:, Equatable, and Hashable) methods to an /// imported NS_OPTIONS struct. void addImplicitStructConformances(StructDecl *ED); - + /// \brief Add the RawRepresentable, Equatable, and Hashable methods to an /// enum with a raw type. void addImplicitEnumConformances(EnumDecl *ED); @@ -1041,7 +1068,7 @@ class TypeChecker final : public LazyResolver { /// \brief Fold the given sequence expression into an (unchecked) expression /// tree. Expr *foldSequence(SequenceExpr *expr, DeclContext *dc); - + /// \brief Type check the given expression. /// /// \param expr The expression to type-check, which will be modified in @@ -1076,7 +1103,7 @@ class TypeChecker final : public LazyResolver { TypeCheckExprOptions(), listener); } - + /// \brief Type check the given expression and return its type without /// applying the solution. /// @@ -1092,7 +1119,7 @@ class TypeChecker final : public LazyResolver { /// \returns the type of \p expr on success, None otherwise. /// FIXME: expr may still be modified... Optional getTypeOfExpressionWithoutApplying( - Expr *&expr, DeclContext *dc, + Expr *&expr, DeclContext *dc, FreeTypeVariableBinding allowFreeTypeVariables = FreeTypeVariableBinding::Disallow, ExprTypeCheckListener *listener = nullptr); @@ -1131,7 +1158,7 @@ class TypeChecker final : public LazyResolver { /// \returns true if an error occurred, false otherwise. bool typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc, Diag<> diagnosticForAlwaysTrue); - + /// \brief Determine the semantics of a checked cast operation. /// /// \param fromType The source type of the cast. @@ -1193,7 +1220,7 @@ class TypeChecker final : public LazyResolver { /// name lookup information. Must be done before type-checking the pattern. Pattern *resolvePattern(Pattern *P, DeclContext *dc, bool isStmtCondition); - + /// Type check the given pattern. /// /// \param P The pattern to type check. @@ -1208,6 +1235,11 @@ class TypeChecker final : public LazyResolver { bool typeCheckCatchPattern(CatchStmt *S, DeclContext *dc); + /// Type check a parameter list. + bool typeCheckParameterList(ParameterList *PL, DeclContext *dc, + TypeResolutionOptions options, + GenericTypeResolver *resolver = nullptr); + /// Coerce a pattern to the given type. /// /// \param P The pattern, which may be modified by this coercion. @@ -1223,6 +1255,13 @@ class TypeChecker final : public LazyResolver { bool typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, Type type); + /// Coerce the specified parameter list of a ClosureExpr to the specified + /// contextual type. + /// + /// \returns true if an error occurred, false otherwise. + bool coerceParameterListToType(ParameterList *P, DeclContext *dc, Type type); + + /// Type-check an initialized variable pattern declaration. bool typeCheckBinding(Pattern *&P, Expr *&Init, DeclContext *DC); bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber); @@ -1282,10 +1321,10 @@ class TypeChecker final : public LazyResolver { /// /// \returns true if an error occurred, false otherwise. bool convertToType(Expr *&expr, Type type, DeclContext *dc); - + /// \brief Coerce the given expression to an rvalue, if it isn't already. Expr *coerceToRValue(Expr *expr); - + /// \brief Coerce the given expression to materializable type, if it /// isn't already. Expr *coerceToMaterializable(Expr *expr); @@ -1332,7 +1371,7 @@ class TypeChecker final : public LazyResolver { /// /// \param name The name of the method to call. /// - /// \param arguments The arguments to + /// \param arguments The arguments to /// /// \param brokenProtocolDiag Diagnostic to emit if the protocol is broken. /// @@ -1418,7 +1457,7 @@ class TypeChecker final : public LazyResolver { ValueDecl *deriveProtocolRequirement(DeclContext *DC, NominalTypeDecl *TypeDecl, ValueDecl *Requirement); - + /// Derive an implicit type witness for the given associated type in /// the conformance of the given nominal type to some known /// protocol. @@ -1452,7 +1491,7 @@ class TypeChecker final : public LazyResolver { /// \brief Look up a member type within the given type. /// /// This routine looks for member types with the given name within the - /// given type. + /// given type. /// /// \param dc The context that needs the member. /// \param type The type in which we will look for a member type. @@ -1488,9 +1527,8 @@ class TypeChecker final : public LazyResolver { /// marked as unavailable, either through "unavailable" or "obsoleted=". bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R, - const DeclContext *DC, - const Expr *ParentExpr); - + const DeclContext *DC); + /// @} /// Fix the name of the given function to the target name, attaching @@ -1517,12 +1555,12 @@ class TypeChecker final : public LazyResolver { /// \brief Build a type-checked reference to the given value. Expr *buildCheckedRefExpr(ValueDecl *D, DeclContext *UseDC, - SourceLoc nameLoc, bool Implicit); + DeclNameLoc nameLoc, bool Implicit); /// \brief Build a reference to a declaration, where name lookup returned /// the given set of declarations. Expr *buildRefExpr(ArrayRef Decls, DeclContext *UseDC, - SourceLoc NameLoc, bool Implicit, + DeclNameLoc NameLoc, bool Implicit, bool isSpecialized = false); /// @} @@ -1580,7 +1618,7 @@ class TypeChecker final : public LazyResolver { Type T, SourceRange TypeRange); void fillObjCRepresentableTypeCache(const DeclContext *DC); - + ArchetypeBuilder createArchetypeBuilder(Module *mod); /// \name Availability checking @@ -1603,7 +1641,7 @@ class TypeChecker final : public LazyResolver { VersionRange &requiredRange); /// Returns an over-approximation of the range of operating system versions - /// that could the passed-in location location could be executing upon for + /// that could the passed-in location could be executing upon for /// the target platform. VersionRange overApproximateOSVersionsAtLocation(SourceLoc loc, const DeclContext *DC); @@ -1689,10 +1727,14 @@ class TypeChecker final : public LazyResolver { static const AvailableAttr *getDeprecated(const Decl *D); /// Emits a diagnostic for a reference to a declaration that is deprecated. + /// Callers can provide a lambda that adds additional information (such as a + /// fixit hint) to the deprecation diagnostic, if it is emitted. void diagnoseDeprecated(SourceRange SourceRange, const DeclContext *ReferenceDC, const AvailableAttr *Attr, - DeclName Name); + DeclName Name, + std::function extraInfoHandler = + [](InFlightDiagnostic&){}); /// @} /// If LangOptions::DebugForbidTypecheckPrefix is set and the given decl @@ -1724,13 +1766,13 @@ class TypeChecker final : public LazyResolver { /// initializer context, returns the implicit 'self' decl of the constructor. /// Otherwise, return nil. VarDecl *getSelfForInitDelegationInConstructor(DeclContext *DC, - UnresolvedConstructorExpr *ctorRef); + UnresolvedDotExpr *ctorRef); /// When referencing a class initializer, check that the base expression is /// either a static metatype or that the initializer is 'required'. bool diagnoseInvalidDynamicConstructorReferences(Expr *base, - SourceLoc memberRefLoc, + DeclNameLoc memberRefLoc, AnyMetatypeType *metaTy, ConstructorDecl *ctorDecl, bool SuppressDiagnostics); @@ -1754,7 +1796,7 @@ class TypeChecker final : public LazyResolver { class CleanupIllFormedExpressionRAII { ASTContext &Context; Expr **expr; - + public: CleanupIllFormedExpressionRAII(ASTContext &Context, Expr *&expr) : Context(Context), expr(&expr) { } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 80e2fa1ef454a..0c2e1a68ad0aa 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,15 +17,13 @@ #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/ClangImporter/ClangImporter.h" +#include "swift/Parse/Parser.h" #include "swift/Serialization/BCReadingExtras.h" #include "llvm/Support/raw_ostream.h" using namespace swift; using namespace swift::serialization; -using ConformancePair = std::pair; - - namespace { struct IDAndKind { const Decl *D; @@ -270,10 +268,55 @@ getActualDefaultArgKind(uint8_t raw) { return swift::DefaultArgumentKind::Function; case serialization::DefaultArgumentKind::DSOHandle: return swift::DefaultArgumentKind::DSOHandle; + case serialization::DefaultArgumentKind::Nil: + return swift::DefaultArgumentKind::Nil; + case serialization::DefaultArgumentKind::EmptyArray: + return swift::DefaultArgumentKind::EmptyArray; + case serialization::DefaultArgumentKind::EmptyDictionary: + return swift::DefaultArgumentKind::EmptyDictionary; } return None; } +ParameterList *ModuleFile::readParameterList() { + using namespace decls_block; + + SmallVector scratch; + auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch); + assert(recordID == PARAMETERLIST); + (void) recordID; + unsigned numParams; + decls_block::ParameterListLayout::readRecord(scratch, numParams); + + SmallVector params; + for (unsigned i = 0; i != numParams; ++i) { + scratch.clear(); + auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch); + assert(recordID == PARAMETERLIST_ELT); + (void) recordID; + + DeclID paramID; + bool isVariadic; + uint8_t rawDefaultArg; + decls_block::ParameterListEltLayout::readRecord(scratch, paramID, + isVariadic, rawDefaultArg); + + + auto decl = cast(getDecl(paramID)); + decl->setVariadic(isVariadic); + + // Decode the default argument kind. + // FIXME: Default argument expression, if available. + if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg)) + decl->setDefaultArgumentKind(*defaultArg); + params.push_back(decl); + } + + return ParameterList::create(getContext(), params); +} + Pattern *ModuleFile::maybeReadPattern() { using namespace decls_block; @@ -319,25 +362,12 @@ Pattern *ModuleFile::maybeReadPattern() { // FIXME: Add something for this record or remove it. IdentifierID labelID; - uint8_t rawDefaultArg; - bool hasEllipsis; - TuplePatternEltLayout::readRecord(scratch, labelID, hasEllipsis, - rawDefaultArg); + TuplePatternEltLayout::readRecord(scratch, labelID); Identifier label = getIdentifier(labelID); Pattern *subPattern = maybeReadPattern(); assert(subPattern); - - // Decode the default argument kind. - // FIXME: Default argument expression, if available. - swift::DefaultArgumentKind defaultArgKind - = swift::DefaultArgumentKind::None; - if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg)) - defaultArgKind = *defaultArg; - - elements.push_back(TuplePatternElt(label, SourceLoc(), subPattern, - hasEllipsis, SourceLoc(), - nullptr, defaultArgKind)); + elements.push_back(TuplePatternElt(label, SourceLoc(), subPattern)); } auto result = TuplePattern::create(getContext(), SourceLoc(), @@ -401,7 +431,7 @@ Pattern *ModuleFile::maybeReadPattern() { } } -ProtocolConformance *ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ +ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ using namespace decls_block; SmallVector scratch; @@ -411,9 +441,11 @@ ProtocolConformance *ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ unsigned kind = Cursor.readRecord(next.ID, scratch); switch (kind) { - case NO_CONFORMANCE: { - // Nothing to read. - return nullptr; + case ABSTRACT_PROTOCOL_CONFORMANCE: { + DeclID protoID; + AbstractProtocolConformanceLayout::readRecord(scratch, protoID); + auto proto = cast(getDecl(protoID)); + return ProtocolConformanceRef(proto); } case SPECIALIZED_PROTOCOL_CONFORMANCE: { @@ -433,11 +465,14 @@ ProtocolConformance *ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ substitutions.push_back(*sub); } - ProtocolConformance *genericConformance = readConformance(Cursor); + ProtocolConformanceRef genericConformance = readConformance(Cursor); - assert(genericConformance && "Missing generic conformance?"); - return ctx.getSpecializedConformance(conformingType, genericConformance, + assert(genericConformance.isConcrete() && "Abstract generic conformance?"); + auto conformance = + ctx.getSpecializedConformance(conformingType, + genericConformance.getConcrete(), ctx.AllocateCopy(substitutions)); + return ProtocolConformanceRef(conformance); } case INHERITED_PROTOCOL_CONFORMANCE: { @@ -447,16 +482,20 @@ ProtocolConformance *ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ ASTContext &ctx = getContext(); Type conformingType = getType(conformingTypeID); - ProtocolConformance *inheritedConformance = readConformance(Cursor); + ProtocolConformanceRef inheritedConformance = readConformance(Cursor); - assert(inheritedConformance && "Missing generic conformance?"); - return ctx.getInheritedConformance(conformingType, inheritedConformance); + assert(inheritedConformance.isConcrete() && + "Abstract inherited conformance?"); + auto conformance = + ctx.getInheritedConformance(conformingType, + inheritedConformance.getConcrete()); + return ProtocolConformanceRef(conformance); } case NORMAL_PROTOCOL_CONFORMANCE_ID: { NormalConformanceID conformanceID; NormalProtocolConformanceIdLayout::readRecord(scratch, conformanceID); - return readNormalConformance(conformanceID); + return ProtocolConformanceRef(readNormalConformance(conformanceID)); } case PROTOCOL_CONFORMANCE_XREF: { @@ -474,13 +513,14 @@ ProtocolConformance *ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){ nominal->lookupConformance(module, proto, conformances); assert(!conformances.empty() && "Could not find conformance"); - return conformances.front(); + return ProtocolConformanceRef(conformances.front()); } // Not a protocol conformance. default: error(); - return nullptr; + ProtocolConformance *conformance = nullptr; + return ProtocolConformanceRef(conformance); // FIXME: this will assert } } @@ -539,8 +579,9 @@ NormalProtocolConformance *ModuleFile::readNormalConformance( // Read inherited conformances. InheritedConformanceMap inheritedConformances; while (inheritedCount--) { - auto inherited = readConformance(DeclTypeCursor); - assert(inherited); + auto inheritedRef = readConformance(DeclTypeCursor); + assert(inheritedRef.isConcrete()); + auto inherited = inheritedRef.getConcrete(); inheritedConformances[inherited->getProtocol()] = inherited; } @@ -572,23 +613,21 @@ ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor) { if (recordID != decls_block::BOUND_GENERIC_SUBSTITUTION) return None; - TypeID archetypeID, replacementID; + TypeID replacementID; unsigned numConformances; decls_block::BoundGenericSubstitutionLayout::readRecord(scratch, - archetypeID, replacementID, numConformances); - auto archetypeTy = getType(archetypeID)->castTo(); auto replacementTy = getType(replacementID); - SmallVector conformanceBuf; + SmallVector conformanceBuf; while (numConformances--) { conformanceBuf.push_back(readConformance(cursor)); } lastRecordOffset.reset(); - return Substitution{archetypeTy, replacementTy, + return Substitution{replacementTy, getContext().AllocateCopy(conformanceBuf)}; } @@ -728,7 +767,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC, auto subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0])); auto constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1])); - requirements.push_back(RequirementRepr::getConformance(subject, + requirements.push_back(RequirementRepr::getTypeConstraint(subject, SourceLoc(), constraint)); break; @@ -743,6 +782,7 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC, break; } + case GenericRequirementKind::Superclass: case WitnessMarker: { // Shouldn't happen where we have requirement representations. error(); @@ -825,6 +865,14 @@ void ModuleFile::readGenericRequirements( subject, constraint)); break; } + case GenericRequirementKind::Superclass: { + auto subject = getType(rawTypeIDs[0]); + auto constraint = getType(rawTypeIDs[1]); + + requirements.push_back(Requirement(RequirementKind::Superclass, + subject, constraint)); + break; + } case GenericRequirementKind::SameType: { auto first = getType(rawTypeIDs[0]); auto second = getType(rawTypeIDs[1]); @@ -1000,11 +1048,47 @@ Decl *ModuleFile::resolveCrossReference(Module *M, uint32_t pathLen) { if (!isType) pathTrace.addType(filterTy); + bool retrying = false; + retry: + M->lookupQualified(ModuleType::get(M), name, NL_QualifiedDefault | NL_KnownNoDependency, /*typeResolver=*/nullptr, values); filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt, None, values); + + // HACK HACK HACK: Omit-needless-words hack to try to cope with + // the "NS" prefix being added/removed. No "real" compiler mode + // has to go through this path: a Swift 2 compiler will have the + // prefix, while a Swift 3 compiler will not have the + // prefix. However, one can set OmitNeedlessWords in a Swift 2 + // compiler to get API dumps and perform basic testing; this hack + // keeps that working. + if (values.empty() && !retrying && + getContext().LangOpts.OmitNeedlessWords && + (M->getName().str() == "ObjectiveC" || + M->getName().str() == "Foundation")) { + if (name.str().startswith("NS")) { + if (name.str().size() > 2 && name.str() != "NSCocoaError") { + auto known = getKnownFoundationEntity(name.str()); + if (!known || !nameConflictsWithStandardLibrary(*known)) { + // FIXME: lowercasing magic for non-types. + name = getContext().getIdentifier(name.str().substr(2)); + retrying = true; + goto retry; + } + } + } else { + SmallString<16> buffer; + buffer += "NS"; + buffer += name.str(); + // FIXME: Try uppercasing for non-types. + name = getContext().getIdentifier(buffer); + retrying = true; + goto retry; + } + } + break; } @@ -1436,6 +1520,8 @@ DeclContext *ModuleFile::getDeclContext(DeclContextID DCID) { declContextOrOffset = ED; } else if (auto AFD = dyn_cast(D)) { declContextOrOffset = AFD; + } else if (auto SD = dyn_cast(D)) { + declContextOrOffset = SD; } else { llvm_unreachable("Unknown Decl : DeclContext kind"); } @@ -1931,6 +2017,22 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { break; } + case decls_block::Swift3Migration_DECL_ATTR: { + bool isImplicit; + uint64_t renameLength; + uint64_t messageLength; + serialization::decls_block::Swift3MigrationDeclAttrLayout::readRecord( + scratch, isImplicit, renameLength, messageLength); + StringRef renameStr = blobData.substr(0, renameLength); + StringRef message = blobData.substr(renameLength, + renameLength + messageLength); + DeclName renamed = parseDeclName(getContext(), renameStr); + Attr = new (ctx) Swift3MigrationAttr(SourceLoc(), SourceLoc(), + SourceLoc(), renamed, + message, SourceLoc(), isImplicit); + break; + } + case decls_block::WarnUnusedResult_DECL_ATTR: { bool isImplicit; uint64_t endOfMessageIndex; @@ -2101,9 +2203,9 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { defaultDefinitionID); declOrOffset = assocType; + assocType->setArchetype(getType(archetypeID)->castTo()); assocType->computeType(); assocType->setAccessibility(cast(DC)->getFormalAccess()); - assocType->setArchetype(getType(archetypeID)->castTo()); if (isImplicit) assocType->setImplicit(); @@ -2229,10 +2331,12 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { return nullptr; } - Pattern *bodyParams0 = maybeReadPattern(); - Pattern *bodyParams1 = maybeReadPattern(); - assert(bodyParams0&&bodyParams1 && "missing body patterns for constructor"); - ctor->setBodyParams(bodyParams0, bodyParams1); + auto *bodyParams0 = readParameterList(); + bodyParams0->get(0)->setImplicit(); // self is implicit. + + auto *bodyParams1 = readParameterList(); + assert(bodyParams0 && bodyParams1 && "missing parameters for constructor"); + ctor->setParameterLists(bodyParams0->get(0), bodyParams1); // This must be set after recording the constructor in the map. // A polymorphic constructor type needs to refer to the constructor to get @@ -2374,7 +2478,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { if (declOrOffset.isComplete()) return declOrOffset; - auto param = createDecl(isLet, SourceLoc(), + auto param = createDecl(isLet, SourceLoc(), SourceLoc(), getIdentifier(argNameID), SourceLoc(), getIdentifier(paramNameID), type, DC); @@ -2489,16 +2593,15 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { fn->setInterfaceType(interfaceType); } - SmallVector patternBuf; - while (Pattern *pattern = maybeReadPattern()) - patternBuf.push_back(pattern); - - assert(!patternBuf.empty()); - assert((patternBuf.size() == numParamPatterns) && - "incorrect number of parameters"); + SmallVector paramLists; + for (unsigned i = 0, e = numParamPatterns; i != e; ++i) + paramLists.push_back(readParameterList()); - ArrayRef patterns(patternBuf); - fn->setDeserializedSignature(patterns, + // If the first parameter list is (self), mark it implicit. + if (numParamPatterns && DC->isTypeContext()) + paramLists[0]->get(0)->setImplicit(); + + fn->setDeserializedSignature(paramLists, TypeLoc::withoutLoc(signature->getResult())); if (auto errorConvention = maybeReadForeignErrorConvention()) @@ -2914,23 +3017,19 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { if (declOrOffset.isComplete()) return declOrOffset; - Pattern *indices = maybeReadPattern(); - assert(indices); - - auto elemTy = TypeLoc::withoutLoc(getType(elemTypeID)); - if (declOrOffset.isComplete()) - return declOrOffset; - // Resolve the name ids. SmallVector argNames; for (auto argNameID : argNameIDs) argNames.push_back(getIdentifier(argNameID)); DeclName name(ctx, ctx.Id_subscript, argNames); - auto subscript = createDecl(name, SourceLoc(), indices, - SourceLoc(), elemTy, DC); + auto subscript = createDecl(name, SourceLoc(), nullptr, + SourceLoc(), TypeLoc(), DC); declOrOffset = subscript; + subscript->setIndices(readParameterList()); + subscript->getElementTypeLoc() = TypeLoc::withoutLoc(getType(elemTypeID)); + configureStorage(subscript, rawStorageKind, getterID, setterID, materializeForSetID, addressorID, mutableAddressorID, willSetID, didSetID); @@ -3055,9 +3154,11 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext) { declOrOffset = dtor; dtor->setAccessibility(cast(DC)->getFormalAccess()); - Pattern *selfParams = maybeReadPattern(); + auto *selfParams = readParameterList(); + selfParams->get(0)->setImplicit(); // self is implicit. + assert(selfParams && "Didn't get self pattern?"); - dtor->setSelfPattern(selfParams); + dtor->setSelfDecl(selfParams->get(0)); dtor->setType(getType(signatureID)); dtor->setInterfaceType(getType(interfaceID)); @@ -3899,9 +4000,7 @@ Type ModuleFile::getType(TypeID TID) { return typeOrOffset; } -void ModuleFile::loadAllMembers(Decl *D, - uint64_t contextData, - bool *) { +void ModuleFile::loadAllMembers(Decl *D, uint64_t contextData) { PrettyStackTraceDecl trace("loading members for", D); BCOffsetRAII restoreOffset(DeclTypeCursor); @@ -3923,7 +4022,7 @@ void ModuleFile::loadAllMembers(Decl *D, void ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData, - SmallVectorImpl &conformances) { + SmallVectorImpl &conformances) { PrettyStackTraceDecl trace("loading conformances for", D); uint64_t numConformances; @@ -3934,8 +4033,11 @@ ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData, BCOffsetRAII restoreOffset(DeclTypeCursor); DeclTypeCursor.JumpToBit(bitPosition); - while (numConformances--) - conformances.push_back(readConformance(DeclTypeCursor)); + while (numConformances--) { + auto conf = readConformance(DeclTypeCursor); + if (conf.isConcrete()) + conformances.push_back(conf.getConcrete()); + } } TypeLoc @@ -3983,23 +4085,8 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, auto second = cast_or_null(getDecl(*rawIDIter++)); assert(second || first->getAttrs().hasAttribute() || first->getAttrs().isUnavailable(ctx)); - - unsigned substitutionCount = *rawIDIter++; - - SmallVector substitutions; - while (substitutionCount--) { - auto sub = maybeReadSubstitution(DeclTypeCursor); - assert(sub.hasValue()); - substitutions.push_back(sub.getValue()); - } - - ConcreteDeclRef witness; - if (substitutions.empty()) - witness = ConcreteDeclRef(second); - else - witness = ConcreteDeclRef(ctx, second, substitutions); - - witnesses.insert(std::make_pair(first, witness)); + (void) ctx; + witnesses.insert(std::make_pair(first, second)); } assert(rawIDIter <= rawIDs.end() && "read too much"); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 7435c52239a68..4a7cb617af933 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -38,6 +38,7 @@ fromStableStringEncoding(unsigned value) { switch (value) { case SIL_UTF8: return StringLiteralInst::Encoding::UTF8; case SIL_UTF16: return StringLiteralInst::Encoding::UTF16; + case SIL_OBJC_SELECTOR: return StringLiteralInst::Encoding::ObjCSelector; default: return None; } } @@ -187,41 +188,33 @@ SILDeserializer::readFuncTable(ArrayRef fields, StringRef blobData) { /// In serializer, we pre-assign a value ID in order, to each basic block /// argument and each SILInstruction that has a value. /// In deserializer, we use LocalValues to store the definitions and -/// ForwardMRVLocalValues for forward-referenced values (values that are +/// ForwardLocalValues for forward-referenced values (values that are /// used but not yet defined). LocalValues are updated in setLocalValue where /// the ID passed in assumes the same ordering as in serializer: in-order /// for each basic block argument and each SILInstruction that has a value. -/// We update ForwardMRVLocalValues in getLocalValue and when a value is defined -/// in setLocalValue, the corresponding entry in ForwardMRVLocalValues will be +/// We update ForwardLocalValues in getLocalValue and when a value is defined +/// in setLocalValue, the corresponding entry in ForwardLocalValues will be /// erased. void SILDeserializer::setLocalValue(ValueBase *Value, ValueID Id) { ValueBase *&Entry = LocalValues[Id]; assert(!Entry && "We should not redefine the same value."); - auto It = ForwardMRVLocalValues.find(Id); - if (It != ForwardMRVLocalValues.end()) { + auto It = ForwardLocalValues.find(Id); + if (It != ForwardLocalValues.end()) { // Take the information about the forward ref out of the map. - std::vector Entries = std::move(It->second); + ValueBase *Placeholder = It->second; // Remove the entries from the map. - ForwardMRVLocalValues.erase(It); - - assert(Entries.size() <= Value->getTypes().size() && - "Value Type mismatch?"); - // Validate that any forward-referenced elements have the right type, and - // RAUW them. - for (unsigned i = 0, e = Entries.size(); i != e; ++i) { - if (!Entries[i]) - continue; - Entries[i].replaceAllUsesWith(SILValue(Value, i)); - } + ForwardLocalValues.erase(It); + + Placeholder->replaceAllUsesWith(Value); } // Store it in our map. Entry = Value; } -SILValue SILDeserializer::getLocalValue(ValueID Id, unsigned ResultNum, +SILValue SILDeserializer::getLocalValue(ValueID Id, SILType Type) { if (Id == 0) return SILUndef::get(Type, &SILMod); @@ -230,22 +223,16 @@ SILValue SILDeserializer::getLocalValue(ValueID Id, unsigned ResultNum, ValueBase *Entry = LocalValues.lookup(Id); if (Entry) { // If this value was already defined, check it to make sure types match. - SILType EntryTy = Entry->getType(ResultNum); - assert(EntryTy == Type && "Value Type mismatch?"); - (void)EntryTy; - return SILValue(Entry, ResultNum); + assert(Entry->getType() == Type && "Value Type mismatch?"); + return Entry; } // Otherwise, this is a forward reference. Create a dummy node to represent // it until we see a real definition. - std::vector &Placeholders = ForwardMRVLocalValues[Id]; - if (Placeholders.size() <= ResultNum) - Placeholders.resize(ResultNum+1); - - if (!Placeholders[ResultNum]) - Placeholders[ResultNum] = - new (SILMod) GlobalAddrInst(nullptr, Type); - return Placeholders[ResultNum]; + ValueBase *&Placeholder = ForwardLocalValues[Id]; + if (!Placeholder) + Placeholder = new (SILMod) GlobalAddrInst(nullptr, Type); + return Placeholder; } /// Return the SILBasicBlock of a given ID. @@ -335,7 +322,7 @@ SILFunction *SILDeserializer::getFuncForReference(StringRef name) { } /// Helper function to find a SILGlobalVariable given its name. It first checks -/// in the module. If we can not find it in the module, we attempt to +/// in the module. If we cannot find it in the module, we attempt to /// deserialize it. SILGlobalVariable *SILDeserializer::getGlobalForReference(StringRef name) { // Check to see if we have a global by this name already. @@ -383,12 +370,11 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID, TypeID funcTyID; unsigned rawLinkage, isTransparent, isFragile, isThunk, isGlobal, inlineStrategy, effect; - IdentifierID SemanticsID; + ArrayRef SemanticsIDs; // TODO: read fragile - SILFunctionLayout::readRecord(scratch, rawLinkage, - isTransparent, isFragile, isThunk, isGlobal, - inlineStrategy, effect, funcTyID, - SemanticsID); + SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isFragile, + isThunk, isGlobal, inlineStrategy, effect, + funcTyID, SemanticsIDs); if (funcTyID == 0) { DEBUG(llvm::dbgs() << "SILFunction typeID is 0.\n"); @@ -441,8 +427,9 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID, SILFunction::NotRelevant, (Inline_t)inlineStrategy); fn->setGlobalInit(isGlobal == 1); fn->setEffectsKind((EffectsKind)effect); - if (SemanticsID) - fn->setSemanticsAttr(MF->getIdentifier(SemanticsID).str()); + for (auto ID : SemanticsIDs) { + fn->addSemanticsAttr(MF->getIdentifier(ID).str()); + } if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), fn); } @@ -521,7 +508,7 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID, UndefinedBlocks.clear(); LastValueID = 0; LocalValues.clear(); - ForwardMRVLocalValues.clear(); + ForwardLocalValues.clear(); // Another SIL_FUNCTION record means the end of this SILFunction. // SIL_VTABLE or SIL_GLOBALVAR or SIL_WITNESSTABLE record also means the end @@ -629,12 +616,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILBuilder Builder(BB); Builder.setCurrentDebugScope(Fn->getDebugScope()); unsigned OpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0, - ValResNum = 0, ValResNum2 = 0, Attr = 0, - NumSubs = 0, NumConformances = 0, IsNonThrowingApply = 0; + Attr = 0, NumSubs = 0, NumConformances = 0, IsNonThrowingApply = 0; ValueID ValID, ValID2, ValID3; TypeID TyID, TyID2, TyID3; TypeID ConcreteTyID; - DeclID ProtoID; ModuleID OwningModuleID; SourceLoc SLoc; ArrayRef ListOfValues; @@ -645,27 +630,27 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, llvm_unreachable("Record kind for a SIL instruction is not supported."); case SIL_ONE_VALUE_ONE_OPERAND: SILOneValueOneOperandLayout::readRecord(scratch, OpCode, Attr, - ValID, ValResNum, TyID, TyCategory, - ValID2, ValResNum2); + ValID, TyID, TyCategory, + ValID2); break; case SIL_ONE_TYPE: SILOneTypeLayout::readRecord(scratch, OpCode, TyID, TyCategory); break; case SIL_ONE_OPERAND: SILOneOperandLayout::readRecord(scratch, OpCode, Attr, - TyID, TyCategory, ValID, ValResNum); + TyID, TyCategory, ValID); break; case SIL_ONE_TYPE_ONE_OPERAND: SILOneTypeOneOperandLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, TyID2, TyCategory2, - ValID, ValResNum); + ValID); break; case SIL_INIT_EXISTENTIAL: SILInitExistentialLayout::readRecord(scratch, OpCode, TyID, TyCategory, TyID2, TyCategory2, - ValID, ValResNum, + ValID, ConcreteTyID, NumConformances); break; @@ -673,7 +658,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILInstCastLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, TyID2, TyCategory2, - ValID, ValResNum); + ValID); break; case SIL_ONE_TYPE_VALUES: SILOneTypeValuesLayout::readRecord(scratch, OpCode, TyID, TyCategory, @@ -681,13 +666,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, break; case SIL_TWO_OPERANDS: SILTwoOperandsLayout::readRecord(scratch, OpCode, Attr, - TyID, TyCategory, ValID, ValResNum, - TyID2, TyCategory2, ValID2, ValResNum2); + TyID, TyCategory, ValID, + TyID2, TyCategory2, ValID2); break; case SIL_INST_APPLY: { unsigned IsPartial; SILInstApplyLayout::readRecord(scratch, IsPartial, NumSubs, - TyID, TyID2, ValID, ValResNum, ListOfValues); + TyID, TyID2, ValID, ListOfValues); switch (IsPartial) { case SIL_APPLY: OpCode = (unsigned)ValueKind::ApplyInst; @@ -744,7 +729,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, "Layout should be OneTypeOneOperand."); \ ResultVal = Builder.create##ID(Loc, \ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), \ - getLocalValue(ValID, ValResNum, \ + getLocalValue(ValID, \ getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2))); \ break; @@ -754,6 +739,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, ONETYPE_ONEOPERAND_INST(AllocValueBuffer) ONETYPE_ONEOPERAND_INST(ProjectValueBuffer) ONETYPE_ONEOPERAND_INST(ProjectBox) + ONETYPE_ONEOPERAND_INST(ProjectExistentialBox) ONETYPE_ONEOPERAND_INST(DeallocValueBuffer) #undef ONETYPE_ONEOPERAND_INST #define ONEOPERAND_ONETYPE_INST(ID) \ @@ -761,7 +747,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ ResultVal = Builder.create##ID(Loc, \ - getLocalValue(ValID, ValResNum, \ + getLocalValue(ValID, \ getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2)), \ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));\ @@ -802,7 +788,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, "Layout should be OneTypeOneOperand."); ResultVal = Builder.createDeallocExistentialBox(Loc, MF->getType(TyID)->getCanonicalType(), - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2))); break; @@ -811,9 +797,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::RefToBridgeObjectInst: { auto RefTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); - auto Ref = getLocalValue(ValID, ValResNum, RefTy); + auto Ref = getLocalValue(ValID, RefTy); auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2); - auto Bits = getLocalValue(ValID2, ValResNum2, BitsTy); + auto Bits = getLocalValue(ValID2, BitsTy); ResultVal = Builder.createRefToBridgeObject(Loc, Ref, Bits); break; @@ -838,10 +824,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, ConcreteTy = MF->getType(ConcreteTyID)->getCanonicalType(); SILValue operand; if ((ValueKind) OpCode != ValueKind::AllocExistentialBoxInst) - operand = getLocalValue(ValID, ValResNum, + operand = getLocalValue(ValID, getSILType(Ty2, (SILValueCategory)TyCategory2)); - SmallVector conformances; + SmallVector conformances; while (NumConformances--) { auto conformance = MF->readConformance(SILCursor); conformances.push_back(conformance); @@ -869,7 +855,6 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, break; case ValueKind::AllocExistentialBoxInst: ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, - SILType::getPrimitiveAddressType(ConcreteTy), ctxConformances); break; } @@ -892,7 +877,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, bool isObjC = Attr & 0x01; ResultVal = Builder.createAllocRefDynamic( Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)), getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), @@ -910,12 +895,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILFunctionType *FTI = SubstFnTy.castTo(); auto ArgTys = FTI->getParameterSILTypes(); - assert((ArgTys.size() << 1) == ListOfValues.size() && + assert(ArgTys.size() == ListOfValues.size() && "Argument number mismatch in ApplyInst."); SmallVector Args; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 2) - Args.push_back(getLocalValue(ListOfValues[I], ListOfValues[I+1], - ArgTys[I>>1])); + for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) + Args.push_back(getLocalValue(ListOfValues[I], ArgTys[I])); unsigned NumSub = NumSubs; SmallVector Substitutions; @@ -925,7 +909,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, Substitutions.push_back(*sub); } - ResultVal = Builder.createApply(Loc, getLocalValue(ValID, ValResNum, FnTy), + ResultVal = Builder.createApply(Loc, getLocalValue(ValID, FnTy), SubstFnTy, FTI->getResult().getSILType(), Substitutions, Args, IsNonThrowingApply != 0); @@ -948,12 +932,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILFunctionType *FTI = SubstFnTy.castTo(); auto ArgTys = FTI->getParameterSILTypes(); - assert((ArgTys.size() << 1) == ListOfValues.size() && + assert(ArgTys.size() == ListOfValues.size() && "Argument number mismatch in ApplyInst."); SmallVector Args; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 2) - Args.push_back(getLocalValue(ListOfValues[I], ListOfValues[I+1], - ArgTys[I>>1])); + for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) + Args.push_back(getLocalValue(ListOfValues[I], ArgTys[I])); unsigned NumSub = NumSubs; SmallVector Substitutions; @@ -964,7 +947,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } ResultVal = Builder.createTryApply(Loc, - getLocalValue(ValID, ValResNum, FnTy), + getLocalValue(ValID, FnTy), SubstFnTy, Substitutions, Args, normalBB, errorBB); break; @@ -977,15 +960,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILFunctionType *FTI = SubstFnTy.castTo(); auto ArgTys = FTI->getParameterSILTypes(); - assert((ArgTys.size() << 1) >= ListOfValues.size() && + assert(ArgTys.size() >= ListOfValues.size() && "Argument number mismatch in PartialApplyInst."); - SILValue FnVal = getLocalValue(ValID, ValResNum, FnTy); + SILValue FnVal = getLocalValue(ValID, FnTy); SmallVector Args; - unsigned unappliedArgs = ArgTys.size() - (ListOfValues.size() >> 1); - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 2) - Args.push_back(getLocalValue(ListOfValues[I], ListOfValues[I+1], - ArgTys[(I>>1) + unappliedArgs])); + unsigned unappliedArgs = ArgTys.size() - ListOfValues.size(); + for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) + Args.push_back(getLocalValue(ListOfValues[I], ArgTys[I + unappliedArgs])); // Compute the result type of the partial_apply, based on which arguments // are getting applied. @@ -1013,11 +995,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto ASTTy = MF->getType(TyID); auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2); SmallVector Args; - for (unsigned i = 0, e = ListOfValues.size(); i < e; i += 4) { - auto ArgASTTy = MF->getType(ListOfValues[i+2]); + for (unsigned i = 0, e = ListOfValues.size(); i < e; i += 3) { + auto ArgASTTy = MF->getType(ListOfValues[i+1]); auto ArgTy = getSILType(ArgASTTy, - (SILValueCategory)(unsigned)ListOfValues[i+3]); - Args.push_back(getLocalValue(ListOfValues[i], ListOfValues[i+1], ArgTy)); + (SILValueCategory)(unsigned)ListOfValues[i+2]); + Args.push_back(getLocalValue(ListOfValues[i], ArgTy)); } unsigned NumSub = NumSubs; SmallVector Substitutions; @@ -1032,6 +1014,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, Args); break; } + case ValueKind::AllocGlobalInst: { + // Format: Name and type. Use SILOneOperandLayout. + Identifier Name = MF->getIdentifier(ValID); + + // Find the global variable. + SILGlobalVariable *g = getGlobalForReference(Name.str()); + assert(g && "Can't deserialize global variable"); + + ResultVal = Builder.createAllocGlobal(Loc, g); + break; + } case ValueKind::GlobalAddrInst: { // Format: Name and type. Use SILOneOperandLayout. auto Ty = MF->getType(TyID); @@ -1051,7 +1044,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::DeallocStackInst: { auto Ty = MF->getType(TyID); ResultVal = Builder.createDeallocStack(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory))); break; } @@ -1059,7 +1052,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); bool OnStack = (bool)Attr; ResultVal = Builder.createDeallocRef(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), OnStack); break; } @@ -1067,9 +1060,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createDeallocPartialRef(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), - getLocalValue(ValID2, ValResNum2, + getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } @@ -1085,9 +1078,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createMarkDependence(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), - getLocalValue(ValID2, ValResNum2, + getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } @@ -1095,9 +1088,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createIndexAddr(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), - getLocalValue(ValID2, ValResNum2, + getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } @@ -1105,9 +1098,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createIndexRawPointer(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), - getLocalValue(ValID2, ValResNum2, + getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } @@ -1150,10 +1143,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Format: a list of typed values. A typed value is expressed by 4 IDs: // TypeID, TypeCategory, ValueID, ValueResultNumber. SmallVector OpList; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 4) { + for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); OpList.push_back( - getLocalValue(ListOfValues[I+2], ListOfValues[I+3], + getLocalValue(ListOfValues[I+2], getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); } ResultVal = Builder.createMarkFunctionEscape(Loc, OpList); @@ -1161,7 +1154,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } // Checked Conversion instructions. case ValueKind::UnconditionalCheckedCastInst: { - SILValue Val = getLocalValue(ValID, ValResNum, + SILValue Val = getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); ResultVal = Builder.createUnconditionalCheckedCast(Loc, Val, Ty); @@ -1172,7 +1165,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && \ "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID(Loc, getLocalValue(ValID, ValResNum, \ + ResultVal = Builder.create##ID(Loc, getLocalValue(ValID, \ getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory))); \ break; @@ -1205,7 +1198,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); bool isTake = (Attr > 0); ResultVal = Builder.createLoadUnowned(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), IsTake_t(isTake)); break; @@ -1214,7 +1207,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); bool isTake = (Attr > 0); ResultVal = Builder.createLoadWeak(Loc, - getLocalValue(ValID, ValResNum, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), IsTake_t(isTake)); break; @@ -1222,7 +1215,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::MarkUninitializedInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto Kind = (MarkUninitializedInst::Kind)Attr; - auto Val = getLocalValue(ValID, ValResNum, Ty); + auto Val = getLocalValue(ValID, Ty); ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind); break; } @@ -1231,8 +1224,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); SILType ValType = addrType.getObjectType(); ResultVal = Builder.createStore(Loc, - getLocalValue(ValID, ValResNum, ValType), - getLocalValue(ValID2, ValResNum2, addrType)); + getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType)); break; } case ValueKind::StoreUnownedInst: { @@ -1242,8 +1235,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); bool isInit = (Attr > 0); ResultVal = Builder.createStoreUnowned(Loc, - getLocalValue(ValID, ValResNum, ValType), - getLocalValue(ValID2, ValResNum2, addrType), + getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType), IsInitialization_t(isInit)); break; } @@ -1254,8 +1247,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); bool isInit = (Attr > 0); ResultVal = Builder.createStoreWeak(Loc, - getLocalValue(ValID, ValResNum, ValType), - getLocalValue(ValID2, ValResNum2, addrType), + getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType), IsInitialization_t(isInit)); break; } @@ -1265,8 +1258,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, bool isInit = (Attr & 0x2) > 0; bool isTake = (Attr & 0x1) > 0; ResultVal = Builder.createCopyAddr(Loc, - getLocalValue(ValID, ValResNum, addrType), - getLocalValue(ValID2, ValResNum2, addrType), + getLocalValue(ValID, addrType), + getLocalValue(ValID2, addrType), IsTake_t(isTake), IsInitialization_t(isInit)); break; @@ -1276,8 +1269,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); SILType ValType = addrType.getObjectType(); ResultVal = Builder.createAssign(Loc, - getLocalValue(ValID, ValResNum, ValType), - getLocalValue(ValID2, ValResNum2, addrType)); + getLocalValue(ValID, ValType), + getLocalValue(ValID2, addrType)); break; } case ValueKind::StructElementAddrInst: @@ -1285,9 +1278,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Use SILOneValueOneOperandLayout. VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - auto Val = getLocalValue(ValID2, ValResNum2, + auto Val = getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)); - auto ResultTy = Val.getType().getFieldType(Field, SILMod); + auto ResultTy = Val->getType().getFieldType(Field, SILMod); if ((ValueKind)OpCode == ValueKind::StructElementAddrInst) ResultVal = Builder.createStructElementAddr(Loc, Val, Field, ResultTy.getAddressType()); @@ -1301,10 +1294,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber. auto Ty = MF->getType(TyID); SmallVector OpList; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 4) { + for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); OpList.push_back( - getLocalValue(ListOfValues[I+2], ListOfValues[I+3], + getLocalValue(ListOfValues[I+2], getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); } ResultVal = Builder.createStruct(Loc, @@ -1324,12 +1317,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::TupleElementAddrInst: ResultVal = Builder.createTupleElementAddr(Loc, - getLocalValue(ValID, ValResNum, ST), + getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Address)); break; case ValueKind::TupleExtractInst: ResultVal = Builder.createTupleExtract(Loc, - getLocalValue(ValID, ValResNum,ST), + getLocalValue(ValID,ST), TyID, getSILType(ResultTy, SILValueCategory::Object)); break; @@ -1343,10 +1336,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, TupleType *TT = Ty->getAs(); assert(TT && "Type of a TupleInst should be TupleType"); SmallVector OpList; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 2) { - Type EltTy = TT->getElement(I >> 1).getType(); + for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) { + Type EltTy = TT->getElement(I).getType(); OpList.push_back( - getLocalValue(ListOfValues[I], ListOfValues[I+1], + getLocalValue(ListOfValues[I], getSILType(EltTy, SILValueCategory::Object))); } ResultVal = Builder.createTuple(Loc, @@ -1356,9 +1349,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case ValueKind::BranchInst: { SmallVector Args; - for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 4) + for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) Args.push_back( - getLocalValue(ListOfValues[I+2], ListOfValues[I+3], + getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); @@ -1372,30 +1365,30 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list has value for condition, true basic block ID, // false basic block ID, number of true arguments, and a list of true|false // arguments. - SILValue Cond = getLocalValue(ListOfValues[0], ListOfValues[1], + SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); - unsigned NumTrueArgs = ListOfValues[4]; - unsigned StartOfTrueArg = 5; - unsigned StartOfFalseArg = StartOfTrueArg + 4*NumTrueArgs; + unsigned NumTrueArgs = ListOfValues[3]; + unsigned StartOfTrueArg = 4; + unsigned StartOfFalseArg = StartOfTrueArg + 3*NumTrueArgs; SmallVector TrueArgs; - for (unsigned I = StartOfTrueArg, E = StartOfFalseArg; I < E; I += 4) + for (unsigned I = StartOfTrueArg, E = StartOfFalseArg; I < E; I += 3) TrueArgs.push_back( - getLocalValue(ListOfValues[I+2], ListOfValues[I+3], + getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); SmallVector FalseArgs; - for (unsigned I = StartOfFalseArg, E = ListOfValues.size(); I < E; I += 4) + for (unsigned I = StartOfFalseArg, E = ListOfValues.size(); I < E; I += 3) FalseArgs.push_back( - getLocalValue(ListOfValues[I+2], ListOfValues[I+3], + getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); ResultVal = Builder.createCondBranch(Loc, Cond, - getBBForReference(Fn, ListOfValues[2]), TrueArgs, - getBBForReference(Fn, ListOfValues[3]), FalseArgs); + getBBForReference(Fn, ListOfValues[1]), TrueArgs, + getBBForReference(Fn, ListOfValues[2]), FalseArgs); break; } case ValueKind::SwitchEnumInst: @@ -1404,16 +1397,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // default basic block ID. Use SILOneTypeValuesLayout: the type is // for condition, the list has value for condition, hasDefault, default // basic block ID, a list of (DeclID, BasicBlock ID). - SILValue Cond = getLocalValue(ListOfValues[0], ListOfValues[1], + SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); SILBasicBlock *DefaultBB = nullptr; - if (ListOfValues[2]) - DefaultBB = getBBForReference(Fn, ListOfValues[3]); + if (ListOfValues[1]) + DefaultBB = getBBForReference(Fn, ListOfValues[2]); SmallVector, 4> CaseBBs; - for (unsigned I = 4, E = ListOfValues.size(); I < E; I += 2) { + for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) { CaseBBs.push_back( {cast(MF->getDecl(ListOfValues[I])), getBBForReference(Fn, ListOfValues[I+1])} ); } @@ -1431,23 +1424,21 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list has value for condition, result type, // hasDefault, default // basic block ID, a list of (DeclID, BasicBlock ID). - SILValue Cond = getLocalValue(ListOfValues[0], ListOfValues[1], + SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); - Type ResultLoweredTy = MF->getType(ListOfValues[2]); - SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[3]; + Type ResultLoweredTy = MF->getType(ListOfValues[1]); + SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); SILValue DefaultVal = nullptr; - if (ListOfValues[4]) - DefaultVal = getLocalValue(ListOfValues[5], ListOfValues[6], - ResultTy); + if (ListOfValues[3]) + DefaultVal = getLocalValue(ListOfValues[4], ResultTy); SmallVector, 4> CaseVals; - for (unsigned I = 7, E = ListOfValues.size(); I < E; I += 3) { - auto Value = getLocalValue(ListOfValues[I+1], ListOfValues[I+2], - ResultTy); + for (unsigned I = 5, E = ListOfValues.size(); I < E; I += 2) { + auto Value = getLocalValue(ListOfValues[I+1], ResultTy); CaseVals.push_back({cast(MF->getDecl(ListOfValues[I])), Value}); } @@ -1466,19 +1457,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // basic block ID, a list of (Value ID, BasicBlock ID). SILType ResultTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); - SILValue Cond = getLocalValue(ListOfValues[0], ListOfValues[1], - getSILType(MF->getType(TyID), + SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); SILBasicBlock *DefaultBB = nullptr; - if (ListOfValues[2]) - DefaultBB = getBBForReference(Fn, ListOfValues[3]); + if (ListOfValues[1]) + DefaultBB = getBBForReference(Fn, ListOfValues[2]); SmallVector, 4> CaseBBs; - for (unsigned I = 4, E = ListOfValues.size(); I < E; I += 3) { - auto value = getLocalValue(ListOfValues[I], ListOfValues[I+1], - ResultTy); - CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+2])} ); + for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) { + auto value = getLocalValue(ListOfValues[I], ResultTy); + CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+1])} ); } ResultVal = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); break; @@ -1489,25 +1478,21 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list has value for condition, result type, // hasDefault, default, // basic block ID, a list of (Value ID, Value ID). - SILValue Cond = getLocalValue(ListOfValues[0], ListOfValues[1], - getSILType(MF->getType(TyID), + SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); - Type ResultLoweredTy = MF->getType(ListOfValues[2]); - SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[3]; + Type ResultLoweredTy = MF->getType(ListOfValues[1]); + SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); SILValue DefaultVal = nullptr; - if (ListOfValues[4]) - DefaultVal = getLocalValue(ListOfValues[5], ListOfValues[6], - ResultTy); + if (ListOfValues[3]) + DefaultVal = getLocalValue(ListOfValues[4], ResultTy); SmallVector, 4> CaseValuesAndResults; - for (unsigned I = 7, E = ListOfValues.size(); I < E; I += 4) { - auto CaseValue = getLocalValue(ListOfValues[I], ListOfValues[I+1], - Cond.getType()); - auto Result = getLocalValue(ListOfValues[I+2], ListOfValues[I+3], - ResultTy); + for (unsigned I = 5, E = ListOfValues.size(); I < E; I += 2) { + auto CaseValue = getLocalValue(ListOfValues[I], Cond->getType()); + auto Result = getLocalValue(ListOfValues[I+1], ResultTy); CaseValuesAndResults.push_back({CaseValue, Result}); } @@ -1519,8 +1504,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type, // (DeclID + hasOperand), and an operand. SILValue Operand; - if (ValResNum) - Operand = getLocalValue(ValID2, ValResNum2, + if (Attr) + Operand = getLocalValue(ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); ResultVal = Builder.createEnum(Loc, Operand, @@ -1536,7 +1521,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createInitEnumDataAddr(Loc, - getLocalValue(ValID2, ValResNum2, OperandTy), + getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } @@ -1547,7 +1532,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createUncheckedEnumData(Loc, - getLocalValue(ValID2, ValResNum2, OperandTy), + getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } @@ -1558,7 +1543,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createUncheckedTakeEnumDataAddr(Loc, - getLocalValue(ValID2, ValResNum2, OperandTy), + getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } @@ -1567,7 +1552,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, EnumElementDecl *Elt = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); ResultVal = Builder.createInjectEnumAddr(Loc, - getLocalValue(ValID2, ValResNum2, + getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)), Elt); break; @@ -1576,9 +1561,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Use SILOneValueOneOperandLayout. VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - auto Val = getLocalValue(ValID2, ValResNum2, + auto Val = getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)); - auto ResultTy = Val.getType().getFieldType(Field, SILMod); + auto ResultTy = Val->getType().getFieldType(Field, SILMod); ResultVal = Builder.createRefElementAddr(Loc, Val, Field, ResultTy); break; @@ -1603,20 +1588,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::ClassMethodInst: ResultVal = Builder.createClassMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], - ListOfValues[NextValueIndex+1], operandTy), + getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; case ValueKind::SuperMethodInst: ResultVal = Builder.createSuperMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], - ListOfValues[NextValueIndex+1], operandTy), + getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; case ValueKind::DynamicMethodInst: ResultVal = Builder.createDynamicMethod(Loc, - getLocalValue(ListOfValues[NextValueIndex], - ListOfValues[NextValueIndex+1], operandTy), + getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; } @@ -1632,14 +1614,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILType OperandTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2); - auto *Conformance = MF->readConformance(SILCursor); + auto Conformance = MF->readConformance(SILCursor); // Read the optional opened existential. SILValue ExistentialOperand; if (TyID3) { SILType ExistentialOperandTy = getSILType(MF->getType(TyID3), (SILValueCategory)TyCategory3); if (ValID3) - ExistentialOperand = getLocalValue(ValID3, 0, ExistentialOperandTy); + ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy); } ResultVal = Builder.createWitnessMethod( Loc, Ty, Conformance, DRef, OperandTy, ExistentialOperand, Attr); @@ -1648,13 +1630,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::DynamicMethodBranchInst: { // Format: a typed value, a SILDeclRef, a BasicBlock ID for method, // a BasicBlock ID for no method. Use SILOneTypeValuesLayout. - unsigned NextValueIndex = 2; + unsigned NextValueIndex = 1; SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() == NextValueIndex + 2 && "Wrong number of entries for DynamicMethodBranchInst"); ResultVal = Builder.createDynamicMethodBranch(Loc, - getLocalValue(ListOfValues[0], ListOfValues[1], - getSILType(MF->getType(TyID), + getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)), DRef, getBBForReference(Fn, ListOfValues[NextValueIndex]), getBBForReference(Fn, ListOfValues[NextValueIndex+1])); @@ -1663,16 +1644,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case ValueKind::CheckedCastBranchInst: { // Format: the cast kind, a typed value, a BasicBlock ID for success, // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout. - assert(ListOfValues.size() == 7 && + assert(ListOfValues.size() == 6 && "expect 7 numbers for CheckedCastBranchInst"); bool isExact = ListOfValues[0] != 0; - SILType opTy = getSILType(MF->getType(ListOfValues[3]), - (SILValueCategory)ListOfValues[4]); - SILValue op = getLocalValue(ListOfValues[1], ListOfValues[2], opTy); + SILType opTy = getSILType(MF->getType(ListOfValues[2]), + (SILValueCategory)ListOfValues[3]); + SILValue op = getLocalValue(ListOfValues[1], opTy); SILType castTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); - auto *successBB = getBBForReference(Fn, ListOfValues[5]); - auto *failureBB = getBBForReference(Fn, ListOfValues[6]); + auto *successBB = getBBForReference(Fn, ListOfValues[4]); + auto *failureBB = getBBForReference(Fn, ListOfValues[5]); ResultVal = Builder.createCheckedCastBranch(Loc, isExact, op, castTy, successBB, failureBB); @@ -1683,14 +1664,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, CastConsumptionKind consumption = getCastConsumptionKind(ListOfValues[0]); CanType sourceType = MF->getType(ListOfValues[1])->getCanonicalType(); - SILType srcAddrTy = getSILType(MF->getType(ListOfValues[4]), - (SILValueCategory)ListOfValues[5]); - SILValue src = getLocalValue(ListOfValues[2], ListOfValues[3], srcAddrTy); + SILType srcAddrTy = getSILType(MF->getType(ListOfValues[3]), + (SILValueCategory)ListOfValues[4]); + SILValue src = getLocalValue(ListOfValues[2], srcAddrTy); - CanType targetType = MF->getType(ListOfValues[6])->getCanonicalType(); + CanType targetType = MF->getType(ListOfValues[5])->getCanonicalType(); SILType destAddrTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); - SILValue dest = getLocalValue(ListOfValues[7], ListOfValues[8], destAddrTy); + SILValue dest = getLocalValue(ListOfValues[6], destAddrTy); if (OpCode == (unsigned) ValueKind::UnconditionalCheckedCastAddrInst) { ResultVal = Builder.createUnconditionalCheckedCastAddr(Loc, consumption, @@ -1699,8 +1680,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, break; } - auto *successBB = getBBForReference(Fn, ListOfValues[9]); - auto *failureBB = getBBForReference(Fn, ListOfValues[10]); + auto *successBB = getBBForReference(Fn, ListOfValues[7]); + auto *failureBB = getBBForReference(Fn, ListOfValues[8]); ResultVal = Builder.createCheckedCastAddrBranch(Loc, consumption, src, sourceType, dest, targetType, @@ -1709,34 +1690,34 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case ValueKind::UncheckedRefCastAddrInst: { CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType(); - SILType srcAddrTy = getSILType(MF->getType(ListOfValues[3]), - (SILValueCategory)ListOfValues[4]); - SILValue src = getLocalValue(ListOfValues[1], ListOfValues[2], srcAddrTy); + SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]), + (SILValueCategory)ListOfValues[3]); + SILValue src = getLocalValue(ListOfValues[1], srcAddrTy); - CanType targetType = MF->getType(ListOfValues[5])->getCanonicalType(); + CanType targetType = MF->getType(ListOfValues[4])->getCanonicalType(); SILType destAddrTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); - SILValue dest = getLocalValue(ListOfValues[6], ListOfValues[7], destAddrTy); + SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); ResultVal = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, dest, targetType); break; } case ValueKind::InitBlockStorageHeaderInst: { - assert(ListOfValues.size() == 6 && + assert(ListOfValues.size() == 4 && "expected 6 values for InitBlockStorageHeader"); SILType blockTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); - SILType storageTy = getSILType(MF->getType(ListOfValues[2]), + SILType storageTy = getSILType(MF->getType(ListOfValues[1]), SILValueCategory::Address); SILValue storage - = getLocalValue(ListOfValues[0], ListOfValues[1], storageTy); + = getLocalValue(ListOfValues[0], storageTy); - SILType invokeTy = getSILType(MF->getType(ListOfValues[5]), + SILType invokeTy = getSILType(MF->getType(ListOfValues[3]), SILValueCategory::Object); SILValue invoke - = getLocalValue(ListOfValues[3], ListOfValues[4], invokeTy); + = getLocalValue(ListOfValues[2], invokeTy); ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke, blockTy); @@ -2004,7 +1985,7 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, // Deserialize Conformance. auto theConformance = cast( - MF->readConformance(SILCursor)); + MF->readConformance(SILCursor).getConcrete()); if (!existingWt) existingWt = SILMod.lookUpWitnessTable(theConformance, false).first; @@ -2055,7 +2036,7 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, ProtocolDecl *proto = cast(MF->getDecl(protoId)); auto conformance = MF->readConformance(SILCursor); witnessEntries.push_back(SILWitnessTable::BaseProtocolWitness{ - proto, conformance + proto, conformance.getConcrete() }); } else if (kind == SIL_WITNESS_ASSOC_PROTOCOL) { DeclID assocId, protoId; @@ -2063,7 +2044,8 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, ProtocolDecl *proto = cast(MF->getDecl(protoId)); auto conformance = MF->readConformance(SILCursor); witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{ - cast(MF->getDecl(assocId)), proto, conformance + cast(MF->getDecl(assocId)), proto, + conformance }); } else if (kind == SIL_WITNESS_ASSOC_ENTRY) { DeclID assocId; @@ -2117,8 +2099,8 @@ void SILDeserializer::getAllWitnessTables() { SILWitnessTable * SILDeserializer::lookupWitnessTable(SILWitnessTable *existingWt) { - assert(existingWt && "Can not deserialize a null witness table declaration."); - assert(existingWt->isDeclaration() && "Can not deserialize a witness table " + assert(existingWt && "Cannot deserialize a null witness table declaration."); + assert(existingWt->isDeclaration() && "Cannot deserialize a witness table " "definition."); // If we don't have a witness table list, we can't look anything up. diff --git a/lib/Serialization/DeserializeSIL.h b/lib/Serialization/DeserializeSIL.h index 3f3bbcd9c55f3..9d08235c48ab6 100644 --- a/lib/Serialization/DeserializeSIL.h +++ b/lib/Serialization/DeserializeSIL.h @@ -1,8 +1,8 @@ -//===--- DeserializeSIL.h - Read SIL ---------------------------*- C++ -*--===// +//===--- DeserializeSIL.h - Read SIL ----------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -55,7 +55,7 @@ namespace swift { /// Data structures used to perform name lookup for local values. llvm::DenseMap LocalValues; - llvm::DenseMap> ForwardMRVLocalValues; + llvm::DenseMap ForwardLocalValues; serialization::ValueID LastValueID = 0; /// Data structures used to perform lookup of basic blocks. @@ -89,7 +89,7 @@ namespace swift { /// register it and update our symbol table. void setLocalValue(ValueBase *Value, serialization::ValueID Id); /// Get a reference to a local value with the specified ID and type. - SILValue getLocalValue(serialization::ValueID Id, unsigned ResultNum, + SILValue getLocalValue(serialization::ValueID Id, SILType Type); SILFunction *getFuncForReference(StringRef Name, SILType Ty); diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index eb21211fdb8af..c6938f08f163d 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -1,8 +1,8 @@ -//===--- ModuleFile.cpp - Loading a serialized module -----------*- C++ -*-===// +//===--- ModuleFile.cpp - Loading a serialized module ---------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -109,6 +109,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, case options_block::IS_TESTABLE: extendedInfo.setIsTestable(true); break; + case options_block::IS_RESILIENT: + extendedInfo.setIsResilient(true); + break; default: // Unknown options record, possibly for use by a future version of the // module format. @@ -1220,7 +1223,7 @@ void ModuleFile::getImportDecls(SmallVectorImpl &Results) { if (!M) { // The dependency module could not be loaded. Just make a guess - // about the import kind, we can not do better. + // about the import kind, we cannot do better. Kind = ImportKind::Func; } else { SmallVector Decls; @@ -1405,6 +1408,25 @@ void ModuleFile::lookupClassMembers(Module::AccessPathTy accessPath, } } +void ModuleFile::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) { + // If we don't have an Objective-C method table, there's nothing to do. + if (!ObjCMethods) return; + + // Look for all methods in the module file with this selector. + auto known = ObjCMethods->find(selector); + if (known == ObjCMethods->end()) return; + + auto found = *known; + for (const auto &result : found) { + // Deserialize the method and add it to the list. + if (auto func = dyn_cast_or_null( + getDecl(std::get<2>(result)))) + results.push_back(func); + } +} + void ModuleFile::collectLinkLibraries(Module::LinkLibraryCallback callback) const { for (auto &lib : LinkLibraries) @@ -1466,7 +1488,7 @@ Optional ModuleFile::getCommentForDecl(const Decl *D) { // Keep these as assertions instead of early exits to ensure that we are not // doing extra work. These cases should be handled by clients of this API. assert(!D->hasClangNode() && - "can not find comments for Clang decls in Swift modules"); + "cannot find comments for Clang decls in Swift modules"); assert(D->getDeclContext()->getModuleScopeContext() == FileContext && "Decl is from a different serialized file"); diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index 4a7181a692a6a..8ffab260a15f3 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -1,8 +1,8 @@ -//===--- SILFormat.h - The internals of serialized SILs --------*- C++ -*-===// +//===--- SILFormat.h - The internals of serialized SILs ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -28,11 +28,11 @@ using ValueIDField = DeclIDField; using SILInstOpCodeField = BCFixed<8>; using SILTypeCategoryField = BCFixed<2>; -using SILValueResultField = BCFixed<8>; enum SILStringEncoding : uint8_t { SIL_UTF8, - SIL_UTF16 + SIL_UTF16, + SIL_OBJC_SELECTOR, }; enum SILLinkageEncoding : uint8_t { @@ -142,7 +142,7 @@ namespace sil_block { // We also share these layouts from the decls block. Their enumerators must // not overlap with ours. BOUND_GENERIC_SUBSTITUTION = decls_block::BOUND_GENERIC_SUBSTITUTION, - NO_CONFORMANCE = decls_block::NO_CONFORMANCE, + ABSTRACT_PROTOCOL_CONFORMANCE = decls_block::ABSTRACT_PROTOCOL_CONFORMANCE, NORMAL_PROTOCOL_CONFORMANCE = decls_block::NORMAL_PROTOCOL_CONFORMANCE, SPECIALIZED_PROTOCOL_CONFORMANCE = decls_block::SPECIALIZED_PROTOCOL_CONFORMANCE, @@ -216,19 +216,18 @@ namespace sil_block { BCFixed<1> // Is this a let variable. >; - using SILFunctionLayout = BCRecordLayout< - SIL_FUNCTION, - SILLinkageField, - BCFixed<1>, // transparent - BCFixed<1>, // fragile - BCFixed<2>, // thunk/reabstraction_thunk - BCFixed<1>, // global_init - BCFixed<2>, // inlineStrategy - BCFixed<2>, // side effect info. - TypeIDField, - IdentifierIDField // Semantics Attribute - // followed by generic param list, if any - >; + using SILFunctionLayout = + BCRecordLayout, // transparent + BCFixed<1>, // fragile + BCFixed<2>, // thunk/reabstraction_thunk + BCFixed<1>, // global_init + BCFixed<2>, // inlineStrategy + BCFixed<2>, // side effect info. + TypeIDField, + BCArray // Semantics Attribute + // followed by generic param list, if any + >; // Has an optional argument list where each argument is a typed valueref. using SILBasicBlockLayout = BCRecordLayout< @@ -243,11 +242,9 @@ namespace sil_block { SILInstOpCodeField, BCFixed<2>, // Optional attributes ValueIDField, - SILValueResultField, TypeIDField, SILTypeCategoryField, - ValueIDField, - SILValueResultField + ValueIDField >; // SIL instructions with one type and one typed valueref. @@ -259,8 +256,7 @@ namespace sil_block { SILTypeCategoryField, TypeIDField, SILTypeCategoryField, - ValueIDField, - SILValueResultField + ValueIDField >; // SIL instructions that construct existential values. @@ -272,7 +268,6 @@ namespace sil_block { TypeIDField, // operand type SILTypeCategoryField, // operand type category ValueIDField, // operand id - SILValueResultField, // operand result id TypeIDField, // formal concrete type BCVBR<5> // # of protocol conformances // Trailed by protocol conformance info (if any) @@ -287,8 +282,7 @@ namespace sil_block { SILTypeCategoryField, TypeIDField, SILTypeCategoryField, - ValueIDField, - SILValueResultField + ValueIDField >; // SIL instructions with one type and a list of values. @@ -315,7 +309,6 @@ namespace sil_block { TypeIDField, // callee unsubstituted type TypeIDField, // callee substituted type ValueIDField, // callee value - SILValueResultField, BCArray // a list of arguments >; @@ -334,8 +327,7 @@ namespace sil_block { BCFixed<3>, // Optional attributes TypeIDField, SILTypeCategoryField, - ValueIDField, - SILValueResultField + ValueIDField >; // SIL instructions with two typed values. @@ -346,11 +338,9 @@ namespace sil_block { TypeIDField, SILTypeCategoryField, ValueIDField, - SILValueResultField, TypeIDField, SILTypeCategoryField, - ValueIDField, - SILValueResultField + ValueIDField >; using SILGenericOuterParamsLayout = BCRecordLayout< diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 4aad30ab61aa2..dc43024609689 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -25,6 +25,7 @@ #include "swift/Basic/FileSystem.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" +#include "swift/Basic/Timer.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Serialization/SerializationOptions.h" @@ -163,7 +164,8 @@ static ASTContext &getContext(ModuleOrSourceFile DC) { } static bool shouldSerializeAsLocalContext(const DeclContext *DC) { - return DC->isLocalContext() && !isa(DC); + return DC->isLocalContext() && !isa(DC) && + !isa(DC); } static const Decl *getDeclForContext(const DeclContext *DC) { @@ -187,6 +189,8 @@ static const Decl *getDeclForContext(const DeclContext *DC) { llvm_unreachable("shouldn't serialize the main module"); case DeclContextKind::AbstractFunctionDecl: return cast(DC); + case DeclContextKind::SubscriptDecl: + return cast(DC); } } @@ -425,6 +429,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(options_block, XCC); BLOCK_RECORD(options_block, IS_SIB); BLOCK_RECORD(options_block, IS_TESTABLE); + BLOCK_RECORD(options_block, IS_RESILIENT); BLOCK(INPUT_BLOCK); BLOCK_RECORD(input_block, IMPORTED_MODULE); @@ -486,7 +491,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::BOUND_GENERIC_SUBSTITUTION); BLOCK_RECORD_WITH_NAMESPACE(sil_block, - decls_block::NO_CONFORMANCE); + decls_block::ABSTRACT_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, decls_block::NORMAL_PROTOCOL_CONFORMANCE); BLOCK_RECORD_WITH_NAMESPACE(sil_block, @@ -573,6 +578,11 @@ void Serializer::writeHeader(const SerializationOptions &options) { IsTestable.emit(ScratchRecord); } + if (M->isResilienceEnabled()) { + options_block::IsResilientLayout IsResilient(Out); + IsResilient.emit(ScratchRecord); + } + if (options.SerializeOptionsForDebugging) { options_block::SDKPathLayout SDKPath(Out); options_block::XCCLayout XCC(Out); @@ -748,6 +758,9 @@ static uint8_t getRawStableDefaultArgumentKind(swift::DefaultArgumentKind kind) CASE(Line) CASE(Function) CASE(DSOHandle) + CASE(Nil) + CASE(EmptyArray) + CASE(EmptyDictionary) #undef CASE } } @@ -784,6 +797,27 @@ static uint8_t getRawStableAddressorKind(swift::AddressorKind kind) { llvm_unreachable("bad addressor kind"); } +void Serializer::writeParameterList(const ParameterList *PL) { + using namespace decls_block; + + unsigned abbrCode = DeclTypeAbbrCodes[ParameterListLayout::Code]; + ParameterListLayout::emitRecord(Out, ScratchRecord, abbrCode, + PL->size()); + + abbrCode = DeclTypeAbbrCodes[ParameterListEltLayout::Code]; + for (auto ¶m : *PL) { + // FIXME: Default argument expressions? + + auto defaultArg = + getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()); + ParameterListEltLayout::emitRecord(Out, ScratchRecord, abbrCode, + addDeclRef(param), + param->isVariadic(), + defaultArg); + } +} + + void Serializer::writePattern(const Pattern *pattern) { using namespace decls_block; @@ -809,9 +843,7 @@ void Serializer::writePattern(const Pattern *pattern) { for (auto &elt : tuple->getElements()) { // FIXME: Default argument expressions? TuplePatternEltLayout::emitRecord( - Out, ScratchRecord, abbrCode, addIdentifierRef(elt.getLabel()), - elt.hasEllipsis(), - getRawStableDefaultArgumentKind(elt.getDefaultArgKind())); + Out, ScratchRecord, abbrCode, addIdentifierRef(elt.getLabel())); writePattern(elt.getPattern()); } break; @@ -895,6 +927,7 @@ static uint8_t getRawStableRequirementKind(RequirementKind kind) { switch (kind) { CASE(Conformance) + CASE(Superclass) CASE(SameType) CASE(WitnessMarker) } @@ -947,7 +980,7 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams, llvm::raw_svector_ostream ReqOS(ReqStr); next.printAsWritten(ReqOS); switch (next.getKind()) { - case RequirementKind::Conformance: + case RequirementReprKind::TypeConstraint: GenericRequirementLayout::emitRecord( Out, ScratchRecord, abbrCode, GenericRequirementKind::Conformance, @@ -955,7 +988,7 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams, addTypeRef(next.getConstraint()), ReqOS.str()); break; - case RequirementKind::SameType: + case RequirementReprKind::SameType: GenericRequirementLayout::emitRecord( Out, ScratchRecord, abbrCode, GenericRequirementKind::SameType, @@ -963,9 +996,6 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams, addTypeRef(next.getSecondType()), ReqOS.str()); break; - case RequirementKind::WitnessMarker: - llvm_unreachable("Can't show up in requirement representations"); - break; } } @@ -1013,8 +1043,6 @@ void Serializer::writeNormalConformance( data.push_back(addDeclRef(witness.getDecl())); assert(witness.getDecl() || req->getAttrs().hasAttribute() || req->getAttrs().isUnavailable(req->getASTContext())); - // The substitution records are serialized later. - data.push_back(witness.getSubstitutions().size()); ++numValueWitnesses; }); @@ -1061,11 +1089,6 @@ void Serializer::writeNormalConformance( DeclTypeAbbrCodes); } - conformance->forEachValueWitness(nullptr, - [&](ValueDecl *req, - ConcreteDeclRef witness) { - writeSubstitutions(witness.getSubstitutions(), DeclTypeAbbrCodes); - }); conformance->forEachTypeWitness(/*resolver=*/nullptr, [&](AssociatedTypeDecl *assocType, const Substitution &witness, @@ -1076,16 +1099,24 @@ void Serializer::writeNormalConformance( } void -Serializer::writeConformance(const ProtocolConformance *conformance, +Serializer::writeConformance(ProtocolConformance *conformance, + const std::array &abbrCodes) { + writeConformance(ProtocolConformanceRef(conformance), abbrCodes); +} + +void +Serializer::writeConformance(ProtocolConformanceRef conformanceRef, const std::array &abbrCodes) { using namespace decls_block; - if (!conformance) { - unsigned abbrCode = abbrCodes[NoConformanceLayout::Code]; - NoConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode); + if (conformanceRef.isAbstract()) { + unsigned abbrCode = abbrCodes[AbstractProtocolConformanceLayout::Code]; + AbstractProtocolConformanceLayout::emitRecord(Out, ScratchRecord, abbrCode, + addDeclRef(conformanceRef.getAbstract())); return; } + auto conformance = conformanceRef.getConcrete(); switch (conformance->getKind()) { case ProtocolConformanceKind::Normal: { auto normal = cast(conformance); @@ -1138,7 +1169,16 @@ Serializer::writeConformance(const ProtocolConformance *conformance, } void -Serializer::writeConformances(ArrayRef conformances, +Serializer::writeConformances(ArrayRef conformances, + const std::array &abbrCodes) { + using namespace decls_block; + + for (auto conformance : conformances) + writeConformance(conformance, abbrCodes); +} + +void +Serializer::writeConformances(ArrayRef conformances, const std::array &abbrCodes) { using namespace decls_block; @@ -1152,12 +1192,8 @@ Serializer::writeSubstitutions(ArrayRef substitutions, using namespace decls_block; auto abbrCode = abbrCodes[BoundGenericSubstitutionLayout::Code]; for (auto &sub : substitutions) { - SmallVector conformanceData; - SmallVector conformancesToWrite; - BoundGenericSubstitutionLayout::emitRecord( Out, ScratchRecord, abbrCode, - addTypeRef(sub.getArchetype()), addTypeRef(sub.getReplacement()), sub.getConformances().size()); @@ -1325,6 +1361,21 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) { break; } + case DeclContextKind::SubscriptDecl: { + auto SD = cast(DC); + writeCrossReference(DC->getParent(), pathLen + 1); + + Type ty = SD->getInterfaceType()->getCanonicalType(); + + abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code]; + bool isProtocolExt = SD->getDeclContext()->isProtocolExtensionContext(); + XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode, + addTypeRef(ty), + addIdentifierRef(SD->getName()), + isProtocolExt); + break; + } + case DeclContextKind::AbstractFunctionDecl: { if (auto fn = dyn_cast(DC)) { if (auto storage = fn->getAccessorStorageDecl()) { @@ -1676,6 +1727,30 @@ void Serializer::writeDeclAttribute(const DeclAttribute *DA) { return; } + case DAK_Swift3Migration: { + auto *theAttr = cast(DA); + + llvm::SmallString<32> blob; + + unsigned renameLength = 0; + if (auto newName = theAttr->getRenamed()) { + llvm::raw_svector_ostream os(blob); + newName.print(os); + renameLength = os.str().size(); + } + + blob.append(theAttr->getMessage()); + + auto abbrCode = DeclTypeAbbrCodes[Swift3MigrationDeclAttrLayout::Code]; + Swift3MigrationDeclAttrLayout::emitRecord( + Out, ScratchRecord, abbrCode, + theAttr->isImplicit(), + renameLength, + theAttr->getMessage().size(), + blob); + return; + } + case DAK_WarnUnusedResult: { auto *theAttr = cast(DA); @@ -1724,6 +1799,7 @@ void Serializer::writeDeclContext(const DeclContext *DC) { switch (DC->getContextKind()) { case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: case DeclContextKind::NominalTypeDecl: case DeclContextKind::ExtensionDecl: declOrDeclContextID = addDeclRef(getDeclForContext(DC)); @@ -2359,7 +2435,7 @@ void Serializer::writeDecl(const Decl *D) { fn->isObjC(), fn->isMutating(), fn->hasDynamicSelf(), - fn->getBodyParamPatterns().size(), + fn->getParameterLists().size(), addTypeRef(fn->getType()), addTypeRef(fn->getInterfaceType()), addDeclRef(fn->getOperatorDecl()), @@ -2373,8 +2449,8 @@ void Serializer::writeDecl(const Decl *D) { writeGenericParams(fn->getGenericParams(), DeclTypeAbbrCodes); // Write the body parameters. - for (auto pattern : fn->getBodyParamPatterns()) - writePattern(pattern); + for (auto pattern : fn->getParameterLists()) + writeParameterList(pattern); if (auto errorConvention = fn->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); @@ -2452,7 +2528,7 @@ void Serializer::writeDecl(const Decl *D) { rawSetterAccessLevel, nameComponents); - writePattern(subscript->getIndices()); + writeParameterList(subscript->getIndices()); break; } @@ -2487,9 +2563,10 @@ void Serializer::writeDecl(const Decl *D) { nameComponents); writeGenericParams(ctor->getGenericParams(), DeclTypeAbbrCodes); - assert(ctor->getBodyParamPatterns().size() == 2); - for (auto pattern : ctor->getBodyParamPatterns()) - writePattern(pattern); + assert(ctor->getParameterLists().size() == 2); + // Why is this writing out the param list for self? + for (auto paramList : ctor->getParameterLists()) + writeParameterList(paramList); if (auto errorConvention = ctor->getForeignErrorConvention()) writeForeignErrorConvention(*errorConvention); break; @@ -2508,9 +2585,9 @@ void Serializer::writeDecl(const Decl *D) { dtor->isObjC(), addTypeRef(dtor->getType()), addTypeRef(dtor->getInterfaceType())); - assert(dtor->getBodyParamPatterns().size() == 1); - for (auto pattern : dtor->getBodyParamPatterns()) - writePattern(pattern); + assert(dtor->getParameterLists().size() == 1); + // Why is this writing out the param list for self? + writeParameterList(dtor->getParameterLists()[0]); break; } @@ -3064,7 +3141,7 @@ void Serializer::writeType(Type ty) { auto generic = cast(ty.getPointer()); // We don't want two copies of Archetype being serialized, one by - // serializing genericArgs, the other by serializaing the Decl. The reason + // serializing genericArgs, the other by serializing the Decl. The reason // is that it is likely the Decl's Archetype can be serialized in // a different module, causing two copies being constructed at // deserialization, one in the other module, one in this module as @@ -3186,6 +3263,9 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); + registerDeclTypeAbbr(); + registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); @@ -3212,7 +3292,7 @@ void Serializer::writeAllDeclsAndTypes() { registerDeclTypeAbbr(); registerDeclTypeAbbr(); - registerDeclTypeAbbr(); + registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); registerDeclTypeAbbr(); @@ -3616,6 +3696,18 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { .push_back({ getStableFixity(OD->getKind()), addDeclRef(D) }); } + // If this is a global variable, force the accessors to be + // serialized. + if (auto VD = dyn_cast(D)) { + if (VD->getGetter()) + addDeclRef(VD->getGetter()); + if (VD->getSetter()) + addDeclRef(VD->getSetter()); + } + + // If this nominal type has associated top-level decls for a + // derived conformance (for example, ==), force them to be + // serialized. if (auto IDC = dyn_cast(D)) { addOperatorsAndTopLevel(*this, IDC->getMembers(), operatorMethodDecls, topLevelDecls, @@ -3632,11 +3724,9 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { for (auto TD : localTypeDecls) { hasLocalTypes = true; - SmallString<32> MangledName; - llvm::raw_svector_ostream Stream(MangledName); - Mangle::Mangler DebugMangler(Stream, false); - DebugMangler.mangleType(TD->getDeclaredType(), - ResilienceExpansion::Minimal, 0); + Mangle::Mangler DebugMangler(false); + DebugMangler.mangleType(TD->getDeclaredType(), 0); + auto MangledName = DebugMangler.finalize(); assert(!MangledName.empty() && "Mangled type came back empty!"); localTypeGenerator.insert(MangledName, { addDeclRef(TD), TD->getLocalDiscriminator() @@ -3799,6 +3889,7 @@ void swift::serialize(ModuleOrSourceFile DC, bool hadError = withOutputFile(getContext(DC), options.OutputPath, [&](raw_ostream &out) { + SharedTimer timer("Serialization (swiftmodule)"); Serializer::writeToStream(out, DC, M, options); }); if (hadError) @@ -3807,6 +3898,7 @@ void swift::serialize(ModuleOrSourceFile DC, if (options.DocOutputPath && options.DocOutputPath[0] != '\0') { (void)withOutputFile(getContext(DC), options.DocOutputPath, [&](raw_ostream &out) { + SharedTimer timer("Serialization (swiftdoc)"); Serializer::writeDocToStream(out, DC); }); } diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index a0fd272ad1a52..a9929f6232c7f 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -1,8 +1,8 @@ -//===--- Serialization.h - Read and write Swift modules -------------------===// +//===--- Serialization.h - Read and write Swift modules ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -235,6 +235,8 @@ class Serializer { /// modules and its source files. void writeInputBlock(const SerializationOptions &options); + void writeParameterList(const ParameterList *PL); + /// Writes the given pattern, recursively. void writePattern(const Pattern *pattern); @@ -242,7 +244,11 @@ class Serializer { void writeRequirements(ArrayRef requirements); /// Writes a list of protocol conformances. - void writeConformances(ArrayRef conformances, + void writeConformances(ArrayRef conformances, + const std::array &abbrCodes); + + /// Writes a list of protocol conformances. + void writeConformances(ArrayRef conformances, const std::array &abbrCodes); /// Writes an array of members for a decl context. @@ -390,7 +396,11 @@ class Serializer { void writeNormalConformance(const NormalProtocolConformance *conformance); /// Writes a protocol conformance. - void writeConformance(const ProtocolConformance *conformance, + void writeConformance(ProtocolConformanceRef conformance, + const std::array &abbrCodes); + + /// Writes a protocol conformance. + void writeConformance(ProtocolConformance *conformance, const std::array &abbrCodes); /// Writes a generic parameter list. diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 65bfd2a3539a8..7ca0f0c8bbbba 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,6 +20,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -36,6 +37,7 @@ static unsigned toStableStringEncoding(StringLiteralInst::Encoding encoding) { switch (encoding) { case StringLiteralInst::Encoding::UTF8: return SIL_UTF8; case StringLiteralInst::Encoding::UTF16: return SIL_UTF16; + case StringLiteralInst::Encoding::ObjCSelector: return SIL_OBJC_SELECTOR; } llvm_unreachable("bad string encoding"); } @@ -117,9 +119,6 @@ namespace { ValueID InstID = 0; llvm::DenseMap ValueIDs; - ValueID addValueRef(SILValue SV) { - return addValueRef(SV.getDef()); - } ValueID addValueRef(const ValueBase *Val); public: @@ -235,9 +234,10 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { << " FnID " << FnID << "\n"); DEBUG(llvm::dbgs() << "Serialized SIL:\n"; F.dump()); - IdentifierID SemanticsID = - F.getSemanticsAttr().empty() ? (IdentifierID)0 : - S.addIdentifierRef(Ctx.getIdentifier(F.getSemanticsAttr())); + SmallVector SemanticsIDs; + for (auto SemanticAttr : F.getSemanticsAttrs()) { + SemanticsIDs.push_back(S.addIdentifierRef(Ctx.getIdentifier(SemanticAttr))); + } SILLinkage Linkage = F.getLinkage(); @@ -246,7 +246,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { // 1. shared_external linkage is just a hack to tell the optimizer that a // shared function was deserialized. // - // 2. We can not just serialize a declaration to a shared_external function + // 2. We cannot just serialize a declaration to a shared_external function // since shared_external functions still have linkonce_odr linkage at the LLVM // level. This means they must be defined not just declared. // @@ -258,7 +258,7 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { bool NoBody = DeclOnly || isAvailableExternally(Linkage) || F.isExternalDeclaration(); - // If we don't emit a function body then make sure to mark the decleration + // If we don't emit a function body then make sure to mark the declaration // as available externally. if (NoBody) { Linkage = addExternalToLinkage(Linkage); @@ -268,8 +268,8 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isFragile(), (unsigned)F.isThunk(), (unsigned)F.isGlobalInit(), - (unsigned)F.getInlineStrategy(), (unsigned)F.getEffectsKind(), - FnID, SemanticsID); + (unsigned)F.getInlineStrategy(), (unsigned)F.getEffectsKind(), FnID, + SemanticsIDs); if (NoBody) return; @@ -346,10 +346,9 @@ void SILSerializer::handleMethodInst(const MethodInst *MI, ListOfValues.push_back(MI->isVolatile()); handleSILDeclRef(S, MI->getMember(), ListOfValues); ListOfValues.push_back( - S.addTypeRef(operand.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)operand.getType().getCategory()); + S.addTypeRef(operand->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)operand->getType().getCategory()); ListOfValues.push_back(addValueRef(operand)); - ListOfValues.push_back(operand.getResultNumber()); } void SILSerializer::writeOneTypeLayout(ValueKind valueKind, @@ -365,7 +364,7 @@ void SILSerializer::writeOneOperandLayout(ValueKind valueKind, unsigned attrs, SILValue operand) { - auto operandType = operand.getType(); + auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); auto operandRef = addValueRef(operand); @@ -373,7 +372,7 @@ void SILSerializer::writeOneOperandLayout(ValueKind valueKind, SILAbbrCodes[SILOneOperandLayout::Code], unsigned(valueKind), attrs, operandTypeRef, unsigned(operandType.getCategory()), - operandRef, operand.getResultNumber()); + operandRef); } void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, @@ -381,7 +380,7 @@ void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, SILType type, SILValue operand) { auto typeRef = S.addTypeRef(type.getSwiftRValueType()); - auto operandType = operand.getType(); + auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); auto operandRef = addValueRef(operand); @@ -390,14 +389,14 @@ void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned(valueKind), attrs, typeRef, unsigned(type.getCategory()), operandTypeRef, unsigned(operandType.getCategory()), - operandRef, operand.getResultNumber()); + operandRef); } void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned attrs, CanType type, SILValue operand) { auto typeRef = S.addTypeRef(type); - auto operandType = operand.getType(); + auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); auto operandRef = addValueRef(operand); @@ -406,15 +405,14 @@ void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned(valueKind), attrs, typeRef, 0, operandTypeRef, unsigned(operandType.getCategory()), - operandRef, operand.getResultNumber()); + operandRef); } /// Write an instruction that looks exactly like a conversion: all /// important information is encoded in the operand and the result type. void SILSerializer::writeConversionLikeInstruction(const SILInstruction *I) { assert(I->getNumOperands() == 1); - assert(I->getNumTypes() == 1); - writeOneTypeOneOperandLayout(I->getKind(), 0, I->getType(0), + writeOneTypeOneOperandLayout(I->getKind(), 0, I->getType(), I->getOperand(0)); } @@ -437,7 +435,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILValue operand; SILType Ty; CanType FormalConcreteType; - ArrayRef conformances; + ArrayRef conformances; switch (SI.getKind()) { default: llvm_unreachable("out of sync with parent"); @@ -477,8 +475,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILValueCategory operandCategory = SILValueCategory::Object; ValueID operandID = 0; if (operand) { - operandType = S.addTypeRef(operand.getType().getSwiftRValueType()); - operandCategory = operand.getType().getCategory(); + operandType = S.addTypeRef(operand->getType().getSwiftRValueType()); + operandCategory = operand->getType().getCategory(); operandID = addValueRef(operand); } @@ -490,7 +488,6 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { operandType, (unsigned)operandCategory, operandID, - operand.getResultNumber(), S.addTypeRef(FormalConcreteType), conformances.size()); @@ -587,6 +584,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { PBI->getOperand()); break; } + case ValueKind::ProjectExistentialBoxInst: { + auto PEBI = cast(&SI); + writeOneTypeOneOperandLayout(PEBI->getKind(), 0, + PEBI->getValueType(), + PEBI->getOperand()); + break; + } case ValueKind::BuiltinInst: { // Format: number of substitutions, the builtin name, result type, and // a list of values for the arguments. Each value in the list @@ -597,9 +601,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector Args; for (auto Arg : BI->getArguments()) { Args.push_back(addValueRef(Arg)); - Args.push_back(Arg.getResultNumber()); - Args.push_back(S.addTypeRef(Arg.getType().getSwiftRValueType())); - Args.push_back((unsigned)Arg.getType().getCategory()); + Args.push_back(S.addTypeRef(Arg->getType().getSwiftRValueType())); + Args.push_back((unsigned)Arg->getType().getCategory()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], @@ -608,7 +611,6 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { S.addTypeRef(BI->getType().getSwiftRValueType()), (unsigned)BI->getType().getCategory(), S.addIdentifierRef(BI->getName()), - 0, Args); S.writeSubstitutions(BI->getSubstitutions(), SILAbbrCodes); break; @@ -623,15 +625,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); - Args.push_back(Arg.getResultNumber()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], AI->isNonThrowing() ? SIL_NON_THROWING_APPLY : SIL_APPLY, AI->getSubstitutions().size(), - S.addTypeRef(AI->getCallee().getType().getSwiftRValueType()), + S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(AI->getSubstCalleeType()), - addValueRef(AI->getCallee()), AI->getCallee().getResultNumber(), + addValueRef(AI->getCallee()), Args); S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes); break; @@ -647,16 +648,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); - Args.push_back(Arg.getResultNumber()); } Args.push_back(BasicBlockMap[AI->getNormalBB()]); Args.push_back(BasicBlockMap[AI->getErrorBB()]); SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_TRY_APPLY, AI->getSubstitutions().size(), - S.addTypeRef(AI->getCallee().getType().getSwiftRValueType()), + S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(AI->getSubstCalleeType()), - addValueRef(AI->getCallee()), AI->getCallee().getResultNumber(), + addValueRef(AI->getCallee()), Args); S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes); break; @@ -666,18 +666,27 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector Args; for (auto Arg: PAI->getArguments()) { Args.push_back(addValueRef(Arg)); - Args.push_back(Arg.getResultNumber()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_PARTIAL_APPLY, PAI->getSubstitutions().size(), - S.addTypeRef(PAI->getCallee().getType().getSwiftRValueType()), + S.addTypeRef(PAI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(PAI->getSubstCalleeType()), - addValueRef(PAI->getCallee()), PAI->getCallee().getResultNumber(), + addValueRef(PAI->getCallee()), Args); S.writeSubstitutions(PAI->getSubstitutions(), SILAbbrCodes); break; } + case ValueKind::AllocGlobalInst: { + // Format: Name and type. Use SILOneOperandLayout. + const AllocGlobalInst *AGI = cast(&SI); + SILOneOperandLayout::emitRecord(Out, ScratchRecord, + SILAbbrCodes[SILOneOperandLayout::Code], + (unsigned)SI.getKind(), 0, 0, 0, + S.addIdentifierRef( + Ctx.getIdentifier(AGI->getReferencedGlobal()->getName()))); + break; + } case ValueKind::GlobalAddrInst: { // Format: Name and type. Use SILOneOperandLayout. const GlobalAddrInst *GAI = cast(&SI); @@ -687,8 +696,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { S.addTypeRef(GAI->getType().getSwiftRValueType()), (unsigned)GAI->getType().getCategory(), S.addIdentifierRef( - Ctx.getIdentifier(GAI->getReferencedGlobal()->getName())), - 0); + Ctx.getIdentifier(GAI->getReferencedGlobal()->getName()))); break; } case ValueKind::BranchInst: { @@ -697,10 +705,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const BranchInst *BrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : BrI->getArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)Elt.getType().getCategory()); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, @@ -718,28 +725,25 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const CondBranchInst *CBI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(CBI->getCondition())); - ListOfValues.push_back(CBI->getCondition().getResultNumber()); ListOfValues.push_back(BasicBlockMap[CBI->getTrueBB()]); ListOfValues.push_back(BasicBlockMap[CBI->getFalseBB()]); ListOfValues.push_back(CBI->getTrueArgs().size()); for (auto Elt : CBI->getTrueArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)Elt.getType().getCategory()); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } for (auto Elt : CBI->getFalseArgs()) { - ListOfValues.push_back(S.addTypeRef(Elt.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)Elt.getType().getCategory()); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CBI->getCondition().getType().getSwiftRValueType()), - (unsigned)CBI->getCondition().getType().getCategory(), + S.addTypeRef(CBI->getCondition()->getType().getSwiftRValueType()), + (unsigned)CBI->getCondition()->getType().getCategory(), ListOfValues); break; } @@ -752,7 +756,6 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SwitchEnumInstBase *SOI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SOI->getOperand())); - ListOfValues.push_back(SOI->getOperand().getResultNumber()); ListOfValues.push_back((unsigned)SOI->hasDefault()); if (SOI->hasDefault()) ListOfValues.push_back(BasicBlockMap[SOI->getDefaultBB()]); @@ -769,8 +772,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SOI->getOperand().getType().getSwiftRValueType()), - (unsigned)SOI->getOperand().getType().getCategory(), + S.addTypeRef(SOI->getOperand()->getType().getSwiftRValueType()), + (unsigned)SOI->getOperand()->getType().getCategory(), ListOfValues); break; } @@ -784,16 +787,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SelectEnumInstBase *SOI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SOI->getEnumOperand())); - ListOfValues.push_back(SOI->getEnumOperand().getResultNumber()); ListOfValues.push_back(S.addTypeRef(SOI->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)SOI->getType().getCategory()); ListOfValues.push_back((unsigned)SOI->hasDefault()); if (SOI->hasDefault()) { ListOfValues.push_back(addValueRef(SOI->getDefaultResult())); - ListOfValues.push_back(SOI->getDefaultResult().getResultNumber()); } else { ListOfValues.push_back(0); - ListOfValues.push_back(0); } for (unsigned i = 0, e = SOI->getNumCases(); i < e; ++i) { EnumElementDecl *elt; @@ -801,13 +801,12 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { std::tie(elt, result) = SOI->getCase(i); ListOfValues.push_back(S.addDeclRef(elt)); ListOfValues.push_back(addValueRef(result)); - ListOfValues.push_back(result.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SOI->getEnumOperand().getType().getSwiftRValueType()), - (unsigned)SOI->getEnumOperand().getType().getCategory(), + S.addTypeRef(SOI->getEnumOperand()->getType().getSwiftRValueType()), + (unsigned)SOI->getEnumOperand()->getType().getCategory(), ListOfValues); break; } @@ -819,7 +818,6 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SwitchValueInst *SII = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SII->getOperand())); - ListOfValues.push_back(SII->getOperand().getResultNumber()); ListOfValues.push_back((unsigned)SII->hasDefault()); if (SII->hasDefault()) ListOfValues.push_back(BasicBlockMap[SII->getDefaultBB()]); @@ -831,14 +829,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILBasicBlock *dest; std::tie(value, dest) = SII->getCase(i); ListOfValues.push_back(addValueRef(value)); - ListOfValues.push_back(value.getResultNumber()); ListOfValues.push_back(BasicBlockMap[dest]); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SII->getOperand().getType().getSwiftRValueType()), - (unsigned)SII->getOperand().getType().getCategory(), + S.addTypeRef(SII->getOperand()->getType().getSwiftRValueType()), + (unsigned)SII->getOperand()->getType().getCategory(), ListOfValues); break; } @@ -851,31 +848,26 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const SelectValueInst *SVI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SVI->getOperand())); - ListOfValues.push_back(SVI->getOperand().getResultNumber()); ListOfValues.push_back(S.addTypeRef(SVI->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)SVI->getType().getCategory()); ListOfValues.push_back((unsigned)SVI->hasDefault()); if (SVI->hasDefault()) { ListOfValues.push_back(addValueRef(SVI->getDefaultResult())); - ListOfValues.push_back(SVI->getDefaultResult().getResultNumber()); } else { ListOfValues.push_back(0); - ListOfValues.push_back(0); } for (unsigned i = 0, e = SVI->getNumCases(); i < e; ++i) { SILValue casevalue; SILValue result; std::tie(casevalue, result) = SVI->getCase(i); ListOfValues.push_back(addValueRef(casevalue)); - ListOfValues.push_back(casevalue.getResultNumber()); ListOfValues.push_back(addValueRef(result)); - ListOfValues.push_back(result.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(SVI->getOperand().getType().getSwiftRValueType()), - (unsigned)SVI->getOperand().getType().getCategory(), + S.addTypeRef(SVI->getOperand()->getType().getSwiftRValueType()), + (unsigned)SVI->getOperand()->getType().getCategory(), ListOfValues); break; } @@ -929,8 +921,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { (unsigned)SI.getKind(), 0, S.addTypeRef(FRI->getType().getSwiftRValueType()), (unsigned)FRI->getType().getCategory(), - S.addIdentifierRef(Ctx.getIdentifier(ReferencedFunction->getName())), - 0); + S.addIdentifierRef(Ctx.getIdentifier(ReferencedFunction->getName()))); // Make sure we declare the referenced function. FuncsToDeclare.insert(ReferencedFunction); @@ -962,12 +953,12 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), Attr, - S.addTypeRef(operand.getType().getSwiftRValueType()), - (unsigned)operand.getType().getCategory(), - addValueRef(operand), operand.getResultNumber(), - S.addTypeRef(operand2.getType().getSwiftRValueType()), - (unsigned)operand2.getType().getCategory(), - addValueRef(operand2), operand2.getResultNumber()); + S.addTypeRef(operand->getType().getSwiftRValueType()), + (unsigned)operand->getType().getCategory(), + addValueRef(operand), + S.addTypeRef(operand2->getType().getSwiftRValueType()), + (unsigned)operand2->getType().getCategory(), + addValueRef(operand2)); break; } case ValueKind::StringLiteralInst: { @@ -977,8 +968,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned encoding = toStableStringEncoding(SLI->getEncoding()); SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), encoding, 0, 0, - S.addIdentifierRef(Ctx.getIdentifier(Str)), - 0); + S.addIdentifierRef(Ctx.getIdentifier(Str))); break; } case ValueKind::FloatLiteralInst: @@ -1003,8 +993,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { (unsigned)SI.getKind(), 0, S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), - S.addIdentifierRef(Ctx.getIdentifier(Str)), - 0); + S.addIdentifierRef(Ctx.getIdentifier(Str))); break; } case ValueKind::MarkFunctionEscapeInst: { @@ -1013,10 +1002,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const MarkFunctionEscapeInst *MFE = cast(&SI); SmallVector ListOfValues; for (auto Elt : MFE->getElements()) { - ListOfValues.push_back(S.addTypeRef(Elt.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)Elt.getType().getCategory()); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, @@ -1025,7 +1013,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { break; } case ValueKind::MetatypeInst: - writeOneTypeLayout(SI.getKind(), SI.getType(0)); + writeOneTypeLayout(SI.getKind(), SI.getType()); break; case ValueKind::ObjCProtocolInst: { const ObjCProtocolInst *PI = cast(&SI); @@ -1034,7 +1022,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { (unsigned)SI.getKind(), 0, S.addTypeRef(PI->getType().getSwiftRValueType()), (unsigned)PI->getType().getCategory(), - S.addDeclRef(PI->getProtocol()), 0); + S.addDeclRef(PI->getProtocol())); break; } // Conversion instructions (and others of similar form). @@ -1074,14 +1062,12 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/ 0, - S.addTypeRef(RI->getConverted().getType().getSwiftRValueType()), - (unsigned)RI->getConverted().getType().getCategory(), + S.addTypeRef(RI->getConverted()->getType().getSwiftRValueType()), + (unsigned)RI->getConverted()->getType().getCategory(), addValueRef(RI->getConverted()), - RI->getConverted().getResultNumber(), - S.addTypeRef(RI->getBitsOperand().getType().getSwiftRValueType()), - (unsigned)RI->getBitsOperand().getType().getCategory(), - addValueRef(RI->getBitsOperand()), - RI->getBitsOperand().getResultNumber()); + S.addTypeRef(RI->getBitsOperand()->getType().getSwiftRValueType()), + (unsigned)RI->getBitsOperand()->getType().getCategory(), + addValueRef(RI->getBitsOperand())); break; } // Checked Conversion instructions. @@ -1092,9 +1078,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { (unsigned)SI.getKind(), /*attr*/ 0, S.addTypeRef(CI->getType().getSwiftRValueType()), (unsigned)CI->getType().getCategory(), - S.addTypeRef(CI->getOperand().getType().getSwiftRValueType()), - (unsigned)CI->getOperand().getType().getCategory(), - addValueRef(CI->getOperand()), CI->getOperand().getResultNumber()); + S.addTypeRef(CI->getOperand()->getType().getSwiftRValueType()), + (unsigned)CI->getOperand()->getType().getCategory(), + addValueRef(CI->getOperand())); break; } case ValueKind::UnconditionalCheckedCastAddrInst: { @@ -1103,17 +1089,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { toStableCastConsumptionKind(CI->getConsumptionKind()), S.addTypeRef(CI->getSourceType()), addValueRef(CI->getSrc()), - CI->getSrc().getResultNumber(), - S.addTypeRef(CI->getSrc().getType().getSwiftRValueType()), - (unsigned)CI->getSrc().getType().getCategory(), + S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()), + (unsigned)CI->getSrc()->getType().getCategory(), S.addTypeRef(CI->getTargetType()), - addValueRef(CI->getDest()), - CI->getDest().getResultNumber() + addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CI->getDest().getType().getSwiftRValueType()), - (unsigned)CI->getDest().getType().getCategory(), + S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()), + (unsigned)CI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } @@ -1122,17 +1106,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ValueID listOfValues[] = { S.addTypeRef(CI->getSourceType()), addValueRef(CI->getSrc()), - CI->getSrc().getResultNumber(), - S.addTypeRef(CI->getSrc().getType().getSwiftRValueType()), - (unsigned)CI->getSrc().getType().getCategory(), + S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()), + (unsigned)CI->getSrc()->getType().getCategory(), S.addTypeRef(CI->getTargetType()), - addValueRef(CI->getDest()), - CI->getDest().getResultNumber() + addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CI->getDest().getType().getSwiftRValueType()), - (unsigned)CI->getDest().getType().getCategory(), + S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()), + (unsigned)CI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } @@ -1169,11 +1151,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { unsigned abbrCode = SILAbbrCodes[SILOneValueOneOperandLayout::Code]; SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), Attr, addValueRef(value), - value.getResultNumber(), - S.addTypeRef(operand.getType().getSwiftRValueType()), - (unsigned)operand.getType().getCategory(), - addValueRef(operand), - operand.getResultNumber()); + S.addTypeRef(operand->getType().getSwiftRValueType()), + (unsigned)operand->getType().getCategory(), + addValueRef(operand)); break; } case ValueKind::RefElementAddrInst: @@ -1220,10 +1200,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { } SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneValueOneOperandLayout::Code], - (unsigned)SI.getKind(), 0, S.addDeclRef(tDecl), 0, - S.addTypeRef(operand.getType().getSwiftRValueType()), - (unsigned)operand.getType().getCategory(), - addValueRef(operand), operand.getResultNumber()); + (unsigned)SI.getKind(), 0, S.addDeclRef(tDecl), + S.addTypeRef(operand->getType().getSwiftRValueType()), + (unsigned)operand->getType().getCategory(), + addValueRef(operand)); break; } case ValueKind::StructInst: { @@ -1232,10 +1212,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const StructInst *StrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : StrI->getElements()) { - ListOfValues.push_back(S.addTypeRef(Elt.getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)Elt.getType().getCategory()); + ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, @@ -1266,9 +1245,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), 0, FieldNo, 0, - S.addTypeRef(operand.getType().getSwiftRValueType()), - (unsigned)operand.getType().getCategory(), - addValueRef(operand), operand.getResultNumber()); + S.addTypeRef(operand->getType().getSwiftRValueType()), + (unsigned)operand->getType().getCategory(), + addValueRef(operand)); break; } case ValueKind::TupleInst: { @@ -1278,7 +1257,6 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector ListOfValues; for (auto Elt : TI->getElements()) { ListOfValues.push_back(addValueRef(Elt)); - ListOfValues.push_back(Elt.getResultNumber()); } unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; @@ -1294,17 +1272,17 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // (DeclID + hasOperand), and an operand. const EnumInst *UI = cast(&SI); TypeID OperandTy = UI->hasOperand() ? - S.addTypeRef(UI->getOperand().getType().getSwiftRValueType()) : (TypeID)0; + S.addTypeRef(UI->getOperand()->getType().getSwiftRValueType()) : (TypeID)0; unsigned OperandTyCategory = UI->hasOperand() ? - (unsigned)UI->getOperand().getType().getCategory() : 0; + (unsigned)UI->getOperand()->getType().getCategory() : 0; SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, - SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), 0, + SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), + UI->hasOperand(), S.addTypeRef(UI->getType().getSwiftRValueType()), (unsigned)UI->getType().getCategory(), - S.addDeclRef(UI->getElement()), UI->hasOperand(), + S.addDeclRef(UI->getElement()), OperandTy, OperandTyCategory, - UI->hasOperand() ? addValueRef(UI->getOperand()) : (ValueID)0, - UI->hasOperand() ? UI->getOperand().getResultNumber() : 0); + UI->hasOperand() ? addValueRef(UI->getOperand()) : (ValueID)0); break; } case ValueKind::WitnessMethodInst: { @@ -1312,7 +1290,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type. const WitnessMethodInst *AMI = cast(&SI); CanType Ty = AMI->getLookupType(); - SILType Ty2 = AMI->getType(0); + SILType Ty2 = AMI->getType(); SmallVector ListOfValues; handleSILDeclRef(S, AMI->getMember(), ListOfValues); @@ -1320,10 +1298,10 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { // Add an optional operand. TypeID OperandTy = AMI->hasOperand() - ? S.addTypeRef(AMI->getOperand().getType().getSwiftRValueType()) + ? S.addTypeRef(AMI->getOperand()->getType().getSwiftRValueType()) : (TypeID)0; unsigned OperandTyCategory = - AMI->hasOperand() ? (unsigned)AMI->getOperand().getType().getCategory() + AMI->hasOperand() ? (unsigned)AMI->getOperand()->getType().getCategory() : 0; SILValue OptionalOpenedExistential = AMI->hasOperand() ? AMI->getOperand() : SILValue(); @@ -1390,15 +1368,14 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { const DynamicMethodBranchInst *DMB = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(DMB->getOperand())); - ListOfValues.push_back(DMB->getOperand().getResultNumber()); handleSILDeclRef(S, DMB->getMember(), ListOfValues); ListOfValues.push_back(BasicBlockMap[DMB->getHasMethodBB()]); ListOfValues.push_back(BasicBlockMap[DMB->getNoMethodBB()]); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(DMB->getOperand().getType().getSwiftRValueType()), - (unsigned)DMB->getOperand().getType().getCategory(), ListOfValues); + S.addTypeRef(DMB->getOperand()->getType().getSwiftRValueType()), + (unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::CheckedCastBranchInst: { @@ -1408,10 +1385,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { SmallVector ListOfValues; ListOfValues.push_back(CBI->isExact()), ListOfValues.push_back(addValueRef(CBI->getOperand())); - ListOfValues.push_back(CBI->getOperand().getResultNumber()); ListOfValues.push_back( - S.addTypeRef(CBI->getOperand().getType().getSwiftRValueType())); - ListOfValues.push_back((unsigned)CBI->getOperand().getType().getCategory()); + S.addTypeRef(CBI->getOperand()->getType().getSwiftRValueType())); + ListOfValues.push_back((unsigned)CBI->getOperand()->getType().getCategory()); ListOfValues.push_back(BasicBlockMap[CBI->getSuccessBB()]); ListOfValues.push_back(BasicBlockMap[CBI->getFailureBB()]); @@ -1431,19 +1407,17 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { toStableCastConsumptionKind(CBI->getConsumptionKind()), S.addTypeRef(CBI->getSourceType()), addValueRef(CBI->getSrc()), - CBI->getSrc().getResultNumber(), - S.addTypeRef(CBI->getSrc().getType().getSwiftRValueType()), - (unsigned)CBI->getSrc().getType().getCategory(), + S.addTypeRef(CBI->getSrc()->getType().getSwiftRValueType()), + (unsigned)CBI->getSrc()->getType().getCategory(), S.addTypeRef(CBI->getTargetType()), addValueRef(CBI->getDest()), - CBI->getDest().getResultNumber(), BasicBlockMap[CBI->getSuccessBB()], BasicBlockMap[CBI->getFailureBB()] }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), - S.addTypeRef(CBI->getDest().getType().getSwiftRValueType()), - (unsigned)CBI->getDest().getType().getCategory(), + S.addTypeRef(CBI->getDest()->getType().getSwiftRValueType()), + (unsigned)CBI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } @@ -1451,15 +1425,13 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { auto IBSHI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage())); - ListOfValues.push_back(IBSHI->getBlockStorage().getResultNumber()); ListOfValues.push_back( - S.addTypeRef(IBSHI->getBlockStorage().getType().getSwiftRValueType())); + S.addTypeRef(IBSHI->getBlockStorage()->getType().getSwiftRValueType())); // Always an address, don't need to save category ListOfValues.push_back(addValueRef(IBSHI->getInvokeFunction())); - ListOfValues.push_back(IBSHI->getInvokeFunction().getResultNumber()); ListOfValues.push_back( - S.addTypeRef(IBSHI->getInvokeFunction().getType().getSwiftRValueType())); + S.addTypeRef(IBSHI->getInvokeFunction()->getType().getSwiftRValueType())); // Always a value, don't need to save category SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, @@ -1675,7 +1647,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) { // We have to make sure BOUND_GENERIC_SUBSTITUTION does not overlap with // SIL-specific records. registerSILAbbr(); - registerSILAbbr(); + registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 2510da96b4f14..112d1cffe2b0a 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -175,6 +175,8 @@ FileUnit *SerializedModuleLoader::loadAST( M.addFile(*fileUnit); if (extendedInfo.isTestable()) M.setTestingEnabled(); + if (extendedInfo.isResilient()) + M.setResilienceEnabled(); auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc()); err = loadedModuleFile->associateWithFileContext(fileUnit, @@ -476,6 +478,12 @@ SerializedASTFile::lookupClassMember(Module::AccessPathTy accessPath, File.lookupClassMember(accessPath, name, decls); } +void SerializedASTFile::lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const { + File.lookupObjCMethods(selector, results); +} + Optional SerializedASTFile::getCommentForDecl(const Decl *D) const { return File.getCommentForDecl(D); diff --git a/lib/Serialization/SerializedSILLoader.cpp b/lib/Serialization/SerializedSILLoader.cpp index bec70db01de6f..08a5660388a22 100644 --- a/lib/Serialization/SerializedSILLoader.cpp +++ b/lib/Serialization/SerializedSILLoader.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SwiftDemangle/MangleHack.cpp b/lib/SwiftDemangle/MangleHack.cpp index bae3a5e740956..b22010a0e3303 100644 --- a/lib/SwiftDemangle/MangleHack.cpp +++ b/lib/SwiftDemangle/MangleHack.cpp @@ -1,8 +1,8 @@ -//===-- MangleHack.cpp - Swift Mangle Hack for various clients ------------===// +//===--- MangleHack.cpp - Swift Mangle Hack for various clients -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/lib/SwiftDemangle/SwiftDemangle.cpp b/lib/SwiftDemangle/SwiftDemangle.cpp index 38e59172be6ce..b2a664b9f000b 100644 --- a/lib/SwiftDemangle/SwiftDemangle.cpp +++ b/lib/SwiftDemangle/SwiftDemangle.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index fd1b7230fdd2a..766d4e7089e84 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -2,16 +2,22 @@ add_custom_target(swift-stdlib-all) foreach(SDK ${SWIFT_SDKS}) add_custom_target("swift-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") + add_custom_target("swift-test-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") foreach(ARCH ${SWIFT_SDK_${SDK}_ARCHITECTURES}) set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-${ARCH}") add_custom_target("swift-stdlib${VARIANT_SUFFIX}") + add_custom_target("swift-test-stdlib${VARIANT_SUFFIX}") add_dependencies(swift-stdlib-all "swift-stdlib${VARIANT_SUFFIX}") add_dependencies("swift-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}" "swift-stdlib${VARIANT_SUFFIX}") + add_dependencies("swift-test-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}" + "swift-test-stdlib${VARIANT_SUFFIX}") endforeach() endforeach() -add_custom_target(swift-stdlib ALL +add_custom_target(swift-stdlib DEPENDS "swift-stdlib${SWIFT_PRIMARY_VARIANT_SUFFIX}") +add_custom_target(swift-test-stdlib ALL + DEPENDS "swift-test-stdlib${SWIFT_PRIMARY_VARIANT_SUFFIX}") if(SWIFT_HOST_VARIANT STREQUAL "linux") find_package(BSD REQUIRED) diff --git a/stdlib/internal/SwiftExperimental/SwiftExperimental.swift b/stdlib/internal/SwiftExperimental/SwiftExperimental.swift index 7e85e7059244b..1f32b4ec6dbfd 100644 --- a/stdlib/internal/SwiftExperimental/SwiftExperimental.swift +++ b/stdlib/internal/SwiftExperimental/SwiftExperimental.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/CMakeLists.txt b/stdlib/private/CMakeLists.txt index f522fbabc449b..d98138d88420c 100644 --- a/stdlib/private/CMakeLists.txt +++ b/stdlib/private/CMakeLists.txt @@ -8,14 +8,16 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") # POSIX APIs it imports the Darwin module on Apple platforms, so it can't # be built separately from the SDK overlay. add_subdirectory(StdlibUnittest) + add_subdirectory(StdlibCollectionUnittest) add_subdirectory(StdlibUnittestFoundationExtras) add_subdirectory(SwiftPrivateDarwinExtras) add_subdirectory(SwiftPrivatePthreadExtras) endif() endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") add_subdirectory(StdlibUnittest) + add_subdirectory(StdlibCollectionUnittest) add_subdirectory(SwiftPrivateDarwinExtras) add_subdirectory(SwiftPrivatePthreadExtras) endif() diff --git a/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt b/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt new file mode 100644 index 0000000000000..8b0c1ebd2bc46 --- /dev/null +++ b/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt @@ -0,0 +1,29 @@ +set(swift_stdlib_unittest_compile_flags) +if(SWIFT_SERIALIZE_STDLIB_UNITTEST) + list(APPEND swift_stdlib_unittest_compile_flags "-Xfrontend" "-sil-serialize-all") +endif() + +set(swift_stdlib_unittest_framework_depends) +if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") + list(APPEND swift_stdlib_unittest_framework_depends + Foundation) +endif() + +add_swift_library(swiftStdlibCollectionUnittest SHARED IS_STDLIB + # This file should be listed the first. Module name is inferred from the + # filename. + StdlibCollectionUnittest.swift + + CheckCollectionType.swift + CheckMutableCollectionType.swift.gyb + CheckRangeReplaceableCollectionType.swift + CheckRangeReplaceableSliceType.swift + CheckSequenceType.swift + MinimalCollections.swift.gyb + + PRIVATE_LINK_LIBRARIES ${swift_stdlib_unittest_private_link_libraries} + SWIFT_MODULE_DEPENDS StdlibUnittest + SWIFT_COMPILE_FLAGS ${swift_stdlib_unittest_compile_flags} + FRAMEWORK_DEPENDS ${swift_stdlib_unittest_framework_depends} + INSTALL_IN_COMPONENT stdlib-experimental) + diff --git a/stdlib/private/StdlibUnittest/CheckCollectionType.swift b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift similarity index 92% rename from stdlib/private/StdlibUnittest/CheckCollectionType.swift rename to stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift index f65450eb3b1cf..0b0baaebaafb1 100644 --- a/stdlib/private/StdlibUnittest/CheckCollectionType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import StdlibUnittest + public struct SubscriptRangeTest { public let expected: [OpaqueValue] public let collection: [OpaqueValue] @@ -772,6 +774,44 @@ self.test("\(testNamePrefix).removeFirst(n: Int)/slice/removeTooMany/semantics") slice.removeFirst(3) // Should trap. } +//===----------------------------------------------------------------------===// +// popFirst()/slice +//===----------------------------------------------------------------------===// + +self.test("\(testNamePrefix).popFirst()/slice/semantics") { + // This can just reuse the test data for removeFirst() + for test in removeFirstTests.filter({ $0.numberToRemove == 1 }) { + let c = makeWrappedCollection(test.collection.map(OpaqueValue.init)) + var slice = c[c.startIndex..>()) + var slice = c[c.startIndex..>()) + var slice = c[c.startIndex.. Bool) -> Void) { body { (_,_) in true } body { (_,_) in false } var i = 0 - body { (_,_) in i++ % 2 == 0 } - body { (_,_) in i++ % 3 == 0 } - body { (_,_) in i++ % 5 == 0 } + body { (_,_) in defer {i += 1}; return i % 2 == 0 } + body { (_,_) in defer {i += 1}; return i % 3 == 0 } + body { (_,_) in defer {i += 1}; return i % 5 == 0 } } internal func _mapInPlace( diff --git a/stdlib/private/StdlibUnittest/CheckRangeReplaceableCollectionType.swift b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift similarity index 99% rename from stdlib/private/StdlibUnittest/CheckRangeReplaceableCollectionType.swift rename to stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift index a4d58323c43bc..b3d6d9ba5a2d8 100644 --- a/stdlib/private/StdlibUnittest/CheckRangeReplaceableCollectionType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import StdlibUnittest + internal enum RangeSelection { case EmptyRange case LeftEdge diff --git a/stdlib/private/StdlibUnittest/CheckRangeReplaceableSliceType.swift b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift similarity index 99% rename from stdlib/private/StdlibUnittest/CheckRangeReplaceableSliceType.swift rename to stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift index 4abdd49c5229f..074fda0ba7a7f 100644 --- a/stdlib/private/StdlibUnittest/CheckRangeReplaceableSliceType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableSliceType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import StdlibUnittest + extension TestSuite { /// Adds a set of tests for `RangeReplaceableCollectionType` that is also a /// slice type. diff --git a/stdlib/private/StdlibUnittest/CheckSequenceType.swift b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift similarity index 99% rename from stdlib/private/StdlibUnittest/CheckSequenceType.swift rename to stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift index 604fc3c3a398b..ed0ea59f2da27 100644 --- a/stdlib/private/StdlibUnittest/CheckSequenceType.swift +++ b/stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +import StdlibUnittest + public struct DropFirstTest { public var sequence: [Int] public let dropElements: Int @@ -1520,7 +1522,8 @@ self.test("\(testNamePrefix).dropFirst/semantics/equivalence") { let s1 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init)) let s2 = makeWrappedSequence([1010, 2020, 3030, 4040].map(OpaqueValue.init)) - let result1 = s1.dropFirst(1).dropFirst(1) + let result0 = s1.dropFirst(1) + let result1 = result0.dropFirst(1) let result2 = s2.dropFirst(2) expectEqualSequence( @@ -1611,7 +1614,8 @@ self.test("\(testNamePrefix).prefix/semantics/equivalence") { let s2 = makeWrappedSequence(expected) let prefixedOnce = s1.prefix(3) - let prefixedTwice = s2.prefix(3).prefix(3) + let temp = s2.prefix(3) + let prefixedTwice = temp.prefix(3) expectEqualSequence(prefixedOnce, prefixedTwice) { extractValue($0).value == extractValue($1).value @@ -1649,7 +1653,8 @@ self.test("\(testNamePrefix).suffix/semantics/equivalence") { let s2 = makeWrappedSequence(expected) let prefixedOnce = s1.suffix(3) - let prefixedTwice = s2.suffix(3).prefix(3) + let temp = s2.suffix(3) + let prefixedTwice = temp.prefix(3) expectEqualSequence(prefixedOnce, prefixedTwice) { extractValue($0).value == extractValue($1).value diff --git a/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb b/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb new file mode 100644 index 0000000000000..fd2d89eed035b --- /dev/null +++ b/stdlib/private/StdlibCollectionUnittest/MinimalCollections.swift.gyb @@ -0,0 +1,1424 @@ +//===--- MinimalCollections.swift.gyb -------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +%{ + TRACE = '''@autoclosure _ message: () -> String = "", + showFrame: Bool = true, + stackTrace: SourceLocStack = SourceLocStack(), + file: String = __FILE__, line: UInt = __LINE__''' + + stackTrace = 'stackTrace.pushIf(showFrame, file: file, line: line)' +}% + +import StdlibUnittest + +/// State that is created every time a fresh generator is created with +/// `MinimalSequence.generate()`. +internal class _MinimalGeneratorPrivateState { + internal init() {} + + internal var returnedNilCounter: Int = 0 +} + +/// State shared by all generators of a MinimalSequence. +internal class _MinimalGeneratorSharedState { + internal init(_ data: [T]) { + self.data = data + } + + internal let data: [T] + internal var i: Int = 0 + internal var underestimatedCount: Int = 0 +} + +//===----------------------------------------------------------------------===// +// MinimalGenerator +//===----------------------------------------------------------------------===// + +/// A GeneratorType that implements the protocol contract in the most +/// narrow way possible. +/// +/// This generator will return `nil` only once. +public struct MinimalGenerator : GeneratorType { + public init(_ s: S) { + self._sharedState = _MinimalGeneratorSharedState(Array(s)) + } + + public init(_ data: [T]) { + self._sharedState = _MinimalGeneratorSharedState(data) + } + + internal init(_ _sharedState: _MinimalGeneratorSharedState) { + self._sharedState = _sharedState + } + + public func next() -> T? { + if _sharedState.i == _sharedState.data.count { + if isConsumed { + expectUnreachable("next() was called on a consumed generator") + } + _privateState.returnedNilCounter += 1 + return nil + } + defer { _sharedState.i += 1 } + return _sharedState.data[_sharedState.i] + } + + public var isConsumed: Bool { + return returnedNilCounter >= 1 + } + + public var returnedNilCounter: Int { + return _privateState.returnedNilCounter + } + + internal let _privateState: _MinimalGeneratorPrivateState = + _MinimalGeneratorPrivateState() + internal let _sharedState: _MinimalGeneratorSharedState +} + +// A protocol to identify MinimalGenerator. +public protocol _MinimalGeneratorType {} +extension MinimalGenerator : _MinimalGeneratorType {} + +//===----------------------------------------------------------------------===// +// MinimalSequence +//===----------------------------------------------------------------------===// + +public enum UnderestimateCountBehavior { + /// Return the actual number of elements. + case Precise + + /// Return the actual number of elements divided by 2. + case Half + + /// Return an overestimated count. Useful to test how algorithms reserve + /// memory. + case Overestimate + + /// Return the provided value. + case Value(Int) +} + +public protocol StrictSequenceType : SequenceType { + associatedtype Element + init(base: MinimalSequence) + var base: MinimalSequence { get } +} + +extension StrictSequenceType { + public init( + elements: S, + underestimatedCount: UnderestimateCountBehavior = .Value(0) + ) { + self.init(base: MinimalSequence( + elements: elements, underestimatedCount: underestimatedCount)) + } + + public func underestimateCount() -> Int { + return base.underestimateCount() + } +} + +extension StrictSequenceType where Generator : _MinimalGeneratorType { + public func generate() -> MinimalGenerator { + return base.generate() + } +} + +/// A SequenceType that implements the protocol contract in the most +/// narrow way possible. +/// +/// This sequence is consumed when its generator is advanced. +public struct MinimalSequence : SequenceType, CustomDebugStringConvertible { + public init( + elements: S, + underestimatedCount: UnderestimateCountBehavior = .Value(0) + ) { + let data = Array(elements) + self._sharedState = _MinimalGeneratorSharedState(data) + + switch underestimatedCount { + case .Precise: + self._sharedState.underestimatedCount = data.count + + case .Half: + self._sharedState.underestimatedCount = data.count / 2 + + case .Overestimate: + self._sharedState.underestimatedCount = data.count * 3 + 5 + + case .Value(let count): + self._sharedState.underestimatedCount = count + } + } + + public func generate() -> MinimalGenerator { + return MinimalGenerator(_sharedState) + } + + public func underestimateCount() -> Int { + return max(0, self._sharedState.underestimatedCount - self._sharedState.i) + } + + public var debugDescription: String { + return "MinimalSequence(\(_sharedState.data[_sharedState.i..<_sharedState.data.count]))" + } + + internal let _sharedState: _MinimalGeneratorSharedState +} + +//===----------------------------------------------------------------------===// +// Index invalidation checking +//===----------------------------------------------------------------------===// + +internal enum _CollectionOperation : Equatable { + case ReserveCapacity(capacity: Int) + case Append + case AppendContentsOf(count: Int) + case ReplaceRange(subRange: Range, replacementCount: Int) + case Insert(atIndex: Int) + case InsertContentsOf(atIndex: Int, count: Int) + case RemoveAtIndex(index: Int) + case RemoveLast + case RemoveRange(subRange: Range) + case RemoveAll(keepCapacity: Bool) + + internal func _applyTo( + elementsLastMutatedStateIds: [Int], nextStateId: Int) -> [Int] { + var result = elementsLastMutatedStateIds + switch self { + case ReserveCapacity: + let invalidIndices = result.indices + result.replaceRange( + invalidIndices, + with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId)) + + case Append: + result.append(nextStateId) + + case AppendContentsOf(let count): + result.appendContentsOf( + Repeat(count: count, repeatedValue: nextStateId)) + + case ReplaceRange(let subRange, let replacementCount): + result.replaceRange( + subRange, + with: Repeat(count: replacementCount, repeatedValue: nextStateId)) + + let invalidIndices = subRange.startIndex.. Bool { + switch (lhs, rhs) { + case (.ReserveCapacity(let lhsCapacity), .ReserveCapacity(let rhsCapacity)): + return lhsCapacity == rhsCapacity + + case (.Append, .Append): + return true + + case (.AppendContentsOf(let lhsCount), .AppendContentsOf(let rhsCount)): + return lhsCount == rhsCount + + case ( + .ReplaceRange(let lhsSubRange, let lhsReplacementCount), + .ReplaceRange(let rhsSubRange, let rhsReplacementCount)): + + return lhsSubRange == rhsSubRange && + lhsReplacementCount == rhsReplacementCount + + case (.Insert(let lhsAtIndex), .Insert(let rhsAtIndex)): + return lhsAtIndex == rhsAtIndex + + case ( + .InsertContentsOf(let lhsAtIndex, let lhsCount), + .InsertContentsOf(let rhsAtIndex, let rhsCount)): + + return lhsAtIndex == rhsAtIndex && lhsCount == rhsCount + + case (.RemoveAtIndex(let lhsIndex), .RemoveAtIndex(let rhsIndex)): + return lhsIndex == rhsIndex + + case (.RemoveLast, .RemoveLast): + return true + + case (.RemoveRange(let lhsSubRange), .RemoveRange(let rhsSubRange)): + return lhsSubRange == rhsSubRange + + case (.RemoveAll(let lhsKeepCapacity), .RemoveAll(let rhsKeepCapacity)): + return lhsKeepCapacity == rhsKeepCapacity + + default: + return false + } +} + +public struct _CollectionState : Equatable, Hashable { + internal static var _nextUnusedState: Int = 0 + internal static var _namedStates: [String : _CollectionState] = [:] + + internal let _id: Int + internal let _elementsLastMutatedStateIds: [Int] + + internal init(id: Int, elementsLastMutatedStateIds: [Int]) { + self._id = id + self._elementsLastMutatedStateIds = elementsLastMutatedStateIds + } + + internal init(newRootStateForElementCount count: Int) { + self._id = _CollectionState._nextUnusedState + _CollectionState._nextUnusedState += 1 + self._elementsLastMutatedStateIds = + Array(Repeat(count: count, repeatedValue: self._id)) + } + + internal init(name: String, elementCount: Int) { + if let result = _CollectionState._namedStates[name] { + self = result + } else { + self = _CollectionState(newRootStateForElementCount: elementCount) + _CollectionState._namedStates[name] = self + } + } + + public var hashValue: Int { + return _id.hashValue + } +} + +public func == (lhs: _CollectionState, rhs: _CollectionState) -> Bool { + return lhs._id == rhs._id +} + +internal struct _CollectionStateTransition { + internal let _previousState: _CollectionState + internal let _operation: _CollectionOperation + internal let _nextState: _CollectionState + + internal static var _allTransitions: + [_CollectionState : Box<[_CollectionStateTransition]>] = [:] + + internal init( + previousState: _CollectionState, + operation: _CollectionOperation, + nextState: _CollectionState + ) { + var transitions = + _CollectionStateTransition._allTransitions[previousState] + if transitions == nil { + transitions = Box<[_CollectionStateTransition]>([]) + _CollectionStateTransition._allTransitions[previousState] = transitions + } + if let i = transitions!.value.indexOf({ $0._operation == operation }) { + self = transitions!.value[i] + return + } + self._previousState = previousState + self._operation = operation + self._nextState = nextState + transitions!.value.append(self) + } + + internal init( + previousState: _CollectionState, + operation: _CollectionOperation + ) { + let nextStateId = _CollectionState._nextUnusedState + _CollectionState._nextUnusedState += 1 + let newElementStates = operation._applyTo( + previousState._elementsLastMutatedStateIds, nextStateId: nextStateId) + let nextState = _CollectionState( + id: nextStateId, elementsLastMutatedStateIds: newElementStates) + self = _CollectionStateTransition( + previousState: previousState, + operation: operation, + nextState: nextState) + } +} + +//===----------------------------------------------------------------------===// +// MinimalForwardIndex +//===----------------------------------------------------------------------===// + +/// Asserts that the two indices are allowed to participate in a binary +/// operation. +internal func _expectCompatibleIndices( + first: Index, + _ second: Index, + ${TRACE} +) { + if let firstStateId = first._collectionState?._id, + let secondStateId = second._collectionState?._id + where firstStateId == secondStateId { + + // The indices are derived from the same state. + return + } + + // The indices are derived from different states. Check that they point + // to elements that persisted from the same state. + + func getLastMutatedStateId(i: Index) -> Int? { + guard let state = i._collectionState else { return nil } + let offset = i._offset + if offset == state._elementsLastMutatedStateIds.endIndex { + return state._id + } + return state._elementsLastMutatedStateIds[offset] + } + + let firstElementLastMutatedStateId = getLastMutatedStateId(first) + let secondElementLastMutatedStateId = getLastMutatedStateId(second) + + expectEqual( + firstElementLastMutatedStateId, + secondElementLastMutatedStateId, + "Indices are not compatible:\n" + + "first: \(first)\n" + + "second: \(second)\n" + + "first element last mutated in state id: \(firstElementLastMutatedStateId)\n" + + "second element last mutated in state id: \(secondElementLastMutatedStateId)\n", + stackTrace: ${stackTrace}) + + // To make writing assertions easier, perform a trap. + if firstElementLastMutatedStateId != secondElementLastMutatedStateId { + fatalError("Indices are not compatible") + } +} + +public protocol _MinimalIndexType { + /// Distance from start index. + var _offset: Int { get } + + var _collectionState: _CollectionState? { get } +} + +% for Distance in [ '', 'Int32' ]: +% Index = 'MinimalForward%sIndex' % Distance + +public struct ${Index} : ForwardIndexType { +% if Distance != '': + public typealias Distance = ${Distance} +% else: + public typealias Distance = Int +% end + + public init(position: Int, startIndex: Int, endIndex: Int) { + self = ${Index}( + collectionState: nil, + position: position, + startIndex: startIndex, + endIndex: endIndex) + } + + internal init( + collectionState: _CollectionState?, + position: Int, + startIndex: Int, + endIndex: Int + ) { + expectLE(startIndex, position) + expectGE(endIndex, position) + self._collectionState = collectionState + self.position = position + self.startIndex = startIndex + self.endIndex = endIndex + } + + public func successor() -> ${Index} { + expectNotEqual(endIndex, position) + return ${Index}( + collectionState: _collectionState, + position: position + 1, startIndex: startIndex, endIndex: endIndex) + } + + public static func _failEarlyRangeCheck( + index: ${Index}, bounds: Range<${Index}> + ) { + expectLE(bounds.startIndex.position, index.position) + expectGT(bounds.endIndex.position, index.position) + + if ${Index}.trapOnRangeCheckFailure.value { + Int._failEarlyRangeCheck( + index.position, + bounds: bounds.startIndex.position.. Bool { + _expectCompatibleIndices(lhs, rhs) + return lhs.position == rhs.position +} + +extension ${Index} : _MinimalIndexType { + public var _offset: Int { + return position - startIndex + } +} + +% end + +//===----------------------------------------------------------------------===// +// MinimalBidirectionalIndex +//===----------------------------------------------------------------------===// + +public struct MinimalBidirectionalIndex : BidirectionalIndexType { + public typealias Distance = Int + + public init(position: Int, startIndex: Int, endIndex: Int) { + self = MinimalBidirectionalIndex( + collectionState: nil, + position: position, + startIndex: startIndex, + endIndex: endIndex) + } + + internal init( + collectionState: _CollectionState?, + position: Int, + startIndex: Int, + endIndex: Int + ) { + expectLE(startIndex, position) + expectGE(endIndex, position) + self._collectionState = collectionState + self.position = position + self.startIndex = startIndex + self.endIndex = endIndex + } + + public func successor() -> MinimalBidirectionalIndex { + expectNotEqual(endIndex, position) + return MinimalBidirectionalIndex( + collectionState: _collectionState, + position: position + 1, startIndex: startIndex, endIndex: endIndex) + } + + public func predecessor() -> MinimalBidirectionalIndex { + expectNotEqual(startIndex, position) + return MinimalBidirectionalIndex( + collectionState: _collectionState, + position: position - 1, startIndex: startIndex, endIndex: endIndex) + } + + public static func _failEarlyRangeCheck( + index: MinimalBidirectionalIndex, + bounds: Range + ) { + expectLE(bounds.startIndex.position, index.position) + expectGT(bounds.endIndex.position, index.position) + + if MinimalBidirectionalIndex.trapOnRangeCheckFailure.value { + Int._failEarlyRangeCheck( + index.position, + bounds: bounds.startIndex.position.. Bool { + _expectCompatibleIndices(lhs, rhs) + return lhs.position == rhs.position +} + +extension MinimalBidirectionalIndex : _MinimalIndexType { + public var _offset: Int { + return position - startIndex + } +} + +//===----------------------------------------------------------------------===// +// Strict Index Types +//===----------------------------------------------------------------------===// + +% for Traversal in ['Forward', 'Bidirectional', 'RandomAccess']: +% StrictIndexType = 'Strict{}IndexType'.format(Traversal) + +public protocol ${StrictIndexType} : ${Traversal}IndexType { + associatedtype Base : ${Traversal}IndexType + init(_ base: Base) + var base: Base { get set } + + func logSuccessor() + func logPredecessor() +} + +extension ${StrictIndexType} { + public func successor() -> Self { + logSuccessor() + return Self(base.successor()) + } +% if Traversal in ['Bidirectional', 'RandomAccess']: + public func predecessor() -> Self { + logPredecessor() + return Self(base.predecessor()) + } +% end +} + +% end + +//===----------------------------------------------------------------------===// +// Defaulted Index Types +//===----------------------------------------------------------------------===// +% for Traversal in ['Forward', 'Bidirectional', 'RandomAccess']: +% StrictIndexType = 'Strict{}IndexType'.format(Traversal) +% DefaultedIndex = 'Defaulted{}Index'.format(Traversal) + +public struct ${DefaultedIndex}: ${StrictIndexType} { + public typealias Distance = Int + public typealias Base = Int + public var base: Base + public static var timesSuccessorCalled = ResettableValue(0) + public static var timesPredecessorCalled = ResettableValue(0) + + public init(_ base: Base) { + self.base = base + } + + public init(position: Base, startIndex: Base, endIndex: Base) { + expectLE(startIndex, position) + expectGE(endIndex, position) + self.init(position) + } + + public func logSuccessor() { + ${DefaultedIndex}.timesSuccessorCalled.value += 1 + } + + public func logPredecessor() { + ${DefaultedIndex}.timesPredecessorCalled.value += 1 + } + +% if Traversal == 'RandomAccess': + public func distanceTo(n: ${DefaultedIndex}) -> Distance { + return n.base - base + } + + public func advancedBy(n: Distance) -> ${DefaultedIndex} { + return ${DefaultedIndex}(base + n) + } +% end +} + +public func == (lhs: ${DefaultedIndex}, rhs: ${DefaultedIndex}) -> Bool { + return rhs.base == lhs.base +} + +% end + + + +//===----------------------------------------------------------------------===// +// MinimalRandomAccessIndex +//===----------------------------------------------------------------------===// + +public struct MinimalRandomAccessIndex : RandomAccessIndexType { + public typealias Distance = Int + public init(position: Int, startIndex: Int, endIndex: Int) { + self = MinimalRandomAccessIndex( + collectionState: nil, + position: position, + startIndex: startIndex, + endIndex: endIndex) + } + + internal init( + collectionState: _CollectionState?, + position: Int, + startIndex: Int, + endIndex: Int + ) { + expectLE(startIndex, position) + expectGE(endIndex, position) /*{ + "position=\(self.position) startIndex=\(self.startIndex) endIndex=\(self.endIndex)" + }*/ + + self._collectionState = collectionState + self.position = position + self.startIndex = startIndex + self.endIndex = endIndex + } + + public func successor() -> MinimalRandomAccessIndex { + expectNotEqual(endIndex, position) + return MinimalRandomAccessIndex( + collectionState: _collectionState, + position: position + 1, startIndex: startIndex, endIndex: endIndex) + } + + public func predecessor() -> MinimalRandomAccessIndex { + expectNotEqual(startIndex, position) + return MinimalRandomAccessIndex( + collectionState: _collectionState, + position: position - 1, startIndex: startIndex, endIndex: endIndex) + } + + public func distanceTo(other: MinimalRandomAccessIndex) -> Int { + _expectCompatibleIndices(self, other) + return other.position - position + } + + public func advancedBy(n: Int) -> MinimalRandomAccessIndex { + let newPosition = position + n + expectLE(startIndex, newPosition) + expectGE( + endIndex, newPosition, + "position=\(self.position) startIndex=\(self.startIndex)") + return MinimalRandomAccessIndex( + collectionState: _collectionState, + position: newPosition, startIndex: startIndex, endIndex: endIndex) + } + + public static func _failEarlyRangeCheck( + index: MinimalRandomAccessIndex, + bounds: Range + ) { + expectLE(bounds.startIndex.position, index.position) + expectGT(bounds.endIndex.position, index.position) + + if MinimalRandomAccessIndex.trapOnRangeCheckFailure.value { + Int._failEarlyRangeCheck( + index.position, + bounds: bounds.startIndex.position.. Bool { + _expectCompatibleIndices(lhs, rhs) + return lhs.position == rhs.position +} + +extension MinimalRandomAccessIndex : _MinimalIndexType { + public var _offset: Int { + return position - startIndex + } +} + +//===----------------------------------------------------------------------===// +// Minimal***[Mutable]?Collection +//===----------------------------------------------------------------------===// + +% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: +% for mutable in [ False, True ]: +// This comment is a workaround for gyb miscompiles nested loops +% Protocol = 'Strict%s%sCollectionType' % (traversal, 'Mutable' if mutable else '') +% Self = 'Minimal%s%sCollection' % (traversal, 'Mutable' if mutable else '') +% Index = 'Minimal%sIndex' % traversal + +public protocol ${Protocol} : ${'MutableCollectionType' if mutable else 'CollectionType'} { + associatedtype Element + init(base: ${Self}) +% if mutable: + var base: ${Self} { get set } +% else: + var base: ${Self} { get } +% end +} + +extension ${Protocol} { + public init( + elements: S, + underestimatedCount: UnderestimateCountBehavior = .Value(0) + ) { + self.init(base: + ${Self}(elements: elements, underestimatedCount: underestimatedCount)) + } + + public func underestimateCount() -> Int { + return base.underestimateCount() + } +} + +extension ${Protocol} where Generator : _MinimalGeneratorType { + public func generate() -> MinimalGenerator { + return base.generate() + } +} + +extension ${Protocol} where Index : _MinimalIndexType { + public var startIndex: ${Index} { + return base.startIndex + } + + public var endIndex: ${Index} { + return base.endIndex + } + + public subscript(i: ${Index}) -> Element { + get { + _expectCompatibleIndices(self.startIndex, i) + return base[i] + } +% if mutable: + set { + _expectCompatibleIndices(self.startIndex, i) + base[i] = newValue + } +% end + } +} + +/// A minimal implementation of `CollectionType` with extra checks. +public struct ${Self} : ${'MutableCollectionType' if mutable else 'CollectionType'} { + public init( + elements: S, + underestimatedCount: UnderestimateCountBehavior = .Value(0) + ) { + self._elements = Array(elements) + + self._collectionState = _CollectionState( + newRootStateForElementCount: self._elements.count) + + switch underestimatedCount { + case .Precise: + self.underestimatedCount = _elements.count + + case .Half: + self.underestimatedCount = _elements.count / 2 + + case .Overestimate: + self.underestimatedCount = _elements.count * 3 + 5 + + case .Value(let count): + self.underestimatedCount = count + } + } + + public func generate() -> MinimalGenerator { + return MinimalGenerator(_elements) + } + + public var startIndex: ${Index} { + return ${Index}( + collectionState: _collectionState, + position: 0, + startIndex: 0, + endIndex: _elements.endIndex) + } + + public var endIndex: ${Index} { + return ${Index}( + collectionState: _collectionState, + position: _elements.endIndex, + startIndex: 0, + endIndex: _elements.endIndex) + } + + public subscript(i: ${Index}) -> T { + get { + _expectCompatibleIndices(self.startIndex, i) + return _elements[i.position] + } +% if mutable: + set { + _expectCompatibleIndices(self.startIndex, i) + _elements[i.position] = newValue + } +% end + } + + public func underestimateCount() -> Int { + return underestimatedCount + } + + public var underestimatedCount: Int + + internal var _elements: [T] + internal let _collectionState: _CollectionState +} + +% end +% end + +//===----------------------------------------------------------------------===// +// Minimal***RangeReplaceableCollectionType +//===----------------------------------------------------------------------===// + +% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: +% Protocol = 'Strict%sRangeReplaceableCollectionType' % traversal +% Self = 'Minimal%sRangeReplaceableCollection' % traversal +% Index = 'Minimal%sIndex' % traversal + +public protocol ${Protocol} : RangeReplaceableCollectionType { + associatedtype Element + init(base: ${Self}) + var base: ${Self} { get set } +} + +extension ${Protocol} { + public mutating func replaceRange< + C: CollectionType where C.Generator.Element == Element + >(subRange: Range<${Self}.Index>, + with newElements: C) { + base.replaceRange(subRange, with: newElements) + } + + public mutating func removeLast() -> Element { + return base.removeLast() + } +} + +extension ${Protocol} where Generator : _MinimalGeneratorType { + public func generate() -> MinimalGenerator { + return base.generate() + } +} + +extension ${Protocol} where Index : _MinimalIndexType { + public var startIndex: ${Index} { + return base.startIndex + } + + public var endIndex: ${Index} { + return base.endIndex + } + + public subscript(i: ${Index}) -> Element { + get { + _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) + return base[i] + } + set { + _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) + base[i] = newValue + } + } +} + +/// A minimal implementation of `RangeReplaceableCollectionType` with extra +/// checks. +public struct ${Self} : RangeReplaceableCollectionType { + /// Creates a collection with given contents, but a unique modification + /// history. No other instance has the same modification history. + public init( + elements: S, + underestimatedCount: UnderestimateCountBehavior = .Value(0) + ) { + self.elements = Array(elements) + + self._collectionState = _CollectionState( + newRootStateForElementCount: self.elements.count) + + switch underestimatedCount { + case .Precise: + self.underestimatedCount = self.elements.count + + case .Half: + self.underestimatedCount = self.elements.count / 2 + + case .Overestimate: + self.underestimatedCount = self.elements.count * 3 + 5 + + case .Value(let count): + self.underestimatedCount = count + } + } + + public init() { + self.underestimatedCount = 0 + self.elements = [] + self._collectionState = _CollectionState(name: "\(self.dynamicType)", elementCount: 0) + } + + public init< + S : SequenceType where S.Generator.Element == T + >(_ elements: S) { + self.underestimatedCount = 0 + self.elements = Array(elements) + self._collectionState = + _CollectionState(newRootStateForElementCount: self.elements.count) + } + + public func generate() -> MinimalGenerator { + return MinimalGenerator(elements) + } + + public func underestimateCount() -> Int { + return underestimatedCount + } + + public var startIndex: ${Index} { + return ${Index}( + collectionState: _collectionState, + position: 0, + startIndex: 0, + endIndex: elements.endIndex) + } + + public var endIndex: ${Index} { + return ${Index}( + collectionState: _collectionState, + position: elements.endIndex, + startIndex: 0, + endIndex: elements.endIndex) + } + + public subscript(i: ${Index}) -> T { + get { + _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) + return elements[i.position] + } + set { + _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) + elements[i.position] = newValue + } + } + + public mutating func reserveCapacity(n: Int) { + _willMutate(.ReserveCapacity(capacity: n)) + elements.reserveCapacity(n) + reservedCapacity = max(reservedCapacity, n) + } + + public mutating func append(x: T) { + _willMutate(.Append) + elements.append(x) + } + + public mutating func appendContentsOf< + S : SequenceType where S.Generator.Element == T + >(newElements: S) { + let oldCount = count + elements.appendContentsOf(newElements) + let newCount = count + _willMutate(.AppendContentsOf(count: newCount - oldCount)) + } + + public mutating func replaceRange< + C : CollectionType where C.Generator.Element == T + >( + subRange: Range<${Index}>, with newElements: C + ) { + let oldCount = count + elements.replaceRange( + subRange.startIndex.position..(newElements: S, at i: ${Index}) { + let oldCount = count + elements.insertContentsOf(newElements, at: i.position) + let newCount = count + + if newCount - oldCount != 0 { + _willMutate(.InsertContentsOf( + atIndex: i._offset, + count: newCount - oldCount)) + } + } + + public mutating func removeAtIndex(i: ${Index}) -> T { + _willMutate(.RemoveAtIndex(index: i._offset)) + return elements.removeAtIndex(i.position) + } + + public mutating func removeLast() -> T { + _willMutate(.RemoveLast) + return elements.removeLast() + } + + public mutating func removeRange(subRange: Range<${Index}>) { + if !subRange.isEmpty { + _willMutate(.RemoveRange( + subRange: subRange.startIndex._offset.. Bool { + ${Self}.timesEqualEqualWasCalled += 1 + return lhs.value == rhs.value +} + +% end + +/// A Sequence that uses as many default implementations as +/// `SequenceType` can provide. +public struct DefaultedSequence : StrictSequenceType { + public let base: MinimalSequence + + public init(base: MinimalSequence) { + self.base = base + } +} + +% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: + +/// A Collection that uses as many default implementations as +/// `CollectionType` can provide. +public struct Defaulted${traversal}Collection + : Strict${traversal}CollectionType { + + public typealias Base = Minimal${traversal}Collection + public typealias Generator = MinimalGenerator + public typealias Index = Minimal${traversal}Index + + public let base: Base + + public init(base: Base) { + self.base = base + } + + public init(_ array: [Element]) { + self.base = Base(elements: array) + } + + public init(elements: [Element]) { + self.base = Base(elements: elements) + } +} + +public struct Defaulted${traversal}MutableCollection + : Strict${traversal}MutableCollectionType { + + public typealias Base = Minimal${traversal}MutableCollection + public typealias Generator = MinimalGenerator + public typealias Index = Minimal${traversal}Index + + public var base: Base + + public init(base: Base) { + self.base = base + } + + public init(_ array: [Element]) { + self.base = Base(elements: array) + } + + public init(elements: [Element]) { + self.base = Base(elements: elements) + } +} + +public struct Defaulted${traversal}RangeReplaceableCollection + : Strict${traversal}RangeReplaceableCollectionType { + + public typealias Base = Minimal${traversal}RangeReplaceableCollection + public typealias Generator = MinimalGenerator + public typealias Index = Minimal${traversal}Index + + public var base: Base + + public init() { + base = Base() + } + + public init(base: Base) { + self.base = base + } + + public init(_ array: [Element]) { + self.base = Base(elements: array) + } + + public init(elements: [Element]) { + self.base = Base(elements: elements) + } +} + +public struct Defaulted${traversal}RangeReplaceableSlice + : RangeReplaceableCollectionType { + + public typealias Self_ = Defaulted${traversal}RangeReplaceableSlice + public typealias Base = Minimal${traversal}RangeReplaceableCollection + public typealias Generator = MinimalGenerator + public typealias Index = Minimal${traversal}Index + + public var base: Base + public var startIndex: Index + public var endIndex: Index + + public init() { + expectSliceType(Self_.self) + + self.base = Base() + self.startIndex = base.startIndex + self.endIndex = base.endIndex + } + + public init(base: Base) { + self.base = base + self.startIndex = base.startIndex + self.endIndex = base.endIndex + } + + public init(base: Base, bounds: Range) { + self.base = base + self.startIndex = bounds.startIndex + self.endIndex = bounds.endIndex + } + + public init(_ array: [Element]) { + self = Defaulted${traversal}RangeReplaceableSlice( + base: Base(elements: array)) + } + + public init(elements: [Element]) { + self = Defaulted${traversal}RangeReplaceableSlice( + base: Base(elements: elements)) + } + + public func generate() -> MinimalGenerator { + return MinimalGenerator(Array(self)) + } + + public subscript(index: Index) -> Element { + Index._failEarlyRangeCheck(index, bounds: startIndex..) -> Self_ { + Index._failEarlyRangeCheck2( + bounds.startIndex, rangeEnd: bounds.endIndex, + boundsStart: startIndex, boundsEnd: endIndex) + return Defaulted${traversal}RangeReplaceableSlice( + base: base, bounds: bounds) + } + + public mutating func replaceRange< + C : CollectionType where C.Generator.Element == Element + >( + subRange: Range, + with newElements: C + ) { + let startOffset = startIndex.position + let endOffset = + endIndex.position + - subRange.count + + numericCast(newElements.count) as Int + Index._failEarlyRangeCheck2( + subRange.startIndex, rangeEnd: subRange.endIndex, + boundsStart: startIndex, boundsEnd: endIndex) + base.replaceRange(subRange, with: newElements) + startIndex = base.startIndex.advancedBy(startOffset) + endIndex = base.startIndex.advancedBy(endOffset) + } +} + +% end + +// ${'Local Variables'}: +// eval: (read-only-mode 1) +// End: diff --git a/stdlib/private/StdlibCollectionUnittest/StdlibCollectionUnittest.swift b/stdlib/private/StdlibCollectionUnittest/StdlibCollectionUnittest.swift new file mode 100644 index 0000000000000..d96a8e690f45a --- /dev/null +++ b/stdlib/private/StdlibCollectionUnittest/StdlibCollectionUnittest.swift @@ -0,0 +1,22 @@ +//===--- StdlibCollectionUnittest.swift -----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + diff --git a/stdlib/private/StdlibUnittest/CMakeLists.txt b/stdlib/private/StdlibUnittest/CMakeLists.txt index 936188672b168..d029a5bc834eb 100644 --- a/stdlib/private/StdlibUnittest/CMakeLists.txt +++ b/stdlib/private/StdlibUnittest/CMakeLists.txt @@ -3,6 +3,7 @@ set(swift_stdlib_unittest_module_depends SwiftPrivate SwiftPrivatePthreadExtras SwiftPrivateDarwinExtras) set(swift_stdlib_unittest_framework_depends) set(swift_stdlib_unittest_private_link_libraries) +set(swift_stdlib_unittest_compile_flags) if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") list(APPEND swift_stdlib_unittest_platform_sources @@ -13,21 +14,19 @@ if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") list(APPEND swift_stdlib_unittest_framework_depends Foundation) endif() -if(SWIFT_HOST_VARIANT STREQUAL "linux") +if(SWIFT_HOST_VARIANT STREQUAL "linux" OR SWIFT_HOST_VARIANT STREQUAL "freebsd") list(APPEND swift_stdlib_unittest_module_depends Glibc) endif() +if(SWIFT_SERIALIZE_STDLIB_UNITTEST) + list(APPEND swift_stdlib_unittest_compile_flags "-Xfrontend" "-sil-serialize-all") +endif() add_swift_library(swiftStdlibUnittest SHARED IS_STDLIB # This file should be listed the first. Module name is inferred from the # filename. StdlibUnittest.swift.gyb - CheckCollectionType.swift - CheckMutableCollectionType.swift.gyb - CheckRangeReplaceableCollectionType.swift - CheckRangeReplaceableSliceType.swift - CheckSequenceType.swift InterceptTraps.cpp LoggingWrappers.swift.gyb OpaqueIdentityFunctions.cpp @@ -40,14 +39,9 @@ add_swift_library(swiftStdlibUnittest SHARED IS_STDLIB LifetimeTracked.swift ${swift_stdlib_unittest_platform_sources} - # Can not serialize StdlibUnittest because of: - # Compiling StdlibUnittest with -sil-serialize-all - # crashes in SIL serializer - # - # SWIFT_COMPILE_FLAGS -Xfrontend -sil-serialize-all - PRIVATE_LINK_LIBRARIES ${swift_stdlib_unittest_private_link_libraries} SWIFT_MODULE_DEPENDS ${swift_stdlib_unittest_module_depends} + SWIFT_COMPILE_FLAGS ${swift_stdlib_unittest_compile_flags} FRAMEWORK_DEPENDS ${swift_stdlib_unittest_framework_depends} INSTALL_IN_COMPONENT stdlib-experimental) diff --git a/stdlib/private/StdlibUnittest/GetOSVersion.mm b/stdlib/private/StdlibUnittest/GetOSVersion.mm index 8e36cc41bf999..1ba1507ba9465 100644 --- a/stdlib/private/StdlibUnittest/GetOSVersion.mm +++ b/stdlib/private/StdlibUnittest/GetOSVersion.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/StdlibUnittest/InterceptTraps.cpp b/stdlib/private/StdlibUnittest/InterceptTraps.cpp index 19ec7327c9a20..7252287a12d30 100644 --- a/stdlib/private/StdlibUnittest/InterceptTraps.cpp +++ b/stdlib/private/StdlibUnittest/InterceptTraps.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/StdlibUnittest/LifetimeTracked.swift b/stdlib/private/StdlibUnittest/LifetimeTracked.swift index 4f7290bcbf1a6..341b814912485 100644 --- a/stdlib/private/StdlibUnittest/LifetimeTracked.swift +++ b/stdlib/private/StdlibUnittest/LifetimeTracked.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,15 +12,16 @@ public final class LifetimeTracked : ForwardIndexType, CustomStringConvertible { public init(_ value: Int, identity: Int = 0) { - ++LifetimeTracked.instances - serialNumber = ++LifetimeTracked._nextSerialNumber + LifetimeTracked.instances += 1 + LifetimeTracked._nextSerialNumber += 1 + serialNumber = LifetimeTracked._nextSerialNumber self.value = value self.identity = identity } deinit { assert(serialNumber > 0, "double destruction!") - --LifetimeTracked.instances + LifetimeTracked.instances -= 1 serialNumber = -serialNumber } diff --git a/stdlib/private/StdlibUnittest/LoggingWrappers.swift.gyb b/stdlib/private/StdlibUnittest/LoggingWrappers.swift.gyb index 0322e8deed2e3..11d3d43b44477 100644 --- a/stdlib/private/StdlibUnittest/LoggingWrappers.swift.gyb +++ b/stdlib/private/StdlibUnittest/LoggingWrappers.swift.gyb @@ -1,8 +1,8 @@ -//===--- LoggingWrappers.swift ---------------------------------------===// +//===--- LoggingWrappers.swift.gyb ----------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,13 +11,13 @@ //===----------------------------------------------------------------------===// public protocol WrapperType { - typealias Base + associatedtype Base init(_: Base) var base: Base {get set} } public protocol LoggingType : WrapperType { - typealias Log : AnyObject + associatedtype Log : AnyObject } extension LoggingType { @@ -49,7 +49,7 @@ public struct LoggingGenerator } public mutating func next() -> Base.Element? { - ++Log.next[selfType] + Log.next[selfType] += 1 return base.next() } @@ -99,14 +99,14 @@ public struct LoggingRangeReplaceableCollection< public init() { self.base = Base() - ++Log.init_[selfType] + Log.init_[selfType] += 1 } public init< S : SequenceType where S.Generator.Element == Generator.Element >(_ elements: S) { self.base = Base(elements) - ++Log.initWithSequence[selfType] + Log.initWithSequence[selfType] += 1 } public init(_ base: Base) { @@ -142,73 +142,73 @@ public struct LoggingRangeReplaceableCollection< >( subRange: Range, with newElements: C ) { - ++Log.replaceRange[selfType] + Log.replaceRange[selfType] += 1 base.replaceRange(subRange, with: newElements) } public mutating func append(newElement: Base.Generator.Element) { - ++Log.append[selfType] + Log.append[selfType] += 1 base.append(newElement) } public mutating func appendContentsOf< S : SequenceType where S.Generator.Element == Base.Generator.Element >(newElements: S) { - ++Log.appendContentsOf[selfType] + Log.appendContentsOf[selfType] += 1 base.appendContentsOf(newElements) } public mutating func insert( newElement: Base.Generator.Element, atIndex i: Base.Index ) { - ++Log.insert[selfType] + Log.insert[selfType] += 1 base.insert(newElement, atIndex: i) } public mutating func removeAtIndex(index: Base.Index) -> Base.Generator.Element { - ++Log.removeAtIndex[selfType] + Log.removeAtIndex[selfType] += 1 return base.removeAtIndex(index) } public mutating func _customRemoveLast() -> Base.Generator.Element? { - ++Log._customRemoveLast[selfType] + Log._customRemoveLast[selfType] += 1 return base._customRemoveLast() } public mutating func _customRemoveLast(n: Int) -> Bool { - ++Log._customRemoveLastN[selfType] + Log._customRemoveLastN[selfType] += 1 return base._customRemoveLast(n) } public mutating func removeFirst() -> Base.Generator.Element { - ++Log.removeFirst[selfType] + Log.removeFirst[selfType] += 1 return base.removeFirst() } public mutating func removeFirst(n: Int) { - ++Log.removeFirstN[selfType] + Log.removeFirstN[selfType] += 1 base.removeFirst(n) } public mutating func removeRange(subRange: Range) { - ++Log.removeRange[selfType] + Log.removeRange[selfType] += 1 base.removeRange(subRange) } public mutating func removeAll(keepCapacity keepCapacity: Bool) { - ++Log.removeAll[selfType] + Log.removeAll[selfType] += 1 base.removeAll(keepCapacity: keepCapacity) } public mutating func reserveCapacity(n: Base.Index.Distance) { - ++Log.reserveCapacity[selfType] + Log.reserveCapacity[selfType] += 1 base.reserveCapacity(n) } public mutating func insertContentsOf< C : CollectionType where C.Generator.Element == Base.Generator.Element >(newElements: C, at i: Base.Index) { - ++Log.insertContentsOf[selfType] + Log.insertContentsOf[selfType] += 1 base.insertContentsOf(newElements, at: i) } @@ -331,30 +331,30 @@ public struct Logging${Kind}< } public func successor() -> Logging${Kind} { - ++Log.successor[selfType] + Log.successor[selfType] += 1 return Logging${Kind}(base.successor()) } % if Kind == 'BidirectionalIndex' or Kind == 'RandomAccessIndex': public func predecessor() -> Logging${Kind} { - ++Log.predecessor[selfType] + Log.predecessor[selfType] += 1 return Logging${Kind}(base.predecessor()) } % end public func distanceTo(end: Logging${Kind}) -> Base.Distance { - ++Log.distanceTo[selfType] + Log.distanceTo[selfType] += 1 return base.distanceTo(end.base) } public func advancedBy(n: Base.Distance) -> Logging${Kind} { - ++Log.advancedBy[selfType] + Log.advancedBy[selfType] += 1 return Logging${Kind}(base.advancedBy(n)) } public func advancedBy(n: Base.Distance, limit: Logging${Kind}) -> Logging${Kind} { - ++Log.advancedByWithLimit[selfType] + Log.advancedByWithLimit[selfType] += 1 return Logging${Kind}(base.advancedBy(n, limit: limit.base)) } } @@ -376,23 +376,23 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { % if Kind == 'Collection' or Kind == 'MutableCollection': public var startIndex: Base.Index { - ++Log.startIndex[selfType] + Log.startIndex[selfType] += 1 return base.startIndex } public var endIndex: Base.Index { - ++Log.endIndex[selfType] + Log.endIndex[selfType] += 1 return base.endIndex } public subscript(position: Base.Index) -> Base.Generator.Element { get { - ++Log.subscriptIndex[selfType] + Log.subscriptIndex[selfType] += 1 return base[position] } % if Kind == 'MutableCollection': set { - ++Log.subscriptIndexSet[selfType] + Log.subscriptIndexSet[selfType] += 1 base[position] = newValue } % end @@ -400,36 +400,36 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { public subscript(bounds: Range) -> Base.SubSequence { get { - ++Log.subscriptRange[selfType] + Log.subscriptRange[selfType] += 1 return base[bounds] } % if Kind == 'MutableCollection': set { - ++Log.subscriptRangeSet[selfType] + Log.subscriptRangeSet[selfType] += 1 base[bounds] = newValue } % end } public var isEmpty: Bool { - ++Log.isEmpty[selfType] + Log.isEmpty[selfType] += 1 return base.isEmpty } public var count: Base.Index.Distance { - ++Log.count[selfType] + Log.count[selfType] += 1 return base.count } public func _customIndexOfEquatableElement( element: Base.Generator.Element ) -> Base.Index?? { - ++Log._customIndexOfEquatableElement[selfType] + Log._customIndexOfEquatableElement[selfType] += 1 return base._customIndexOfEquatableElement(element) } public var first: Base.Generator.Element? { - ++Log.first[selfType] + Log.first[selfType] += 1 return base.first } % end @@ -438,29 +438,29 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { public mutating func _withUnsafeMutableBufferPointerIfSupported( @noescape body: (UnsafeMutablePointer, Int) throws -> R ) rethrows -> R? { - ++Log._withUnsafeMutableBufferPointerIfSupported[selfType] + Log._withUnsafeMutableBufferPointerIfSupported[selfType] += 1 let result = try base._withUnsafeMutableBufferPointerIfSupported(body) if result != nil { - ++Log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[selfType] + Log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[selfType] += 1 } return result } % end public func generate() -> LoggingGenerator { - ++Log.generate[selfType] + Log.generate[selfType] += 1 return LoggingGenerator(base.generate()) } public func underestimateCount() -> Int { - ++Log.underestimateCount[selfType] + Log.underestimateCount[selfType] += 1 return base.underestimateCount() } public func forEach( @noescape body: (Base.Generator.Element) throws -> Void ) rethrows { - ++Log.forEach[selfType] + Log.forEach[selfType] += 1 try base.forEach(body) } @@ -468,7 +468,7 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { public func map( @noescape transform: (Base.Generator.Element) throws -> T ) rethrows -> [T] { - ++Log.map[selfType] + Log.map[selfType] += 1 return try base.map(transform) } @@ -476,27 +476,27 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { public func filter( @noescape includeElement: (Base.Generator.Element) throws -> Bool ) rethrows -> [Base.Generator.Element] { - ++Log.filter[selfType] + Log.filter[selfType] += 1 return try base.filter(includeElement) } public func dropFirst(n: Int) -> Base.SubSequence { - ++Log.dropFirst[selfType] + Log.dropFirst[selfType] += 1 return base.dropFirst(n) } public func dropLast(n: Int) -> Base.SubSequence { - ++Log.dropLast[selfType] + Log.dropLast[selfType] += 1 return base.dropLast(n) } public func prefix(maxLength: Int) -> Base.SubSequence { - ++Log.prefix[selfType] + Log.prefix[selfType] += 1 return base.prefix(maxLength) } public func suffix(maxLength: Int) -> Base.SubSequence { - ++Log.suffix[selfType] + Log.suffix[selfType] += 1 return base.suffix(maxLength) } @@ -505,7 +505,7 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { allowEmptySlices: Bool = false, @noescape isSeparator: (Base.Generator.Element) throws -> Bool ) rethrows -> [Base.SubSequence] { - ++Log.split[selfType] + Log.split[selfType] += 1 return try base.split(maxSplit, allowEmptySlices: allowEmptySlices, isSeparator: isSeparator) } @@ -513,17 +513,17 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { % if Kind == 'Collection' or Kind == 'MutableCollection': public func prefixUpTo(end: Index) -> Base.SubSequence { - ++Log.prefixUpTo[selfType] + Log.prefixUpTo[selfType] += 1 return base.prefixUpTo(end) } public func suffixFrom(start: Index) -> Base.SubSequence { - ++Log.suffixFrom[selfType] + Log.suffixFrom[selfType] += 1 return base.suffixFrom(start) } public func prefixThrough(position: Index) -> Base.SubSequence { - ++Log.prefixThrough[selfType] + Log.prefixThrough[selfType] += 1 return base.prefixThrough(position) } @@ -532,7 +532,7 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { public func _customContainsEquatableElement( element: Base.Generator.Element ) -> Bool? { - ++Log._customContainsEquatableElement[selfType] + Log._customContainsEquatableElement[selfType] += 1 return base._customContainsEquatableElement(element) } @@ -540,9 +540,9 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { /// `preprocess` on `self` and return its result. Otherwise, return /// `nil`. public func _preprocessingPass( - preprocess: (Logging${Kind})->R + @noescape preprocess: (Logging${Kind}) -> R ) -> R? { - ++Log._preprocessingPass[selfType] + Log._preprocessingPass[selfType] += 1 return base._preprocessingPass { _ in preprocess(self) } } @@ -550,14 +550,14 @@ public struct Logging${Kind} : ${Kind}Type, LoggingType { /// in the same order. public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { - ++Log._copyToNativeArrayBuffer[selfType] + Log._copyToNativeArrayBuffer[selfType] += 1 return base._copyToNativeArrayBuffer() } /// Copy a Sequence into an array. public func _initializeTo(ptr: UnsafeMutablePointer) -> UnsafeMutablePointer { - ++Log._initializeTo[selfType] + Log._initializeTo[selfType] += 1 return base._initializeTo(ptr) } @@ -572,7 +572,7 @@ public func expectCustomizable< T.Log == T.Base.Log >(_: T, _ counters: TypeIndexed, //===--- TRACE boilerplate ----------------------------------------------===// - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ @@ -590,7 +590,7 @@ public func expectNotCustomizable< T.Log == T.Base.Log >(_: T, _ counters: TypeIndexed, //===--- TRACE boilerplate ----------------------------------------------===// - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ diff --git a/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.cpp b/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.cpp index c30dfddc56bb0..7c8790e6db6a0 100644 --- a/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.cpp +++ b/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.swift b/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.swift index 2bc2048b568a4..7bb8727527b49 100644 --- a/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.swift +++ b/stdlib/private/StdlibUnittest/OpaqueIdentityFunctions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index 2def6e0b1a055..12cb15e5b0289 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -40,7 +40,7 @@ import SwiftPrivate import SwiftPrivatePthreadExtras #if os(OSX) || os(iOS) import Darwin -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) import Glibc #endif @@ -68,15 +68,15 @@ public protocol RaceTestWithPerTrialDataType { /// /// This type should be a class. (The harness will not pass struct instances /// between threads correctly.) - typealias RaceData : AnyObject + associatedtype RaceData : AnyObject /// Type of thread-local data. /// /// Thread-local data is newly created for every trial. - typealias ThreadLocalData + associatedtype ThreadLocalData /// Results of the observation made after performing an operation. - typealias Observation + associatedtype Observation init() @@ -501,8 +501,8 @@ public func runRaceTest( let racingThreadCount = threads ?? max(2, _stdlib_getHardwareConcurrency()) let sharedState = _RaceTestSharedState(racingThreadCount: racingThreadCount) - let masterThreadBody: (_: ())->() = { - (_: ())->() in + let masterThreadBody: () -> Void = { + () -> Void in for _ in 0..( } } - let racingThreadBody: (Int)->() = { - (tid: Int)->() in + let racingThreadBody: (Int) -> Void = { + (tid: Int) -> Void in for _ in 0.. String.Index? { } if needle[needleIndex] == haystack[matchIndex] { // keep advancing through both the string and search string on match - ++matchIndex - ++needleIndex + matchIndex = matchIndex.successor() + needleIndex = needleIndex.successor() } else { // no match, go back to finding a starting match in the string. break diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb index 40756b43b7041..a0487e7613505 100644 --- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb +++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,7 +16,7 @@ import SwiftPrivateDarwinExtras #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) import Glibc #endif @@ -87,7 +87,7 @@ public struct SourceLocStack { } %{ - TRACE = '''@autoclosure _ message: ()->String = "", + TRACE = '''@autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__''' @@ -166,7 +166,7 @@ public func expectationFailure( } public func expectEqual( - expected: T, _ actual: T, ${TRACE}, sameValue equal: (T,T)->Bool + expected: T, _ actual: T, ${TRACE}, sameValue equal: (T,T) -> Bool ) { if !equal(expected, actual) { expectationFailure( @@ -186,7 +186,7 @@ public func expectNotEqual(expected: T, _ actual: T, ${TRACE}) { } } -// Can not write a sane set of overloads using generics because of: +// Cannot write a sane set of overloads using generics because of: // Array->NSArray implicit conversion insanity public func expectOptionalEqual( expected: T, _ actual: T?, ${TRACE} @@ -195,7 +195,7 @@ public func expectOptionalEqual( } public func expectOptionalEqual( - expected: T, _ actual: T?, ${TRACE}, sameValue equal: (T,T)->Bool + expected: T, _ actual: T?, ${TRACE}, sameValue equal: (T,T) -> Bool ) { if (actual == nil) || !equal(expected, actual!) { expectationFailure( @@ -477,15 +477,17 @@ struct _ParentProcess { internal var _runTestsInProcess: Bool internal var _filter: String? + internal var _args: [String] - init(runTestsInProcess: Bool, filter: String?) { + init(runTestsInProcess: Bool, args: [String], filter: String?) { self._runTestsInProcess = runTestsInProcess self._filter = filter + self._args = args } mutating func _spawnChild() { - let (pid, childStdinFD, childStdoutFD, childStderrFD) = - spawnChild([ "--stdlib-unittest-run-child" ]) + let params = [ "--stdlib-unittest-run-child" ] + _args + let (pid, childStdinFD, childStdoutFD, childStderrFD) = spawnChild(params) _pid = pid _childStdin = _FDOutputStream(fd: childStdinFD) _childStdout = _FDInputStream(fd: childStdoutFD) @@ -756,17 +758,58 @@ struct _ParentProcess { } } -public func runAllTests() { - struct PersistentState { - static var runAllTestsWasCalled: Bool = false +// Track repeated calls to runAllTests() and/or runNoTests(). +// Complain if a file runs no tests without calling runNoTests(). +struct PersistentState { + static var runAllTestsWasCalled: Bool = false + static var runNoTestsWasCalled: Bool = false + static var ranSomething: Bool = false + static var complaintInstalled = false + + static func complainIfNothingRuns() { + if !complaintInstalled { + complaintInstalled = true + atexit { + if !PersistentState.ranSomething { + print("Ran no tests and runNoTests() was not called. Aborting. ") + print("Did you forget to call runAllTests()?") + _testSuiteFailedCallback() + } + } + } + } +} + + +// Call runNoTests() if you want to deliberately run no tests. +public func runNoTests() { + if PersistentState.runAllTestsWasCalled { + print("runNoTests() called after runAllTests(). Aborting.") + _testSuiteFailedCallback() + return + } + if PersistentState.runNoTestsWasCalled { + print("runNoTests() called twice. Aborting.") + _testSuiteFailedCallback() + return } + PersistentState.runNoTestsWasCalled = true + PersistentState.ranSomething = true +} +public func runAllTests() { + if PersistentState.runNoTestsWasCalled { + print("runAllTests() called after runNoTests(). Aborting.") + _testSuiteFailedCallback() + return + } if PersistentState.runAllTestsWasCalled { - print("runAllTests() called twice. It is not allowed, aborting.") + print("runAllTests() called twice. Aborting.") _testSuiteFailedCallback() return } PersistentState.runAllTestsWasCalled = true + PersistentState.ranSomething = true #if _runtime(_ObjC) autoreleasepool { @@ -782,11 +825,14 @@ public func runAllTests() { } else { var runTestsInProcess: Bool = false var filter: String? = nil - for var i = 0; i < Process.arguments.count; { + var args = [String]() + var i = 0 + i += 1 // Skip the name of the executable. + while i < Process.arguments.count { let arg = Process.arguments[i] if arg == "--stdlib-unittest-in-process" { runTestsInProcess = true - ++i + i += 1 continue } if arg == "--stdlib-unittest-filter" { @@ -807,12 +853,14 @@ public func runAllTests() { return } - // FIXME: skipping unrecognized parameters. - ++i + // Pass through unparsed arguments to the child process. + args.append(Process.arguments[i]) + + i += 1 } var parent = _ParentProcess( - runTestsInProcess: runTestsInProcess, filter: filter) + runTestsInProcess: runTestsInProcess, args: args, filter: filter) parent.run() } } @@ -825,6 +873,7 @@ public class TestSuite { "test suite with the same name already exists") _allTestSuites.append(self) _testSuiteNameToIndex[name] = _allTestSuites.count - 1 + PersistentState.complainIfNothingRuns() } public func test( @@ -853,6 +902,7 @@ public class TestSuite { } func _runTest(testName: String) { + PersistentState.ranSomething = true for r in _allResettables { r.reset() } @@ -985,6 +1035,7 @@ public enum OSVersion : CustomStringConvertible { case TVOSSimulator case watchOSSimulator case Linux + case FreeBSD public var description: String { switch self { @@ -1004,6 +1055,8 @@ public enum OSVersion : CustomStringConvertible { return "watchOSSimulator" case Linux: return "Linux" + case FreeBSD: + return "FreeBSD" } } } @@ -1036,22 +1089,22 @@ func _getOSVersion() -> OSVersion { return .watchOSSimulator #elseif os(Linux) return .Linux +#elseif os(FreeBSD) + return .FreeBSD #else - let productName = _stdlib_getSystemVersionPlistProperty("ProductName")! let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")! let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion) - switch productName { - case "Mac OS X": - return .OSX(major: major, minor: minor, bugFix: bugFix) - case "iPhone OS": - return .iOS(major: major, minor: minor, bugFix: bugFix) - case "Apple TVOS": - return .TVOS(major: major, minor: minor, bugFix: bugFix) - case "Watch OS": - return .watchOS(major: major, minor: minor, bugFix: bugFix) - default: - fatalError("could not determine OS version") - } + #if os(OSX) + return .OSX(major: major, minor: minor, bugFix: bugFix) + #elseif os(iOS) + return .iOS(major: major, minor: minor, bugFix: bugFix) + #elseif os(tvOS) + return .TVOS(major: major, minor: minor, bugFix: bugFix) + #elseif os(watchOS) + return .watchOS(major: major, minor: minor, bugFix: bugFix) + #else + fatalError("could not determine OS version") + #endif #endif } @@ -1071,6 +1124,9 @@ func _getRunningOSVersion() -> OSVersion { public enum TestRunPredicate : CustomStringConvertible { case Custom(() -> Bool, reason: String) + case Always(/*reason:*/ String) + case Never + case OSXAny(/*reason:*/ String) case OSXMajor(Int, reason: String) case OSXMinor(Int, Int, reason: String) @@ -1107,10 +1163,18 @@ public enum TestRunPredicate : CustomStringConvertible { case LinuxAny(reason: String) + case FreeBSDAny(reason: String) + public var description: String { switch self { case Custom(_, let reason): return "Custom(reason: \(reason))" + + case Always(let reason): + return "Always(reason: \(reason))" + case Never: + return "" + case OSXAny(let reason): return "OSX(*, reason: \(reason))" case OSXMajor(let major, let reason): @@ -1174,6 +1238,9 @@ public enum TestRunPredicate : CustomStringConvertible { case LinuxAny(reason: let reason): return "LinuxAny(*, reason: \(reason))" + + case FreeBSDAny(reason: let reason): + return "FreeBSDAny(*, reason: \(reason))" } } @@ -1182,6 +1249,11 @@ public enum TestRunPredicate : CustomStringConvertible { case Custom(let predicate, _): return predicate() + case Always: + return true + case Never: + return false + case OSXAny: switch _getRunningOSVersion() { case .OSX: @@ -1405,6 +1477,14 @@ public enum TestRunPredicate : CustomStringConvertible { default: return false } + + case FreeBSDAny: + switch _getRunningOSVersion() { + case .FreeBSD: + return true + default: + return false + } } } } @@ -1477,7 +1557,7 @@ public func checkHashable< Instances: CollectionType where Instances.Generator.Element : Hashable >( instances: Instances, - equalityOracle: (Instances.Index, Instances.Index)->Bool, + equalityOracle: (Instances.Index, Instances.Index) -> Bool, ${TRACE} ) { checkEquatable(instances, oracle: equalityOracle, ${trace}) @@ -1498,9 +1578,9 @@ public func checkHashable( [lhs, rhs], equalityOracle: { expectedEqual || $0 == $1 }, ${trace}) } -% for inc, protocol, op, successor, end in ( -% ('inc', '_Incrementable', '++', 'successor', 'end'), -% ('dec', 'BidirectionalIndexType', '--', 'predecessor', 'start')): +% for inc, protocol, successor, end in ( +% ('inc', '_Incrementable', 'successor', 'end'), +% ('dec', 'BidirectionalIndexType', 'predecessor', 'start')): /// Test that the elements of `instances` satisfy /// ${'some of ' if inc == 'dec' else ''}the semantic @@ -1516,7 +1596,7 @@ public func check${inc.capitalize()}rementable< where Instances.Generator.Element : ${protocol} >( instances: Instances, - equalityOracle: (Instances.Index, Instances.Index)->Bool, + equalityOracle: (Instances.Index, Instances.Index) -> Bool, ${end}Index: Instances.Generator.Element, ${TRACE} ) { checkEquatable(instances, oracle: equalityOracle, ${trace}) @@ -1530,16 +1610,6 @@ public func check${inc.capitalize()}rementable< var j = i j._${successor}InPlace() expectEqual(j, next, ${trace}) - - // Post-${inc}rement works - j = i - expectEqual(j${op}, i, ${trace}) - expectEqual(j, next, ${trace}) - - // Pre-${inc}rement works - j = i - expectEqual(${op}j, next, ${trace}) - expectEqual(j, next, ${trace}) } } } @@ -1735,10 +1805,10 @@ internal func _checkIncrementalAdvance< Instances: CollectionType where Instances.Generator.Element : ForwardIndexType >( instances: Instances, - equalityOracle: (Instances.Index, Instances.Index)->Bool, + equalityOracle: (Instances.Index, Instances.Index) -> Bool, limit: Instances.Generator.Element, sign: Instances.Generator.Element.Distance, // 1 or -1 - next: (Instances.Generator.Element)->Instances.Generator.Element, + next: (Instances.Generator.Element) -> Instances.Generator.Element, ${TRACE} ) { for i in instances { @@ -1769,7 +1839,7 @@ public func checkForwardIndex< Instances: CollectionType where Instances.Generator.Element : ForwardIndexType >( instances: Instances, - equalityOracle: (Instances.Index, Instances.Index)->Bool, + equalityOracle: (Instances.Index, Instances.Index) -> Bool, endIndex: Instances.Generator.Element, ${TRACE} ) { typealias Index = Instances.Generator.Element @@ -1795,7 +1865,7 @@ public func checkBidirectionalIndex< where Instances.Generator.Element : BidirectionalIndexType >( instances: Instances, - equalityOracle: (Instances.Index, Instances.Index)->Bool, + equalityOracle: (Instances.Index, Instances.Index) -> Bool, startIndex: Instances.Generator.Element, endIndex: Instances.Generator.Element, ${TRACE} @@ -1919,15 +1989,16 @@ public func checkSequence< // Check that _initializeTo does the right thing if we can do so // without destroying the sequence. - sequence._preprocessingPass { (sequence)->Void in + sequence._preprocessingPass { (sequence) -> Void in var count = 0 - for _ in sequence { ++count } + for _ in sequence { count += 1 } let buf = UnsafeMutablePointer.alloc(count) let end = sequence._initializeTo(buf) expectTrue(end == buf + count, "_initializeTo returned the wrong value") var j = expected.startIndex for i in 0..<(end - buf) { - expectTrue(sameValue(expected[j++], buf[i])) + expectTrue(sameValue(expected[j], buf[i])) + j = j.successor() } buf.destroy(end - buf) buf.dealloc(count) @@ -2012,12 +2083,12 @@ public func check${traversal}Collection< var i = i if n < 0 { for _ in 0 ..< -(n.toIntMax()) { - --i + i -= 1 } } else { for _ in 0..( - makeCollection: ()->C, - _ makeNewValues: (Int)->N + makeCollection: () -> C, + _ makeNewValues: (Int) -> N ) { typealias A = C @@ -2286,7 +2357,7 @@ public func expectEqualSequence< Actual: SequenceType where Expected.Generator.Element == Actual.Generator.Element >(expected: Expected, _ actual: Actual, ${TRACE}, - sameValue: (Expected.Generator.Element, Expected.Generator.Element)->Bool) { + sameValue: (Expected.Generator.Element, Expected.Generator.Element) -> Bool) { if !expected.elementsEqual(actual, isEquivalent: sameValue) { expectationFailure("expected elements: \"\(expected)\"\n" @@ -2460,1487 +2531,138 @@ func compose(f: A -> B, _ g: B -> C) -> A -> C { } } -/// State that is created every time a fresh generator is created with -/// `MinimalSequence.generate()`. -internal class _MinimalGeneratorPrivateState { - internal init() {} - - internal var returnedNilCounter: Int = 0 -} - -/// State shared by all generators of a MinimalSequence. -internal class _MinimalGeneratorSharedState { - internal init(_ data: [T]) { - self.data = data - } - - internal let data: [T] - internal var i: Int = 0 - internal var underestimatedCount: Int = 0 -} - -//===----------------------------------------------------------------------===// -// MinimalGenerator -//===----------------------------------------------------------------------===// - -/// A GeneratorType that implements the protocol contract in the most -/// narrow way possible. +/// A type that does not conform to any protocols. /// -/// This generator will return `nil` only once. -public struct MinimalGenerator : GeneratorType { - public init(_ s: S) { - self._sharedState = _MinimalGeneratorSharedState(Array(s)) - } - - public init(_ data: [T]) { - self._sharedState = _MinimalGeneratorSharedState(data) - } - - internal init(_ _sharedState: _MinimalGeneratorSharedState) { - self._sharedState = _sharedState - } - - public func next() -> T? { - if _sharedState.i == _sharedState.data.count { - if isConsumed { - expectUnreachable("next() was called on a consumed generator") - } - ++_privateState.returnedNilCounter - return nil - } - return _sharedState.data[_sharedState.i++] - } - - public var isConsumed: Bool { - return returnedNilCounter >= 1 - } - - public var returnedNilCounter: Int { - return _privateState.returnedNilCounter - } - - internal let _privateState: _MinimalGeneratorPrivateState = - _MinimalGeneratorPrivateState() - internal let _sharedState: _MinimalGeneratorSharedState -} - -// A protocol to identify MinimalGenerator. -public protocol _MinimalGeneratorType {} -extension MinimalGenerator : _MinimalGeneratorType {} - -//===----------------------------------------------------------------------===// -// MinimalSequence -//===----------------------------------------------------------------------===// - -public enum UnderestimateCountBehavior { - /// Return the actual number of elements. - case Precise - - /// Return the actual number of elements divided by 2. - case Half - - /// Return an overestimated count. Useful to test how algorithms reserve - /// memory. - case Overestimate - - /// Return the provided value. - case Value(Int) -} - -public protocol StrictSequenceType : SequenceType { - typealias Element - init(base: MinimalSequence) - var base: MinimalSequence { get } -} - -extension StrictSequenceType { - public init( - elements: S, - underestimatedCount: UnderestimateCountBehavior = .Value(0) - ) { - self.init(base: MinimalSequence( - elements: elements, underestimatedCount: underestimatedCount)) - } +/// This type can be used to check that generic functions don't rely on any +/// conformances. +public struct OpaqueValue { + public var value: Underlying + public var identity: Int - public func underestimateCount() -> Int { - return base.underestimateCount() + public init(_ value: Underlying) { + self.value = value + self.identity = 0 } -} -extension StrictSequenceType where Generator : _MinimalGeneratorType { - public func generate() -> MinimalGenerator { - return base.generate() + public init(_ value: Underlying, identity: Int) { + self.value = value + self.identity = identity } } -/// A SequenceType that implements the protocol contract in the most -/// narrow way possible. +/// A type that conforms only to `Equatable`. /// -/// This sequence is consumed when its generator is advanced. -public struct MinimalSequence : SequenceType, CustomDebugStringConvertible { - public init( - elements: S, - underestimatedCount: UnderestimateCountBehavior = .Value(0) - ) { - let data = Array(elements) - self._sharedState = _MinimalGeneratorSharedState(data) - - switch underestimatedCount { - case .Precise: - self._sharedState.underestimatedCount = data.count - - case .Half: - self._sharedState.underestimatedCount = data.count / 2 - - case .Overestimate: - self._sharedState.underestimatedCount = data.count * 3 + 5 - - case .Value(let count): - self._sharedState.underestimatedCount = count - } - } - - public func generate() -> MinimalGenerator { - return MinimalGenerator(_sharedState) - } +/// This type can be used to check that generic functions don't rely on any +/// other conformances. +public struct MinimalEquatableValue : Equatable { + public static var timesEqualEqualWasCalled: Int = 0 - public func underestimateCount() -> Int { - return max(0, self._sharedState.underestimatedCount - self._sharedState.i) - } + public var value: Int + public var identity: Int - public var debugDescription: String { - return "MinimalSequence(\(_sharedState.data[_sharedState.i..<_sharedState.data.count]))" + public init(_ value: Int) { + self.value = value + self.identity = 0 } - internal let _sharedState: _MinimalGeneratorSharedState -} - -//===----------------------------------------------------------------------===// -// Index invalidation checking -//===----------------------------------------------------------------------===// - -internal enum _CollectionOperation : Equatable { - case ReserveCapacity(capacity: Int) - case Append - case AppendContentsOf(count: Int) - case ReplaceRange(subRange: Range, replacementCount: Int) - case Insert(atIndex: Int) - case InsertContentsOf(atIndex: Int, count: Int) - case RemoveAtIndex(index: Int) - case RemoveLast - case RemoveRange(subRange: Range) - case RemoveAll(keepCapacity: Bool) - - internal func _applyTo( - elementsLastMutatedStateIds: [Int], nextStateId: Int) -> [Int] { - var result = elementsLastMutatedStateIds - switch self { - case ReserveCapacity: - let invalidIndices = result.indices - result.replaceRange( - invalidIndices, - with: Repeat(count: invalidIndices.count, repeatedValue: nextStateId)) - - case Append: - result.append(nextStateId) - - case AppendContentsOf(let count): - result.appendContentsOf( - Repeat(count: count, repeatedValue: nextStateId)) - - case ReplaceRange(let subRange, let replacementCount): - result.replaceRange( - subRange, - with: Repeat(count: replacementCount, repeatedValue: nextStateId)) - - let invalidIndices = subRange.startIndex.. Bool { - switch (lhs, rhs) { - case (.ReserveCapacity(let lhsCapacity), .ReserveCapacity(let rhsCapacity)): - return lhsCapacity == rhsCapacity - - case (.Append, .Append): - return true - - case (.AppendContentsOf(let lhsCount), .AppendContentsOf(let rhsCount)): - return lhsCount == rhsCount - - case ( - .ReplaceRange(let lhsSubRange, let lhsReplacementCount), - .ReplaceRange(let rhsSubRange, let rhsReplacementCount)): - - return lhsSubRange == rhsSubRange && - lhsReplacementCount == rhsReplacementCount - - case (.Insert(let lhsAtIndex), .Insert(let rhsAtIndex)): - return lhsAtIndex == rhsAtIndex - - case ( - .InsertContentsOf(let lhsAtIndex, let lhsCount), - .InsertContentsOf(let rhsAtIndex, let rhsCount)): - - return lhsAtIndex == rhsAtIndex && lhsCount == rhsCount - - case (.RemoveAtIndex(let lhsIndex), .RemoveAtIndex(let rhsIndex)): - return lhsIndex == rhsIndex - - case (.RemoveLast, .RemoveLast): - return true - - case (.RemoveRange(let lhsSubRange), .RemoveRange(let rhsSubRange)): - return lhsSubRange == rhsSubRange - - case (.RemoveAll(let lhsKeepCapacity), .RemoveAll(let rhsKeepCapacity)): - return lhsKeepCapacity == rhsKeepCapacity - - default: - return false - } -} - -public struct _CollectionState : Equatable, Hashable { - internal static var _nextUnusedState: Int = 0 - internal static var _namedStates: [String : _CollectionState] = [:] - - internal let _id: Int - internal let _elementsLastMutatedStateIds: [Int] - - internal init(id: Int, elementsLastMutatedStateIds: [Int]) { - self._id = id - self._elementsLastMutatedStateIds = elementsLastMutatedStateIds - } - - internal init(newRootStateForElementCount count: Int) { - self._id = _CollectionState._nextUnusedState++ - self._elementsLastMutatedStateIds = - Array(Repeat(count: count, repeatedValue: self._id)) - } - - internal init(name: String, elementCount: Int) { - if let result = _CollectionState._namedStates[name] { - self = result - } else { - self = _CollectionState(newRootStateForElementCount: elementCount) - _CollectionState._namedStates[name] = self - } - } - - public var hashValue: Int { - return _id.hashValue - } + MinimalEquatableValue.timesEqualEqualWasCalled += 1 + return lhs.value == rhs.value } -public func == (lhs: _CollectionState, rhs: _CollectionState) -> Bool { - return lhs._id == rhs._id -} +/// A type that conforms only to `Equatable` and `Comparable`. +/// +/// This type can be used to check that generic functions don't rely on any +/// other conformances. +public struct MinimalComparableValue : Equatable, Comparable { + public static var timesEqualEqualWasCalled = ResettableValue(0) + public static var timesLessWasCalled = ResettableValue(0) -internal struct _CollectionStateTransition { - internal let _previousState: _CollectionState - internal let _operation: _CollectionOperation - internal let _nextState: _CollectionState + public static var equalImpl = + ResettableValue<(Int, Int) -> Bool>({ $0 == $1 }) + public static var lessImpl = + ResettableValue<(Int, Int) -> Bool>({ $0 < $1 }) - internal static var _allTransitions: - [_CollectionState : Box<[_CollectionStateTransition]>] = [:] + public var value: Int + public var identity: Int - internal init( - previousState: _CollectionState, - operation: _CollectionOperation, - nextState: _CollectionState - ) { - var transitions = - _CollectionStateTransition._allTransitions[previousState] - if transitions == nil { - transitions = Box<[_CollectionStateTransition]>([]) - _CollectionStateTransition._allTransitions[previousState] = transitions - } - if let i = transitions!.value.indexOf({ $0._operation == operation }) { - self = transitions!.value[i] - return - } - self._previousState = previousState - self._operation = operation - self._nextState = nextState - transitions!.value.append(self) + public init(_ value: Int) { + self.value = value + self.identity = 0 } - internal init( - previousState: _CollectionState, - operation: _CollectionOperation - ) { - let nextStateId = _CollectionState._nextUnusedState++ - let newElementStates = operation._applyTo( - previousState._elementsLastMutatedStateIds, nextStateId: nextStateId) - let nextState = _CollectionState( - id: nextStateId, elementsLastMutatedStateIds: newElementStates) - self = _CollectionStateTransition( - previousState: previousState, - operation: operation, - nextState: nextState) + public init(_ value: Int, identity: Int) { + self.value = value + self.identity = identity } } -//===----------------------------------------------------------------------===// -// MinimalForwardIndex -//===----------------------------------------------------------------------===// - -/// Asserts that the two indices are allowed to participate in a binary -/// operation. -internal func _expectCompatibleIndices( - first: Index, - _ second: Index, - ${TRACE} -) { - if let firstStateId = first._collectionState?._id, - let secondStateId = second._collectionState?._id - where firstStateId == secondStateId { - - // The indices are derived from the same state. - return - } - - // The indices are derived from different states. Check that they point - // to elements that persisted from the same state. - - func getLastMutatedStateId(i: Index) -> Int? { - guard let state = i._collectionState else { return nil } - let offset = i._offset - if offset == state._elementsLastMutatedStateIds.endIndex { - return state._id - } - return state._elementsLastMutatedStateIds[offset] - } - - let firstElementLastMutatedStateId = getLastMutatedStateId(first) - let secondElementLastMutatedStateId = getLastMutatedStateId(second) - - expectEqual( - firstElementLastMutatedStateId, - secondElementLastMutatedStateId, - "Indices are not compatible:\n" + - "first: \(first)\n" + - "second: \(second)\n" + - "first element last mutated in state id: \(firstElementLastMutatedStateId)\n" + - "second element last mutated in state id: \(secondElementLastMutatedStateId)\n", - stackTrace: ${stackTrace}) - - // To make writing assertions easier, perform a trap. - if firstElementLastMutatedStateId != secondElementLastMutatedStateId { - fatalError("Indices are not compatible") - } +public func == ( + lhs: MinimalComparableValue, + rhs: MinimalComparableValue +) -> Bool { + MinimalComparableValue.timesEqualEqualWasCalled.value += 1 + return MinimalComparableValue.equalImpl.value(lhs.value, rhs.value) } -public protocol _MinimalIndexType { - /// Distance from start index. - var _offset: Int { get } - - var _collectionState: _CollectionState? { get } +public func < ( + lhs: MinimalComparableValue, + rhs: MinimalComparableValue +) -> Bool { + MinimalComparableValue.timesLessWasCalled.value += 1 + return MinimalComparableValue.lessImpl.value(lhs.value, rhs.value) } -% for Distance in [ '', 'Int32' ]: -% Index = 'MinimalForward%sIndex' % Distance - -public struct ${Index} : ForwardIndexType { -% if Distance != '': - public typealias Distance = ${Distance} -% end - - public init(position: Int, startIndex: Int, endIndex: Int) { - self = ${Index}( - collectionState: nil, - position: position, - startIndex: startIndex, - endIndex: endIndex) - } - - internal init( - collectionState: _CollectionState?, - position: Int, - startIndex: Int, - endIndex: Int - ) { - expectLE(startIndex, position) - expectGE(endIndex, position) - self._collectionState = collectionState - self.position = position - self.startIndex = startIndex - self.endIndex = endIndex - } +/// A type that conforms only to `Comparable` and `ForwardIndexType`. +/// +/// This type can be used to check that generic functions don't rely on any +/// other conformances. +public struct MinimalComparableIndexValue : Comparable, ForwardIndexType { + public static var timesEqualEqualWasCalled = 0 + public static var timesLessWasCalled = 0 - public func successor() -> ${Index} { - expectNotEqual(endIndex, position) - return ${Index}( - collectionState: _collectionState, - position: position + 1, startIndex: startIndex, endIndex: endIndex) + public func successor() -> MinimalComparableIndexValue { + return MinimalComparableIndexValue(value.successor()) } - public static func _failEarlyRangeCheck( - index: ${Index}, bounds: Range<${Index}> - ) { - expectLE(bounds.startIndex.position, index.position) - expectGT(bounds.endIndex.position, index.position) + public var value: Int + public var identity: Int - if ${Index}.trapOnRangeCheckFailure.value { - Int._failEarlyRangeCheck( - index.position, - bounds: bounds.startIndex.position.. Bool { - _expectCompatibleIndices(lhs, rhs) - return lhs.position == rhs.position +public func == ( + lhs: MinimalComparableIndexValue, + rhs: MinimalComparableIndexValue +) -> Bool { + MinimalComparableIndexValue.timesEqualEqualWasCalled += 1 + return lhs.value == rhs.value } -extension ${Index} : _MinimalIndexType { - public var _offset: Int { - return position - startIndex - } +public func < ( + lhs: MinimalComparableIndexValue, + rhs: MinimalComparableIndexValue +) -> Bool { + MinimalComparableIndexValue.timesLessWasCalled += 1 + return lhs.value < rhs.value } -% end - -//===----------------------------------------------------------------------===// -// MinimalBidirectionalIndex -//===----------------------------------------------------------------------===// - -public struct MinimalBidirectionalIndex : BidirectionalIndexType { - public init(position: Int, startIndex: Int, endIndex: Int) { - self = MinimalBidirectionalIndex( - collectionState: nil, - position: position, - startIndex: startIndex, - endIndex: endIndex) - } - - internal init( - collectionState: _CollectionState?, - position: Int, - startIndex: Int, - endIndex: Int - ) { - expectLE(startIndex, position) - expectGE(endIndex, position) - self._collectionState = collectionState - self.position = position - self.startIndex = startIndex - self.endIndex = endIndex - } - - public func successor() -> MinimalBidirectionalIndex { - expectNotEqual(endIndex, position) - return MinimalBidirectionalIndex( - collectionState: _collectionState, - position: position + 1, startIndex: startIndex, endIndex: endIndex) - } - - public func predecessor() -> MinimalBidirectionalIndex { - expectNotEqual(startIndex, position) - return MinimalBidirectionalIndex( - collectionState: _collectionState, - position: position - 1, startIndex: startIndex, endIndex: endIndex) - } - - public static func _failEarlyRangeCheck( - index: MinimalBidirectionalIndex, - bounds: Range - ) { - expectLE(bounds.startIndex.position, index.position) - expectGT(bounds.endIndex.position, index.position) - - if MinimalBidirectionalIndex.trapOnRangeCheckFailure.value { - Int._failEarlyRangeCheck( - index.position, - bounds: bounds.startIndex.position.. Bool { - _expectCompatibleIndices(lhs, rhs) - return lhs.position == rhs.position -} - -extension MinimalBidirectionalIndex : _MinimalIndexType { - public var _offset: Int { - return position - startIndex - } -} - -//===----------------------------------------------------------------------===// -// Strict Index Types -//===----------------------------------------------------------------------===// - -% for Traversal in ['Forward', 'Bidirectional', 'RandomAccess']: -% StrictIndexType = 'Strict{}IndexType'.format(Traversal) - -public protocol ${StrictIndexType} : ${Traversal}IndexType { - typealias Base : ${Traversal}IndexType - init(_ base: Base) - var base: Base { get set } - - func logSuccessor() - func logPredecessor() -} - -extension ${StrictIndexType} { - public func successor() -> Self { - logSuccessor() - return Self(base.successor()) - } -% if Traversal in ['Bidirectional', 'RandomAccess']: - public func predecessor() -> Self { - logPredecessor() - return Self(base.predecessor()) - } -% end -} - -% end - -//===----------------------------------------------------------------------===// -// Defaulted Index Types -//===----------------------------------------------------------------------===// -% for Traversal in ['Forward', 'Bidirectional', 'RandomAccess']: -% StrictIndexType = 'Strict{}IndexType'.format(Traversal) -% DefaultedIndex = 'Defaulted{}Index'.format(Traversal) - -public struct ${DefaultedIndex}: ${StrictIndexType} { - public typealias Distance = Int - public typealias Base = Int - public var base: Base - public static var timesSuccessorCalled = ResettableValue(0) - public static var timesPredecessorCalled = ResettableValue(0) - - public init(_ base: Base) { - self.base = base - } - - public init(position: Base, startIndex: Base, endIndex: Base) { - expectLE(startIndex, position) - expectGE(endIndex, position) - self.init(position) - } - - public func logSuccessor() { - ${DefaultedIndex}.timesSuccessorCalled.value++ - } - - public func logPredecessor() { - ${DefaultedIndex}.timesPredecessorCalled.value++ - } - -% if Traversal == 'RandomAccess': - public func distanceTo(n: ${DefaultedIndex}) -> Distance { - return n.base - base - } - - public func advancedBy(n: Distance) -> ${DefaultedIndex} { - return ${DefaultedIndex}(base + n) - } -% end -} - -public func == (lhs: ${DefaultedIndex}, rhs: ${DefaultedIndex}) -> Bool { - return rhs.base == lhs.base -} - -% end - - - -//===----------------------------------------------------------------------===// -// MinimalRandomAccessIndex -//===----------------------------------------------------------------------===// - -public struct MinimalRandomAccessIndex : RandomAccessIndexType { - public typealias Distance = Int - public init(position: Int, startIndex: Int, endIndex: Int) { - self = MinimalRandomAccessIndex( - collectionState: nil, - position: position, - startIndex: startIndex, - endIndex: endIndex) - } - - internal init( - collectionState: _CollectionState?, - position: Int, - startIndex: Int, - endIndex: Int - ) { - expectLE(startIndex, position) - expectGE(endIndex, position) /*{ - "position=\(self.position) startIndex=\(self.startIndex) endIndex=\(self.endIndex)" - }*/ - - self._collectionState = collectionState - self.position = position - self.startIndex = startIndex - self.endIndex = endIndex - } - - public func successor() -> MinimalRandomAccessIndex { - expectNotEqual(endIndex, position) - return MinimalRandomAccessIndex( - collectionState: _collectionState, - position: position + 1, startIndex: startIndex, endIndex: endIndex) - } - - public func predecessor() -> MinimalRandomAccessIndex { - expectNotEqual(startIndex, position) - return MinimalRandomAccessIndex( - collectionState: _collectionState, - position: position - 1, startIndex: startIndex, endIndex: endIndex) - } - - public func distanceTo(other: MinimalRandomAccessIndex) -> Int { - _expectCompatibleIndices(self, other) - return other.position - position - } - - public func advancedBy(n: Int) -> MinimalRandomAccessIndex { - let newPosition = position + n - expectLE(startIndex, newPosition) - expectGE( - endIndex, newPosition, - "position=\(self.position) startIndex=\(self.startIndex)") - return MinimalRandomAccessIndex( - collectionState: _collectionState, - position: newPosition, startIndex: startIndex, endIndex: endIndex) - } - - public static func _failEarlyRangeCheck( - index: MinimalRandomAccessIndex, - bounds: Range - ) { - expectLE(bounds.startIndex.position, index.position) - expectGT(bounds.endIndex.position, index.position) - - if MinimalRandomAccessIndex.trapOnRangeCheckFailure.value { - Int._failEarlyRangeCheck( - index.position, - bounds: bounds.startIndex.position.. Bool { - _expectCompatibleIndices(lhs, rhs) - return lhs.position == rhs.position -} - -extension MinimalRandomAccessIndex : _MinimalIndexType { - public var _offset: Int { - return position - startIndex - } -} - -//===----------------------------------------------------------------------===// -// Minimal***[Mutable]?Collection -//===----------------------------------------------------------------------===// - -% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: -% for mutable in [ False, True ]: -// This comment is a workaround for gyb miscompiles nested loops -% Protocol = 'Strict%s%sCollectionType' % (traversal, 'Mutable' if mutable else '') -% Self = 'Minimal%s%sCollection' % (traversal, 'Mutable' if mutable else '') -% Index = 'Minimal%sIndex' % traversal - -public protocol ${Protocol} : ${'MutableCollectionType' if mutable else 'CollectionType'} { - typealias Element - init(base: ${Self}) -% if mutable: - var base: ${Self} { get set } -% else: - var base: ${Self} { get } -% end -} - -extension ${Protocol} { - public init( - elements: S, - underestimatedCount: UnderestimateCountBehavior = .Value(0) - ) { - self.init(base: - ${Self}(elements: elements, underestimatedCount: underestimatedCount)) - } - - public func underestimateCount() -> Int { - return base.underestimateCount() - } -} - -extension ${Protocol} where Generator : _MinimalGeneratorType { - public func generate() -> MinimalGenerator { - return base.generate() - } -} - -extension ${Protocol} where Index : _MinimalIndexType { - public var startIndex: ${Index} { - return base.startIndex - } - - public var endIndex: ${Index} { - return base.endIndex - } - - public subscript(i: ${Index}) -> Element { - get { - _expectCompatibleIndices(self.startIndex, i) - return base[i] - } -% if mutable: - set { - _expectCompatibleIndices(self.startIndex, i) - base[i] = newValue - } -% end - } -} - -/// A minimal implementation of `CollectionType` with extra checks. -public struct ${Self} : ${'MutableCollectionType' if mutable else 'CollectionType'} { - public init( - elements: S, - underestimatedCount: UnderestimateCountBehavior = .Value(0) - ) { - self._elements = Array(elements) - - self._collectionState = _CollectionState( - newRootStateForElementCount: self._elements.count) - - switch underestimatedCount { - case .Precise: - self.underestimatedCount = _elements.count - - case .Half: - self.underestimatedCount = _elements.count / 2 - - case .Overestimate: - self.underestimatedCount = _elements.count * 3 + 5 - - case .Value(let count): - self.underestimatedCount = count - } - } - - public func generate() -> MinimalGenerator { - return MinimalGenerator(_elements) - } - - public var startIndex: ${Index} { - return ${Index}( - collectionState: _collectionState, - position: 0, - startIndex: 0, - endIndex: _elements.endIndex) - } - - public var endIndex: ${Index} { - return ${Index}( - collectionState: _collectionState, - position: _elements.endIndex, - startIndex: 0, - endIndex: _elements.endIndex) - } - - public subscript(i: ${Index}) -> T { - get { - _expectCompatibleIndices(self.startIndex, i) - return _elements[i.position] - } -% if mutable: - set { - _expectCompatibleIndices(self.startIndex, i) - _elements[i.position] = newValue - } -% end - } - - public func underestimateCount() -> Int { - return underestimatedCount - } - - public var underestimatedCount: Int - - internal var _elements: [T] - internal let _collectionState: _CollectionState -} - -% end -% end - -//===----------------------------------------------------------------------===// -// Minimal***RangeReplaceableCollectionType -//===----------------------------------------------------------------------===// - -% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: -% Protocol = 'Strict%sRangeReplaceableCollectionType' % traversal -% Self = 'Minimal%sRangeReplaceableCollection' % traversal -% Index = 'Minimal%sIndex' % traversal - -public protocol ${Protocol} : RangeReplaceableCollectionType { - typealias Element - init(base: ${Self}) - var base: ${Self} { get set } -} - -extension ${Protocol} { - public mutating func replaceRange< - C: CollectionType where C.Generator.Element == Element - >(subRange: Range<${Self}.Index>, - with newElements: C) { - base.replaceRange(subRange, with: newElements) - } - - public mutating func removeLast() -> Element { - return base.removeLast() - } -} - -extension ${Protocol} where Generator : _MinimalGeneratorType { - public func generate() -> MinimalGenerator { - return base.generate() - } -} - -extension ${Protocol} where Index : _MinimalIndexType { - public var startIndex: ${Index} { - return base.startIndex - } - - public var endIndex: ${Index} { - return base.endIndex - } - - public subscript(i: ${Index}) -> Element { - get { - _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) - return base[i] - } - set { - _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) - base[i] = newValue - } - } -} - -/// A minimal implementation of `RangeReplaceableCollectionType` with extra -/// checks. -public struct ${Self} : RangeReplaceableCollectionType { - /// Creates a collection with given contents, but a unique modification - /// history. No other instance has the same modification history. - public init( - elements: S, - underestimatedCount: UnderestimateCountBehavior = .Value(0) - ) { - self.elements = Array(elements) - - self._collectionState = _CollectionState( - newRootStateForElementCount: self.elements.count) - - switch underestimatedCount { - case .Precise: - self.underestimatedCount = self.elements.count - - case .Half: - self.underestimatedCount = self.elements.count / 2 - - case .Overestimate: - self.underestimatedCount = self.elements.count * 3 + 5 - - case .Value(let count): - self.underestimatedCount = count - } - } - - public init() { - self.underestimatedCount = 0 - self.elements = [] - self._collectionState = _CollectionState(name: "\(self.dynamicType)", elementCount: 0) - } - - public init< - S : SequenceType where S.Generator.Element == T - >(_ elements: S) { - self.underestimatedCount = 0 - self.elements = Array(elements) - self._collectionState = - _CollectionState(newRootStateForElementCount: self.elements.count) - } - - public func generate() -> MinimalGenerator { - return MinimalGenerator(elements) - } - - public func underestimateCount() -> Int { - return underestimatedCount - } - - public var startIndex: ${Index} { - return ${Index}( - collectionState: _collectionState, - position: 0, - startIndex: 0, - endIndex: elements.endIndex) - } - - public var endIndex: ${Index} { - return ${Index}( - collectionState: _collectionState, - position: elements.endIndex, - startIndex: 0, - endIndex: elements.endIndex) - } - - public subscript(i: ${Index}) -> T { - get { - _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) - return elements[i.position] - } - set { - _expectCompatibleIndices(self.startIndex.advancedBy(i.position), i) - elements[i.position] = newValue - } - } - - public mutating func reserveCapacity(n: Int) { - _willMutate(.ReserveCapacity(capacity: n)) - elements.reserveCapacity(n) - reservedCapacity = max(reservedCapacity, n) - } - - public mutating func append(x: T) { - _willMutate(.Append) - elements.append(x) - } - - public mutating func appendContentsOf< - S : SequenceType where S.Generator.Element == T - >(newElements: S) { - let oldCount = count - elements.appendContentsOf(newElements) - let newCount = count - _willMutate(.AppendContentsOf(count: newCount - oldCount)) - } - - public mutating func replaceRange< - C : CollectionType where C.Generator.Element == T - >( - subRange: Range<${Index}>, with newElements: C - ) { - let oldCount = count - elements.replaceRange( - subRange.startIndex.position..(newElements: S, at i: ${Index}) { - let oldCount = count - elements.insertContentsOf(newElements, at: i.position) - let newCount = count - - if newCount - oldCount != 0 { - _willMutate(.InsertContentsOf( - atIndex: i._offset, - count: newCount - oldCount)) - } - } - - public mutating func removeAtIndex(i: ${Index}) -> T { - _willMutate(.RemoveAtIndex(index: i._offset)) - return elements.removeAtIndex(i.position) - } - - public mutating func removeLast() -> T { - _willMutate(.RemoveLast) - return elements.removeLast() - } - - public mutating func removeRange(subRange: Range<${Index}>) { - if !subRange.isEmpty { - _willMutate(.RemoveRange( - subRange: subRange.startIndex._offset.. { - public var value: Underlying - public var identity: Int - - public init(_ value: Underlying) { - self.value = value - self.identity = 0 - } - - public init(_ value: Underlying, identity: Int) { - self.value = value - self.identity = identity - } -} - -/// A type that conforms only to `Equatable`. -/// -/// This type can be used to check that generic functions don't rely on any -/// other conformances. -public struct MinimalEquatableValue : Equatable { - public static var timesEqualEqualWasCalled: Int = 0 - - public var value: Int - public var identity: Int - - public init(_ value: Int) { - self.value = value - self.identity = 0 - } - - public init(_ value: Int, identity: Int) { - self.value = value - self.identity = identity - } -} -public func == ( - lhs: MinimalEquatableValue, - rhs: MinimalEquatableValue -) -> Bool { - ++MinimalEquatableValue.timesEqualEqualWasCalled - return lhs.value == rhs.value -} - -% for kind in [ 'Value', 'Class' ]: -% Self = 'MinimalHashable%s' % kind - -/// A type that conforms only to `Equatable` and `Hashable`. -/// -/// This type can be used to check that generic functions don't rely on any -/// other conformances. -public struct ${Self} : Equatable, Hashable { - public static var timesEqualEqualWasCalled: Int = 0 - public static var timesHashValueWasCalled: Int = 0 - - public var value: Int - public var identity: Int - - public init(_ value: Int) { - self.value = value - self.identity = 0 - } - - public init(_ value: Int, identity: Int) { - self.value = value - self.identity = identity - } - - public var hashValue: Int { - ++${Self}.timesHashValueWasCalled - return value.hashValue - } -} - -public func == ( - lhs: ${Self}, - rhs: ${Self} -) -> Bool { - ++${Self}.timesEqualEqualWasCalled - return lhs.value == rhs.value -} - -% end - -/// A type that conforms only to `Equatable` and `Comparable`. -/// -/// This type can be used to check that generic functions don't rely on any -/// other conformances. -public struct MinimalComparableValue : Equatable, Comparable { - public static var timesEqualEqualWasCalled = ResettableValue(0) - public static var timesLessWasCalled = ResettableValue(0) - - public static var equalImpl = - ResettableValue<(Int, Int) -> Bool>({ $0 == $1 }) - public static var lessImpl = - ResettableValue<(Int, Int) -> Bool>({ $0 < $1 }) - - public var value: Int - public var identity: Int - - public init(_ value: Int) { - self.value = value - self.identity = 0 - } - - public init(_ value: Int, identity: Int) { - self.value = value - self.identity = identity - } -} - -public func == ( - lhs: MinimalComparableValue, - rhs: MinimalComparableValue -) -> Bool { - ++MinimalComparableValue.timesEqualEqualWasCalled.value - return MinimalComparableValue.equalImpl.value(lhs.value, rhs.value) -} - -public func < ( - lhs: MinimalComparableValue, - rhs: MinimalComparableValue -) -> Bool { - ++MinimalComparableValue.timesLessWasCalled.value - return MinimalComparableValue.lessImpl.value(lhs.value, rhs.value) -} - -/// A Sequence that uses as many default implementations as -/// `SequenceType` can provide. -public struct DefaultedSequence : StrictSequenceType { - public let base: MinimalSequence - - public init(base: MinimalSequence) { - self.base = base - } -} - -% for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: - -/// A Collection that uses as many default implementations as -/// `CollectionType` can provide. -public struct Defaulted${traversal}Collection - : Strict${traversal}CollectionType { - - public typealias Base = Minimal${traversal}Collection - public typealias Generator = MinimalGenerator - public typealias Index = Minimal${traversal}Index - - public let base: Base - - public init(base: Base) { - self.base = base - } - - public init(_ array: [Element]) { - self.base = Base(elements: array) - } - - public init(elements: [Element]) { - self.base = Base(elements: elements) - } -} - -public struct Defaulted${traversal}MutableCollection - : Strict${traversal}MutableCollectionType { - - public typealias Base = Minimal${traversal}MutableCollection - public typealias Generator = MinimalGenerator - public typealias Index = Minimal${traversal}Index - - public var base: Base - - public init(base: Base) { - self.base = base - } - - public init(_ array: [Element]) { - self.base = Base(elements: array) - } - - public init(elements: [Element]) { - self.base = Base(elements: elements) - } -} - -public struct Defaulted${traversal}RangeReplaceableCollection - : Strict${traversal}RangeReplaceableCollectionType { - - public typealias Base = Minimal${traversal}RangeReplaceableCollection - public typealias Generator = MinimalGenerator - public typealias Index = Minimal${traversal}Index - - public var base: Base - - public init() { - base = Base() - } - - public init(base: Base) { - self.base = base - } - - public init(_ array: [Element]) { - self.base = Base(elements: array) - } - - public init(elements: [Element]) { - self.base = Base(elements: elements) - } -} - -public struct Defaulted${traversal}RangeReplaceableSlice - : RangeReplaceableCollectionType { - - public typealias Self_ = Defaulted${traversal}RangeReplaceableSlice - public typealias Base = Minimal${traversal}RangeReplaceableCollection - public typealias Generator = MinimalGenerator - public typealias Index = Minimal${traversal}Index - - public var base: Base - public var startIndex: Index - public var endIndex: Index - - public init() { - expectSliceType(Self_.self) - - self.base = Base() - self.startIndex = base.startIndex - self.endIndex = base.endIndex - } - - public init(base: Base) { - self.base = base - self.startIndex = base.startIndex - self.endIndex = base.endIndex - } - - public init(base: Base, bounds: Range) { - self.base = base - self.startIndex = bounds.startIndex - self.endIndex = bounds.endIndex - } - - public init(_ array: [Element]) { - self = Defaulted${traversal}RangeReplaceableSlice( - base: Base(elements: array)) - } - - public init(elements: [Element]) { - self = Defaulted${traversal}RangeReplaceableSlice( - base: Base(elements: elements)) - } - - public func generate() -> MinimalGenerator { - return MinimalGenerator(Array(self)) - } - - public subscript(index: Index) -> Element { - Index._failEarlyRangeCheck(index, bounds: startIndex..) -> Self_ { - Index._failEarlyRangeCheck2( - bounds.startIndex, rangeEnd: bounds.endIndex, - boundsStart: startIndex, boundsEnd: endIndex) - return Defaulted${traversal}RangeReplaceableSlice( - base: base, bounds: bounds) - } - - public mutating func replaceRange< - C : CollectionType where C.Generator.Element == Element - >( - subRange: Range, - with newElements: C - ) { - let startOffset = startIndex.position - let endOffset = - endIndex.position - - subRange.count - + numericCast(newElements.count) as Int - Index._failEarlyRangeCheck2( - subRange.startIndex, rangeEnd: subRange.endIndex, - boundsStart: startIndex, boundsEnd: endIndex) - base.replaceRange(subRange, with: newElements) - startIndex = base.startIndex.advancedBy(startOffset) - endIndex = base.startIndex.advancedBy(endOffset) - } -} - -% end - // ${'Local Variables'}: // eval: (read-only-mode 1) // End: diff --git a/stdlib/private/StdlibUnittest/TypeIndexed.swift b/stdlib/private/StdlibUnittest/TypeIndexed.swift index a51586c682629..df6c0a130906d 100644 --- a/stdlib/private/StdlibUnittest/TypeIndexed.swift +++ b/stdlib/private/StdlibUnittest/TypeIndexed.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -55,11 +55,11 @@ public class TypeIndexed : Resettable { extension TypeIndexed where Value : ForwardIndexType { public func expectIncrement( t: Any.Type, - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__, - body: ()->R + body: () -> R ) -> R { let expected = self[t].successor() let r = body() @@ -73,11 +73,11 @@ extension TypeIndexed where Value : ForwardIndexType { extension TypeIndexed where Value : Equatable { public func expectUnchanged( t: Any.Type, - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__, - body: ()->R + body: () -> R ) -> R { let expected = self[t] let r = body() @@ -99,7 +99,7 @@ public func <=> ( public func expectEqual( expected: DictionaryLiteral, _ actual: TypeIndexed, - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ diff --git a/stdlib/private/StdlibUnittestFoundationExtras/CMakeLists.txt b/stdlib/private/StdlibUnittestFoundationExtras/CMakeLists.txt index 99431e8b17c00..63fe9e3415833 100644 --- a/stdlib/private/StdlibUnittestFoundationExtras/CMakeLists.txt +++ b/stdlib/private/StdlibUnittestFoundationExtras/CMakeLists.txt @@ -3,7 +3,7 @@ add_swift_library(swiftStdlibUnittestFoundationExtras SHARED IS_STDLIB # filename. StdlibUnittestFoundationExtras.swift - # Can not serialize StdlibUnittestFoundationExtras because of: + # Cannot serialize StdlibUnittestFoundationExtras because of: # Compiling StdlibUnittest with -sil-serialize-all # crashes in SIL serializer # diff --git a/stdlib/private/StdlibUnittestFoundationExtras/StdlibUnittestFoundationExtras.swift b/stdlib/private/StdlibUnittestFoundationExtras/StdlibUnittestFoundationExtras.swift index b567c02c82d45..25147222f1e28 100644 --- a/stdlib/private/StdlibUnittestFoundationExtras/StdlibUnittestFoundationExtras.swift +++ b/stdlib/private/StdlibUnittestFoundationExtras/StdlibUnittestFoundationExtras.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,11 +27,11 @@ public func withOverriddenNSLocaleCurrentLocale( @noescape _ body: () -> Result ) -> Result { let oldMethod = class_getClassMethod( - NSLocale.self, Selector("currentLocale")) + NSLocale.self, #selector(NSLocale.currentLocale)) precondition(oldMethod != nil, "could not find +[NSLocale currentLocale]") let newMethod = class_getClassMethod( - NSLocale.self, Selector("_swiftUnittest_currentLocale")) + NSLocale.self, #selector(NSLocale._swiftUnittest_currentLocale)) precondition(newMethod != nil, "could not find +[NSLocale _swiftUnittest_currentLocale]") precondition(_temporaryNSLocaleCurrentLocale == nil, diff --git a/stdlib/private/SwiftPrivate/IO.swift b/stdlib/private/SwiftPrivate/IO.swift index 00d63767f76cb..c89936ceb5714 100644 --- a/stdlib/private/SwiftPrivate/IO.swift +++ b/stdlib/private/SwiftPrivate/IO.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/private/SwiftPrivate/PRNG.swift b/stdlib/private/SwiftPrivate/PRNG.swift index d05583050f27e..c5cd6d9dd2eb1 100644 --- a/stdlib/private/SwiftPrivate/PRNG.swift +++ b/stdlib/private/SwiftPrivate/PRNG.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -32,7 +32,7 @@ public func rand64() -> UInt64 { public func randInt() -> Int { #if arch(i386) || arch(arm) return Int(Int32(bitPattern: rand32())) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return Int(Int64(bitPattern: rand64())) #else fatalError("unimplemented") diff --git a/stdlib/private/SwiftPrivate/ShardedAtomicCounter.swift b/stdlib/private/SwiftPrivate/ShardedAtomicCounter.swift index ffc37531b4655..4ccbfdbcced4b 100644 --- a/stdlib/private/SwiftPrivate/ShardedAtomicCounter.swift +++ b/stdlib/private/SwiftPrivate/ShardedAtomicCounter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,7 @@ public struct _stdlib_ShardedAtomicCounter { let hardwareConcurrency = _stdlib_getHardwareConcurrency() let count = max(8, hardwareConcurrency * hardwareConcurrency) let shards = UnsafeMutablePointer.alloc(count) - for var i = 0; i != count; i++ { + for i in 0.. Int { var result = 0 - for var i = 0; i != Int._sizeInBits; ++i { + for _ in 0..> 1) ^ (-(_state & 1) & Int(bitPattern: 0xD0000001)) } diff --git a/stdlib/private/SwiftPrivate/SwiftPrivate.swift b/stdlib/private/SwiftPrivate/SwiftPrivate.swift index e0a2ff6462575..19bb8f128ec75 100644 --- a/stdlib/private/SwiftPrivate/SwiftPrivate.swift +++ b/stdlib/private/SwiftPrivate/SwiftPrivate.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -43,7 +43,7 @@ public func scan< public func randomShuffle(a: [T]) -> [T] { var result = a - for var i = a.count - 1; i != 0; --i { + for i in (1.. UnsafeMutablePointer UnsafeMutablePointer> { #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) return _NSGetEnviron().memory +#elseif os(FreeBSD) + return environ; #else return __environ #endif diff --git a/stdlib/private/SwiftPrivateDarwinExtras/SwiftPrivateDarwinExtras.swift b/stdlib/private/SwiftPrivateDarwinExtras/SwiftPrivateDarwinExtras.swift index 46fe5dbe4440f..c8168921e3045 100644 --- a/stdlib/private/SwiftPrivateDarwinExtras/SwiftPrivateDarwinExtras.swift +++ b/stdlib/private/SwiftPrivateDarwinExtras/SwiftPrivateDarwinExtras.swift @@ -1,8 +1,8 @@ -//===--- DarwinExtras.swift -----------------------------------------------===// +//===--- SwiftPrivateDarwinExtras.swift -----------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,7 +13,7 @@ import SwiftPrivate #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) import Glibc #endif diff --git a/stdlib/private/SwiftPrivatePthreadExtras/CMakeLists.txt b/stdlib/private/SwiftPrivatePthreadExtras/CMakeLists.txt index 86f45e5db357d..934c104455bc2 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/CMakeLists.txt +++ b/stdlib/private/SwiftPrivatePthreadExtras/CMakeLists.txt @@ -3,7 +3,7 @@ set(swift_private_pthread_extras_module_depends) if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") list(APPEND swift_private_pthread_extras_module_depends Darwin) -elseif(SWIFT_HOST_VARIANT STREQUAL "linux") +elseif(SWIFT_HOST_VARIANT STREQUAL "linux" OR SWIFT_HOST_VARIANT STREQUAL "freebsd") list(APPEND swift_private_pthread_extras_module_depends Glibc) endif() diff --git a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift index a2e81ba581f71..de5d46ff02c76 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) import Glibc #endif @@ -105,7 +105,7 @@ public func _stdlib_pthread_barrier_wait( if pthread_mutex_lock(barrier.memory.mutex) != 0 { return -1 } - ++barrier.memory.numThreadsWaiting + barrier.memory.numThreadsWaiting += 1 if barrier.memory.numThreadsWaiting < barrier.memory.count { // Put the thread to sleep. if pthread_cond_wait(barrier.memory.cond, barrier.memory.mutex) != 0 { diff --git a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift index 6394da3636e3f..decd206477aff 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,7 +17,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) +#elseif os(Linux) || os(FreeBSD) import Glibc #endif diff --git a/stdlib/public/CMakeLists.txt b/stdlib/public/CMakeLists.txt index e0f030b26f22b..29aae6e5def59 100644 --- a/stdlib/public/CMakeLists.txt +++ b/stdlib/public/CMakeLists.txt @@ -27,6 +27,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") endif() endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") add_subdirectory(Glibc) endif() diff --git a/stdlib/public/Glibc/CMakeLists.txt b/stdlib/public/Glibc/CMakeLists.txt index 8cc1df681e12c..d7e277b69e260 100644 --- a/stdlib/public/Glibc/CMakeLists.txt +++ b/stdlib/public/Glibc/CMakeLists.txt @@ -17,7 +17,12 @@ if (NOT EXISTS "${GLIBC_ARCH_INCLUDE_PATH}/sys") endif() # Generate module.map +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") configure_file(module.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY) +endif() +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") +configure_file(module.freebsd.map.in "${CMAKE_CURRENT_BINARY_DIR}/module.map" @ONLY) +endif() add_custom_command_target(unused_var COMMAND diff --git a/stdlib/public/Glibc/Glibc.swift b/stdlib/public/Glibc/Glibc.swift index b333d06d536be..18b450793bd93 100644 --- a/stdlib/public/Glibc/Glibc.swift +++ b/stdlib/public/Glibc/Glibc.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,10 +18,18 @@ public var errno: Int32 { get { +#if os(FreeBSD) + return __error().memory +#else return __errno_location().memory +#endif } set(val) { +#if os(FreeBSD) + return __error().memory = val +#else return __errno_location().memory = val +#endif } } @@ -211,3 +219,15 @@ public func sem_open( ) -> UnsafeMutablePointer { return _swift_Glibc_sem_open4(name, oflag, mode, value) } + +// FreeBSD defines extern char **environ differently than Linux. +#if os(FreeBSD) +@warn_unused_result +@_silgen_name("_swift_FreeBSD_getEnv") +func _swift_FreeBSD_getEnv( +) -> UnsafeMutablePointer>> + +public var environ: UnsafeMutablePointer> { + return _swift_FreeBSD_getEnv().memory +} +#endif diff --git a/stdlib/public/Glibc/Misc.c b/stdlib/public/Glibc/Misc.c index b53a28052a6d4..128b3c6977d20 100644 --- a/stdlib/public/Glibc/Misc.c +++ b/stdlib/public/Glibc/Misc.c @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,3 +44,8 @@ _swift_Glibc_fcntlPtr(int fd, int cmd, void* ptr) { return fcntl(fd, cmd, ptr); } +extern char ** +_swift_FreeBSD_getEnv() { + extern char **environ; + return environ; +} diff --git a/stdlib/public/Glibc/module.freebsd.map.in b/stdlib/public/Glibc/module.freebsd.map.in new file mode 100644 index 0000000000000..c60664e8a01b6 --- /dev/null +++ b/stdlib/public/Glibc/module.freebsd.map.in @@ -0,0 +1,364 @@ +//===--- module.freebsd.map.in --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +/// This is a semi-complete modulemap that maps glibc's headers in a roughly +/// similar way to the Darwin SDK modulemap. We do not take care to list every +/// single header which may be included by a particular submodule, so there can +/// still be issues if imported into the same context as one in which someone +/// included those headers directly. +/// +/// It's not named just FreeBSD libc so that it doesn't conflict in the event of a +/// future official FreeBSD libc modulemap. +module SwiftGlibc [system] { + link "pthread" + link "dl" + + // C standard library + module C { + module complex { + header "@GLIBC_INCLUDE_PATH@/complex.h" + export * + } + module ctype { + header "@GLIBC_INCLUDE_PATH@/ctype.h" + export * + } + module errno { + header "@GLIBC_INCLUDE_PATH@/errno.h" + export * + } + + module fenv { + header "@GLIBC_INCLUDE_PATH@/fenv.h" + export * + } + + // note: supplied by compiler + // module float { + // header "@GLIBC_INCLUDE_PATH@/float.h" + // export * + // } + + module inttypes { + header "@GLIBC_INCLUDE_PATH@/inttypes.h" + export * + } + + // note: potentially supplied by compiler + // module iso646 { + // header "@GLIBC_INCLUDE_PATH@/iso646.h" + // export * + // } + // module limits { + // header "@GLIBC_INCLUDE_PATH@/limits.h" + // export * + // } + + module locale { + header "@GLIBC_INCLUDE_PATH@/locale.h" + export * + } + module math { + header "@GLIBC_INCLUDE_PATH@/math.h" + export * + } + module setjmp { + header "@GLIBC_INCLUDE_PATH@/setjmp.h" + export * + } + module signal { + header "@GLIBC_INCLUDE_PATH@/signal.h" + export * + } + + // note: supplied by the compiler + // module stdarg { + // header "@GLIBC_INCLUDE_PATH@/stdarg.h" + // export * + // } + // module stdbool { + // header "@GLIBC_INCLUDE_PATH@/stdbool.h" + // export * + // } + // module stddef { + // header "@GLIBC_INCLUDE_PATH@/stddef.h" + // export * + // } + // module stdint { + // header "@GLIBC_INCLUDE_PATH@/stdint.h" + // export * + // } + + module stdio { + header "@GLIBC_INCLUDE_PATH@/stdio.h" + export * + } + module stdlib { + header "@GLIBC_INCLUDE_PATH@/stdlib.h" + export * + export stddef + } + module string { + header "@GLIBC_INCLUDE_PATH@/string.h" + export * + } + + // note: supplied by the compiler + // explicit module tgmath { + // header "@GLIBC_INCLUDE_PATH@/tgmath.h" + // export * + // } + + module time { + header "@GLIBC_INCLUDE_PATH@/time.h" + export * + } + } + + // POSIX + module POSIX { + module aio { + header "@GLIBC_INCLUDE_PATH@/aio.h" + export * + } + module arpa { + module inet { + header "@GLIBC_INCLUDE_PATH@/arpa/inet.h" + export * + } + export * + } + module cpio { + header "@GLIBC_INCLUDE_PATH@/cpio.h" + export * + } + module dirent { + header "@GLIBC_INCLUDE_PATH@/dirent.h" + export * + } + module dlfcn { + header "@GLIBC_INCLUDE_PATH@/dlfcn.h" + export * + } + module fcntl { + header "@GLIBC_INCLUDE_PATH@/fcntl.h" + export * + } + module fmtmsg { + header "@GLIBC_INCLUDE_PATH@/fmtmsg.h" + export * + } + module fnmatch { + header "@GLIBC_INCLUDE_PATH@/fnmatch.h" + export * + } + module ftw { + header "@GLIBC_INCLUDE_PATH@/ftw.h" + export * + } + module glob { + header "@GLIBC_INCLUDE_PATH@/glob.h" + export * + } + module grp { + header "@GLIBC_INCLUDE_PATH@/grp.h" + export * + } + module iconv { + header "@GLIBC_INCLUDE_PATH@/iconv.h" + export * + } + module ioctl { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/ioctl.h" + export * + } + module langinfo { + header "@GLIBC_INCLUDE_PATH@/langinfo.h" + export * + } + module libgen { + header "@GLIBC_INCLUDE_PATH@/libgen.h" + export * + } + module monetary { + header "@GLIBC_INCLUDE_PATH@/monetary.h" + export * + } + module netdb { + header "@GLIBC_INCLUDE_PATH@/netdb.h" + export * + } + module net { + module if { + header "@GLIBC_INCLUDE_PATH@/net/if.h" + export * + } + } + module netinet { + module in { + header "@GLIBC_INCLUDE_PATH@/netinet/in.h" + export * + + exclude header "@GLIBC_INCLUDE_PATH@/netinet6/in6.h" + } + module tcp { + header "@GLIBC_INCLUDE_PATH@/netinet/tcp.h" + export * + } + } + module nl_types { + header "@GLIBC_INCLUDE_PATH@/nl_types.h" + export * + } + module poll { + header "@GLIBC_INCLUDE_PATH@/poll.h" + export * + } + module pthread { + header "@GLIBC_INCLUDE_PATH@/pthread.h" + export * + } + module pwd { + header "@GLIBC_INCLUDE_PATH@/pwd.h" + export * + } + module regex { + header "@GLIBC_INCLUDE_PATH@/regex.h" + export * + } + module sched { + header "@GLIBC_INCLUDE_PATH@/sched.h" + export * + } + module search { + header "@GLIBC_INCLUDE_PATH@/search.h" + export * + } + module semaphore { + header "@GLIBC_INCLUDE_PATH@/semaphore.h" + export * + } + module spawn { + header "@GLIBC_INCLUDE_PATH@/spawn.h" + export * + } + module strings { + header "@GLIBC_INCLUDE_PATH@/strings.h" + export * + } + + module sys { + export * + + module ipc { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/ipc.h" + export * + } + module mman { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/mman.h" + export * + } + module msg { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/msg.h" + export * + } + module resource { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/resource.h" + export * + } + module select { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/select.h" + export * + } + module sem { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/sem.h" + export * + } + module shm { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/shm.h" + export * + } + module socket { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/socket.h" + export * + } + module stat { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/stat.h" + export * + } + module statvfs { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/statvfs.h" + export * + } + module time { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/time.h" + export * + } + module times { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/times.h" + export * + } + module types { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/types.h" + export * + } + module uio { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/uio.h" + export * + } + module un { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/un.h" + export * + } + module utsname { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/utsname.h" + export * + } + module wait { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/wait.h" + export * + } + } + module syslog { + header "@GLIBC_INCLUDE_PATH@/syslog.h" + export * + } + module tar { + header "@GLIBC_INCLUDE_PATH@/tar.h" + export * + } + module termios { + header "@GLIBC_INCLUDE_PATH@/termios.h" + export * + } + module ulimit { + header "@GLIBC_INCLUDE_PATH@/ulimit.h" + export * + } + module unistd { + header "@GLIBC_INCLUDE_PATH@/unistd.h" + export * + } + module utime { + header "@GLIBC_INCLUDE_PATH@/utime.h" + export * + } + module utmpx { + header "@GLIBC_INCLUDE_PATH@/utmpx.h" + export * + } + module wordexp { + header "@GLIBC_INCLUDE_PATH@/wordexp.h" + export * + } + } +} diff --git a/stdlib/public/Glibc/module.map.in b/stdlib/public/Glibc/module.map.in index d33febc8a0b78..668967406d5dd 100644 --- a/stdlib/public/Glibc/module.map.in +++ b/stdlib/public/Glibc/module.map.in @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/AppKit/AppKit.swift b/stdlib/public/SDK/AppKit/AppKit.swift index 80654fe465ae0..45675e474a99d 100644 --- a/stdlib/public/SDK/AppKit/AppKit.swift +++ b/stdlib/public/SDK/AppKit/AppKit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,96 +13,39 @@ import Foundation @_exported import AppKit -struct _NSCursorMirror : _MirrorType { - var _value: NSCursor - - init(_ v: NSCursor) { _value = v } - - var value: Any { return _value } - - var valueType: Any.Type { return (_value as Any).dynamicType } - - var objectIdentifier: ObjectIdentifier? { return .None } - - var count: Int { return 0 } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") +extension NSCursor : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Image(image) } - - var summary: String { return "" } - - var quickLookObject: PlaygroundQuickLook? { - return .Some(.Image(_value.image)) - } - - var disposition : _MirrorDisposition { return .Aggregate } } -extension NSCursor : _Reflectable { - public func _getMirror() -> _MirrorType { - return _NSCursorMirror(self) - } +internal struct _NSViewQuickLookState { + static var views = Set() } -struct _NSViewMirror : _MirrorType { - static var _views = NSMutableSet() - - var _v : NSView - - init(_ v : NSView) { _v = v } - - var value: Any { get { return _v } } - - var valueType: Any.Type { get { return (_v as Any).dynamicType } } - - var objectIdentifier: ObjectIdentifier? { get { return .None } } - - var count: Int { get { return 0 } } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { get { return "" } } - - var quickLookObject: PlaygroundQuickLook? { get { - // adapted from the Xcode QuickLooks implementation - - var result: PlaygroundQuickLook? = nil - - // if you set NSView.needsDisplay, you can get yourself in a recursive scenario where the same view - // could need to draw itself in order to get a QLObject for itself, which in turn if your code was - // instrumented to log on-draw, would cause yourself to get back here and so on and so forth - // until you run out of stack and crash - // This code checks that we aren't trying to log the same view recursively - and if so just returns - // nil, which is probably a safer option than crashing - // FIXME: is there a way to say "cacheDisplayInRect butDoNotRedrawEvenIfISaidSo"? - switch _NSViewMirror._views.member(_v) { - case nil: - _NSViewMirror._views.addObject(_v) - - let bounds = _v.bounds - if let b = _v.bitmapImageRepForCachingDisplayInRect(bounds) { - _v.cacheDisplayInRect(bounds, toBitmapImageRep: b) - result = .Some(.View(b)) - } - - _NSViewMirror._views.removeObject(_v) - default: () +extension NSView : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + // if you set NSView.needsDisplay, you can get yourself in a recursive scenario where the same view + // could need to draw itself in order to get a QLObject for itself, which in turn if your code was + // instrumented to log on-draw, would cause yourself to get back here and so on and so forth + // until you run out of stack and crash + // This code checks that we aren't trying to log the same view recursively - and if so just returns + // an empty view, which is probably a safer option than crashing + // FIXME: is there a way to say "cacheDisplayInRect butDoNotRedrawEvenIfISaidSo"? + if _NSViewQuickLookState.views.contains(self) { + return .View(NSImage()) + } else { + _NSViewQuickLookState.views.insert(self) + let result: PlaygroundQuickLook + if let b = bitmapImageRepForCachingDisplayInRect(bounds) { + cacheDisplayInRect(bounds, toBitmapImageRep: b) + result = .View(b) + } else { + result = .View(NSImage()) } - + _NSViewQuickLookState.views.remove(self) return result - - } } - - var disposition : _MirrorDisposition { get { return .Aggregate } } -} - -extension NSView : _Reflectable { - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _NSViewMirror(self) + } } } diff --git a/stdlib/public/SDK/AssetsLibrary/AssetsLibrary.swift b/stdlib/public/SDK/AssetsLibrary/AssetsLibrary.swift index 2b1b01914b6d1..60f30e0ceb636 100644 --- a/stdlib/public/SDK/AssetsLibrary/AssetsLibrary.swift +++ b/stdlib/public/SDK/AssetsLibrary/AssetsLibrary.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Contacts/Contacts.swift b/stdlib/public/SDK/Contacts/Contacts.swift index 5bda8ff026bb4..f30a1dbb32bc5 100644 --- a/stdlib/public/SDK/Contacts/Contacts.swift +++ b/stdlib/public/SDK/Contacts/Contacts.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/CoreAudio/CoreAudio.swift b/stdlib/public/SDK/CoreAudio/CoreAudio.swift index 5857aa89f0fe6..647da5dc7fd54 100644 --- a/stdlib/public/SDK/CoreAudio/CoreAudio.swift +++ b/stdlib/public/SDK/CoreAudio/CoreAudio.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb b/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb index 3b654ce53aabd..b2d805552e4b2 100644 --- a/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb +++ b/stdlib/public/SDK/CoreGraphics/CGFloat.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 @@ -145,10 +145,10 @@ public var CGFLOAT_MAX: CGFloat { fatalError("can't retrieve unavailable property") } -extension CGFloat : _Reflectable { +extension CGFloat : CustomReflectable { /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _reflect(native) + public func customMirror() -> Mirror { + return Mirror(reflecting: native) } } diff --git a/stdlib/public/SDK/CoreGraphics/CMakeLists.txt b/stdlib/public/SDK/CoreGraphics/CMakeLists.txt index cb884b3794d65..3ae62ab2e50a1 100644 --- a/stdlib/public/SDK/CoreGraphics/CMakeLists.txt +++ b/stdlib/public/SDK/CoreGraphics/CMakeLists.txt @@ -1,7 +1,6 @@ add_swift_library(swiftCoreGraphics IS_SDK_OVERLAY CoreGraphics.swift CGFloat.swift.gyb - CoreGraphicsMirrors.swift.gyb # rdar://problem/20891746 # SWIFT_COMPILE_FLAGS -Xfrontend -sil-serialize-all SWIFT_MODULE_DEPENDS ObjectiveC Dispatch Darwin diff --git a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift index 480c60a5370bf..2c511f3241aeb 100644 --- a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift +++ b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -39,6 +39,22 @@ public extension CGPoint { } } +extension CGPoint : CustomReflectable, CustomPlaygroundQuickLookable { + public func customMirror() -> Mirror { + return Mirror(self, children: ["x": x, "y": y], displayStyle: .Struct) + } + + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Point(Double(x), Double(y)) + } +} + +extension CGPoint : CustomDebugStringConvertible { + public var debugDescription: String { + return "(\(x), \(y))" + } +} + extension CGPoint : Equatable {} @_transparent // @fragile @warn_unused_result @@ -68,6 +84,22 @@ public extension CGSize { } } +extension CGSize : CustomReflectable, CustomPlaygroundQuickLookable { + public func customMirror() -> Mirror { + return Mirror(self, children: ["width": width, "height": height], displayStyle: .Struct) + } + + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Size(Double(width), Double(height)) + } +} + +extension CGSize : CustomDebugStringConvertible { + public var debugDescription : String { + return "(\(width), \(height))" + } +} + extension CGSize : Equatable {} @_transparent // @fragile @warn_unused_result @@ -357,6 +389,22 @@ public extension CGRect { } } +extension CGRect : CustomReflectable, CustomPlaygroundQuickLookable { + public func customMirror() -> Mirror { + return Mirror(self, children: ["origin": origin, "size": size], displayStyle: .Struct) + } + + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Rectangle(Double(origin.x), Double(origin.y), Double(size.width), Double(size.height)) + } +} + +extension CGRect : CustomDebugStringConvertible { + public var debugDescription : String { + return "(\(origin.x), \(origin.y), \(size.width), \(size.height))" + } +} + extension CGRect : Equatable {} @_transparent // @fragile @warn_unused_result diff --git a/stdlib/public/SDK/CoreGraphics/CoreGraphicsMirrors.swift.gyb b/stdlib/public/SDK/CoreGraphics/CoreGraphicsMirrors.swift.gyb deleted file mode 100644 index 496cfee5da5cf..0000000000000 --- a/stdlib/public/SDK/CoreGraphics/CoreGraphicsMirrors.swift.gyb +++ /dev/null @@ -1,59 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../../common/MirrorBoilerplate.gyb") - -% for Type in [['CGPoint',['x','y'],'Point',['x','y']],\ -% ['CGSize',['width','height'],'Size',['width','height']],\ -% ['CGRect',['origin','size'],'Rectangle',['origin.x','origin.y','size.width','size.height']]]: -% Self = Type[0] -% Children = Type[1] -% QLTag = Type[2] -% QLArgs = Type[3] -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,introspecteeType=Self,disposition='Struct') -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,introspecteeType=Self,disposition='Struct') -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,introspecteeType=Self,disposition='Struct') -% QLArgFirst=True -% QLArgString = '' -% SummaryString = '' -% for QLArg in QLArgs: -% if QLArgFirst == False: -% QLArgString = QLArgString + ', ' -% SummaryString = SummaryString + ', ' -% else: -% QLArgFirst = False -% QLArgString = QLArgString + 'Double(_value.' + QLArg + ')' -% SummaryString = SummaryString + '\(_value.' + QLArg + ')' -% end - -${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return 2 } - - subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: return ("${Children[0]}", _reflect(_value.${Children[0]})) - case 1: return ("${Children[1]}", _reflect(_value.${Children[1]})) - default: _preconditionFailure("cannot extract this child index") - } - } - - var summary: String { return "(${SummaryString})" } - - var quickLookObject: PlaygroundQuickLook? { return .Some(.${QLTag}(${QLArgString})) } -} - -${MirrorConformance} diff --git a/stdlib/public/SDK/CoreImage/CoreImage.swift b/stdlib/public/SDK/CoreImage/CoreImage.swift index 444796780ff01..92b81eb187f1d 100644 --- a/stdlib/public/SDK/CoreImage/CoreImage.swift +++ b/stdlib/public/SDK/CoreImage/CoreImage.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/CoreMedia/CMTime.swift b/stdlib/public/SDK/CoreMedia/CMTime.swift index 38f93bf8ca57d..4f9df9b444f33 100644 --- a/stdlib/public/SDK/CoreMedia/CMTime.swift +++ b/stdlib/public/SDK/CoreMedia/CMTime.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/CoreMedia/CMTimeRange.swift b/stdlib/public/SDK/CoreMedia/CMTimeRange.swift index e10138bf03db3..d6e0e2cf5ea11 100644 --- a/stdlib/public/SDK/CoreMedia/CMTimeRange.swift +++ b/stdlib/public/SDK/CoreMedia/CMTimeRange.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/CoreMedia/CoreMedia.swift b/stdlib/public/SDK/CoreMedia/CoreMedia.swift index bbf1b32ff46a7..ce986fe913e66 100644 --- a/stdlib/public/SDK/CoreMedia/CoreMedia.swift +++ b/stdlib/public/SDK/CoreMedia/CoreMedia.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Darwin/Darwin.swift b/stdlib/public/SDK/Darwin/Darwin.swift index dc74129f424b0..4544de4f5f206 100644 --- a/stdlib/public/SDK/Darwin/Darwin.swift +++ b/stdlib/public/SDK/Darwin/Darwin.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -42,10 +42,10 @@ public struct DarwinBoolean : BooleanType, BooleanLiteralConvertible { } } -extension DarwinBoolean : _Reflectable { +extension DarwinBoolean : CustomReflectable { /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _reflect(boolValue) + public func customMirror() -> Mirror { + return Mirror(reflecting: boolValue) } } diff --git a/stdlib/public/SDK/Darwin/Misc.mm b/stdlib/public/SDK/Darwin/Misc.mm index f54927e661160..75e08b8a3f9c6 100644 --- a/stdlib/public/SDK/Darwin/Misc.mm +++ b/stdlib/public/SDK/Darwin/Misc.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Darwin/tgmath.swift.gyb b/stdlib/public/SDK/Darwin/tgmath.swift.gyb index 6dec54eb82fcd..f935f81e4dd00 100644 --- a/stdlib/public/SDK/Darwin/tgmath.swift.gyb +++ b/stdlib/public/SDK/Darwin/tgmath.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,43 +45,51 @@ def cFuncSuffix(bits): # (T) -> T # These functions do not have a corresponding LLVM intrinsic -UnaryFunctions = ['acos', 'asin', 'atan', 'tan', - 'acosh', 'asinh', 'atanh', 'cosh', 'sinh', 'tanh', - 'expm1', - 'log1p', 'logb', - 'cbrt', 'sqrt', 'erf', 'erfc', 'tgamma', - ] +UnaryFunctions = [ + 'acos', 'asin', 'atan', 'tan', + 'acosh', 'asinh', 'atanh', 'cosh', 'sinh', 'tanh', + 'expm1', + 'log1p', 'logb', + 'cbrt', 'sqrt', 'erf', 'erfc', 'tgamma', +] # These functions have a corresponding LLVM intrinsic # We call this intrinsic via the Builtin method so keep this list in # sync with core/BuiltinMath.swift.gyb -UnaryIntrinsicFunctions = ['cos', 'sin', - 'exp', 'exp2', - 'log', 'log10', 'log2', - 'fabs', - 'ceil', 'floor', 'nearbyint', 'rint', 'round', 'trunc', - ] +UnaryIntrinsicFunctions = [ + 'cos', 'sin', + 'exp', 'exp2', + 'log', 'log10', 'log2', + 'fabs', + 'ceil', 'floor', 'nearbyint', 'rint', 'round', 'trunc', +] # (T, T) -> T -BinaryFunctions = ['atan2', 'hypot', 'pow', 'fmod', - 'remainder', 'copysign', 'nextafter', 'fdim', 'fmax', 'fmin'] +BinaryFunctions = [ + 'atan2', 'hypot', 'pow', 'fmod', + 'remainder', 'copysign', 'nextafter', 'fdim', 'fmax', 'fmin' +] # These functions have special implementations. -OtherFunctions = ['fpclassify', - 'isnormal', 'isfinite', 'isinf', 'isnan', 'signbit', - 'modf', 'ldexp', 'frexp', 'ilogb', 'scalbn', 'lgamma', - 'remquo', 'nan', 'fma', - 'jn', 'yn'] +OtherFunctions = [ + 'fpclassify', + 'isnormal', 'isfinite', 'isinf', 'isnan', 'signbit', + 'modf', 'ldexp', 'frexp', 'ilogb', 'scalbn', 'lgamma', + 'remquo', 'nan', 'fma', + 'jn', 'yn' +] # These functions are imported correctly as-is. OkayFunctions = ['j0', 'j1', 'y0', 'y1'] # These functions are not supported for various reasons. -UnhandledFunctions = ['math_errhandling', 'scalbln', - 'lrint', 'lround', 'llrint', 'llround', 'nexttoward', - 'isgreater', 'isgreaterequal', 'isless', 'islessequal', - 'islessgreater', 'isunordered', '__exp10', - '__sincos', '__cospi', '__sinpi', '__tanpi', '__sincospi'] +UnhandledFunctions = [ + 'math_errhandling', 'scalbln', + 'lrint', 'lround', 'llrint', 'llround', 'nexttoward', + 'isgreater', 'isgreaterequal', 'isless', 'islessequal', + 'islessgreater', 'isunordered', '__exp10', + '__sincos', '__cospi', '__sinpi', '__tanpi', '__sincospi' +] def AllFloatTypes(): diff --git a/stdlib/public/SDK/Dispatch/Dispatch.mm b/stdlib/public/SDK/Dispatch/Dispatch.mm index 0cc51299795cc..a8cbf16120366 100644 --- a/stdlib/public/SDK/Dispatch/Dispatch.mm +++ b/stdlib/public/SDK/Dispatch/Dispatch.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Dispatch/Dispatch.swift b/stdlib/public/SDK/Dispatch/Dispatch.swift index 9bf1718d5dfaf..ddadf38ae5cd4 100644 --- a/stdlib/public/SDK/Dispatch/Dispatch.swift +++ b/stdlib/public/SDK/Dispatch/Dispatch.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Foundation/CMakeLists.txt b/stdlib/public/SDK/Foundation/CMakeLists.txt index f8e2f47b81657..36e0f7c5bdc93 100644 --- a/stdlib/public/SDK/Foundation/CMakeLists.txt +++ b/stdlib/public/SDK/Foundation/CMakeLists.txt @@ -1,6 +1,5 @@ add_swift_library(swiftFoundation IS_SDK_OVERLAY Foundation.swift - FoundationMirrors.swift.gyb NSError.swift NSStringAPI.swift NSValue.swift diff --git a/stdlib/public/SDK/Foundation/ExtraStringAPIs.swift b/stdlib/public/SDK/Foundation/ExtraStringAPIs.swift index 5996dcfa40b1f..bde1205bfcb6f 100644 --- a/stdlib/public/SDK/Foundation/ExtraStringAPIs.swift +++ b/stdlib/public/SDK/Foundation/ExtraStringAPIs.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Foundation/Foundation.swift b/stdlib/public/SDK/Foundation/Foundation.swift index 2fc82a3e34ad6..534a9a88b10d1 100644 --- a/stdlib/public/SDK/Foundation/Foundation.swift +++ b/stdlib/public/SDK/Foundation/Foundation.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -313,8 +313,7 @@ extension Bool: _ObjectiveCBridgeable { } public init(_ number: NSNumber) { - if number.boolValue { self = true } - else { self = false } + self = number.boolValue } public static func _getObjectiveCType() -> Any.Type { @@ -860,7 +859,7 @@ public func _convertNSSetToSet(s: NSSet?) -> Set { return result! } -// Set is conditionally bridged to NSSet +// Set is conditionally bridged to NSSet extension Set : _ObjectiveCBridgeable { public static func _getObjectiveCType() -> Any.Type { return NSSet.self @@ -1044,15 +1043,28 @@ extension CGRectEdge { public typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer +// Note: NSErrorPointer becomes ErrorPointer in Swift 3. +public typealias ErrorPointer = NSErrorPointer + +public // COMPILER_INTRINSIC +let _nilObjCError: ErrorType = _GenericObjCError.NilError + @warn_unused_result @_silgen_name("swift_convertNSErrorToErrorType") public // COMPILER_INTRINSIC -func _convertNSErrorToErrorType(error: NSError?) -> ErrorType +func _convertNSErrorToErrorType(error: NSError?) -> ErrorType { + if let error = error { + return error + } + return _nilObjCError +} @warn_unused_result @_silgen_name("swift_convertErrorTypeToNSError") public // COMPILER_INTRINSIC -func _convertErrorTypeToNSError(error: ErrorType) -> NSError +func _convertErrorTypeToNSError(error: ErrorType) -> NSError { + return unsafeDowncast(_bridgeErrorTypeToNSError(error)) +} //===----------------------------------------------------------------------===// // Variadic initializers and methods @@ -1161,7 +1173,7 @@ extension NSOrderedSet : ArrayLiteralConvertible { //===--- "Copy constructors" ----------------------------------------------===// // These are needed to make Cocoa feel natural since we eliminated -// implicit briding conversions from Objective-C to Swift +// implicit bridging conversions from Objective-C to Swift //===----------------------------------------------------------------------===// extension NSArray { @@ -1364,6 +1376,10 @@ extension NSKeyedUnarchiver { } } +//===----------------------------------------------------------------------===// +// NSURL +//===----------------------------------------------------------------------===// + extension NSURL : _FileReferenceLiteralConvertible { private convenience init(failableFileReferenceLiteral path: String) { let fullPath = NSBundle.mainBundle().pathForResource(path, ofType: nil)! @@ -1376,3 +1392,62 @@ extension NSURL : _FileReferenceLiteralConvertible { } public typealias _FileReferenceLiteralType = NSURL + +//===----------------------------------------------------------------------===// +// Mirror/Quick Look Conformance +//===----------------------------------------------------------------------===// + +extension NSURL : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .URL(absoluteString) + } +} + +extension NSRange : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: ["location": location, "length": length]) + } +} + +extension NSRange : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Range(Int64(location), Int64(length)) + } +} + +extension NSDate : CustomPlaygroundQuickLookable { + var summary: String { + let df = NSDateFormatter() + df.dateStyle = .MediumStyle + df.timeStyle = .ShortStyle + return df.stringFromDate(self) + } + + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(summary) + } +} + +extension NSSet : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(reflecting: self as Set) + } +} + +extension NSString : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(self as String) + } +} + +extension NSArray : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(reflecting: self as [AnyObject]) + } +} + +extension NSDictionary : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(reflecting: self as [NSObject : AnyObject]) + } +} diff --git a/stdlib/public/SDK/Foundation/FoundationMirrors.swift.gyb b/stdlib/public/SDK/Foundation/FoundationMirrors.swift.gyb deleted file mode 100644 index 8e0d0f3957d4c..0000000000000 --- a/stdlib/public/SDK/Foundation/FoundationMirrors.swift.gyb +++ /dev/null @@ -1,156 +0,0 @@ -//===----------------------------------------------------------*- swift -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../../common/MirrorBoilerplate.gyb") - -// helper functions - these Mirrors are dissimilar enough that it's -// probably not worth trying to write one unique generator - let's -// just use these helpers manually and write the bulk of each one -%{ -def getMirrorConformance(Self,Disp = None): - return gyb.executeTemplate( - TMirrorConformance,introspecteeType=Self,disposition=Disp) - -def getMirrorBoilerplate(Self,Disp = None): - return gyb.executeTemplate( - TMirrorBoilerplate,introspecteeType=Self,disposition=Disp) - -def getMirrorDecl(Self,Disp = None): - return gyb.executeTemplate(TMirrorDecl,introspecteeType=Self,disposition=Disp) -}% - -// actual Mirrors -${getMirrorDecl("NSURL")} { - ${getMirrorBoilerplate("NSURL")} - - var count: Int { get { return 0 } } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { get { return _value.absoluteString } } - - var quickLookObject: PlaygroundQuickLook? { return .Some(.URL(summary)) } -} - -${getMirrorDecl("NSRange")} { - ${getMirrorBoilerplate("NSRange")} - - var count: Int { get { return 2 } } - - subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: return ("location", _reflect(_value.location)) - case 1: return ("length", _reflect(_value.length)) - default: _preconditionFailure("_MirrorType access out of bounds") - } - } - - var summary: String { return "(\(_value.location),\(_value.length))" } - - var quickLookObject: PlaygroundQuickLook? { - return .Some(.Range(Int64(_value.location),Int64(_value.length))) - } -} - -${getMirrorDecl("NSDate")} { - ${getMirrorBoilerplate("NSDate")} - - var count: Int { get { return 0 } } - - subscript(i: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { - let df = NSDateFormatter() - df.dateStyle = .MediumStyle - df.timeStyle = .ShortStyle - return df.stringFromDate(_value) - } - - var quickLookObject: PlaygroundQuickLook? { return .Some(.Text(summary)) } -} - -${getMirrorDecl("NSSet","MembershipContainer")} { - var _a : NSArray! - var _value: NSSet - - init(_ x: NSSet) { - _value = x - _a = _value.allObjects as NSArray - } - - var disposition: _MirrorDisposition { return .MembershipContainer } - - var value: Any { return _value } - - var valueType: Any.Type { return (_value as Any).dynamicType } - - var objectIdentifier: ObjectIdentifier? { return .None } - - // this is the only member that needs to validate _a - others either don't touch it or call into this - var count: Int { - if _a != nil { - return _a.count - } - return 0 - } - - subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - return ("[\(i)]", _reflect(_a[i])) - } - - var summary: String { return "\(count) elements" } - - var quickLookObject: PlaygroundQuickLook? { return nil } -} - -${getMirrorDecl("NSString")} { - ${getMirrorBoilerplate("NSString")} - - var count: Int { get { return 0 } } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { get { return _value as String } } - - var quickLookObject: PlaygroundQuickLook? { return .Some(.Text(summary)) } -} - -// conformances -${getMirrorConformance("NSURL")} -${getMirrorConformance("NSRange")} -${getMirrorConformance("NSDate")} -${getMirrorConformance("NSSet","MembershipContainer")} -${getMirrorConformance("NSString")} - -extension NSArray : _Reflectable { - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _reflect(self as [AnyObject]) - } -} -extension NSDictionary : _Reflectable { - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - let dict: [NSObject : AnyObject] = _convertNSDictionaryToDictionary(self) - return _reflect(dict) - } -} diff --git a/stdlib/public/SDK/Foundation/NSError.swift b/stdlib/public/SDK/Foundation/NSError.swift index 3d2279b41bff5..d31a7d8747b17 100644 --- a/stdlib/public/SDK/Foundation/NSError.swift +++ b/stdlib/public/SDK/Foundation/NSError.swift @@ -26,14 +26,6 @@ public enum _GenericObjCError : ErrorType { case NilError } -/// An intrinsic used by the runtime to create an error when an -/// Objective-C API indicates failure but produces a nil error. -@warn_unused_result -@_silgen_name("swift_allocNilObjCError") -public func _allocNilObjCError() -> ErrorType { - return _GenericObjCError.NilError -} - /// An internal protocol to represent Swift error enums that map to standard /// Cocoa NSError domains. public protocol _ObjectiveCBridgeableErrorType : ErrorType { @@ -61,7 +53,7 @@ public func _stdlib_bridgeNSErrorToErrorType< } } -/// Helper protocol for _BridgedNSError, which used used to provide +/// Helper protocol for _BridgedNSError, which used to provide /// default implementations. public protocol __BridgedNSError : RawRepresentable, ErrorType { static var _NSErrorDomain: String { get } diff --git a/stdlib/public/SDK/Foundation/NSStringAPI.swift b/stdlib/public/SDK/Foundation/NSStringAPI.swift index feabe11ed6f9f..6276be228dcfc 100644 --- a/stdlib/public/SDK/Foundation/NSStringAPI.swift +++ b/stdlib/public/SDK/Foundation/NSStringAPI.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -103,7 +103,7 @@ extension String { /// memory referred to by `index` func _withOptionalOutParameter( index: UnsafeMutablePointer, - @noescape body: (UnsafeMutablePointer)->Result + @noescape body: (UnsafeMutablePointer) -> Result ) -> Result { var utf16Index: Int = 0 let result = index._withBridgeValue(&utf16Index) { @@ -118,7 +118,7 @@ extension String { /// it into the memory referred to by `range` func _withOptionalOutParameter( range: UnsafeMutablePointer>, - @noescape body: (UnsafeMutablePointer)->Result + @noescape body: (UnsafeMutablePointer) -> Result ) -> Result { var nsRange = NSRange(location: 0, length: 0) let result = range._withBridgeValue(&nsRange) { @@ -134,7 +134,7 @@ extension String { // + (const NSStringEncoding *)availableStringEncodings /// Returns an Array of the encodings string objects support - /// in the application’s environment. + /// in the application's environment. @warn_unused_result public static func availableStringEncodings() -> [NSStringEncoding] { var result = [NSStringEncoding]() @@ -302,7 +302,7 @@ extension String { /// Returns a string containing characters the `String` and a /// given string have in common, starting from the beginning of each - /// up to the first characters that aren’t equivalent. + /// up to the first characters that aren't equivalent. @warn_unused_result public func commonPrefixWithString( aString: String, options: NSStringCompareOptions) -> String { @@ -452,7 +452,7 @@ extension String { // @property NSString* decomposedStringWithCanonicalMapping; - /// Returns a string made by normalizing the `String`’s + /// Returns a string made by normalizing the `String`'s /// contents using Form D. public var decomposedStringWithCanonicalMapping: String { return _ns.decomposedStringWithCanonicalMapping @@ -460,7 +460,7 @@ extension String { // @property NSString* decomposedStringWithCompatibilityMapping; - /// Returns a string made by normalizing the `String`’s + /// Returns a string made by normalizing the `String`'s /// contents using Form KD. public var decomposedStringWithCompatibilityMapping: String { return _ns.decomposedStringWithCompatibilityMapping @@ -479,7 +479,7 @@ extension String { // enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block /// Enumerates all the lines in a string. - public func enumerateLines(body: (line: String, inout stop: Bool)->()) { + public func enumerateLines(body: (line: String, inout stop: Bool) -> ()) { _ns.enumerateLinesUsingBlock { (line: String, stop: UnsafeMutablePointer) in @@ -511,7 +511,7 @@ extension String { options opts: NSLinguisticTaggerOptions, orthography: NSOrthography?, _ body: - (String, Range, Range, inout Bool)->() + (String, Range, Range, inout Bool) -> () ) { _ns.enumerateLinguisticTagsInRange( _toNSRange(range), @@ -546,7 +546,7 @@ extension String { _ body: ( substring: String?, substringRange: Range, enclosingRange: Range, inout Bool - )->() + ) -> () ) { _ns.enumerateSubstringsInRange(_toNSRange(range), options: opts) { var stop_ = false @@ -605,7 +605,7 @@ extension String { /// - Parameter encoding: The encoding to use for the returned bytes. /// /// - Parameter options: A mask to specify options to use for - /// converting the receiver’s contents to `encoding` (if conversion + /// converting the receiver's contents to `encoding` (if conversion /// is necessary). /// /// - Parameter range: The range of characters in the receiver to get. @@ -645,7 +645,7 @@ extension String { // maxLength:(NSUInteger)maxBufferCount // encoding:(NSStringEncoding)encoding - /// Converts the `String`’s content to a given encoding and + /// Converts the `String`'s content to a given encoding and /// stores them in a buffer. /// - Note: will store a maximum of `min(buffer.count, maxLength)` bytes. public func getCString( @@ -923,7 +923,7 @@ extension String { /// Returns a `String` object initialized by using a given /// format string as a template into which the remaining argument - /// values are substituted according to the user’s default locale. + /// values are substituted according to the user's default locale. public init(format: String, arguments: [CVarArgType]) { self = String(format: format, locale: nil, arguments: arguments) } @@ -1120,7 +1120,7 @@ extension String { // @property NSString* pathExtension; /// Interprets the `String` as a path and returns the - /// `String`’s extension, if any. + /// `String`'s extension, if any. @available(*, unavailable, message="Use pathExtension on NSURL instead.") public var pathExtension: String { return _ns.pathExtension @@ -1128,7 +1128,7 @@ extension String { // @property NSString* precomposedStringWithCanonicalMapping; - /// Returns a string made by normalizing the `String`’s + /// Returns a string made by normalizing the `String`'s /// contents using Form C. public var precomposedStringWithCanonicalMapping: String { return _ns.precomposedStringWithCanonicalMapping @@ -1136,7 +1136,7 @@ extension String { // @property NSString * precomposedStringWithCompatibilityMapping; - /// Returns a string made by normalizing the `String`’s + /// Returns a string made by normalizing the `String`'s /// contents using Form KC. public var precomposedStringWithCompatibilityMapping: String { return _ns.precomposedStringWithCompatibilityMapping @@ -1181,7 +1181,7 @@ extension String { aSet: NSCharacterSet, options mask:NSStringCompareOptions = [], range aRange: Range? = nil - )-> Range? { + ) -> Range? { return _optionalRange( _ns.rangeOfCharacterFromSet( aSet, options: mask, @@ -1537,7 +1537,7 @@ extension String { // - (NSArray *)stringsByAppendingPaths:(NSArray *)paths /// Returns an array of strings made by separately appending - /// to the `String` each string in in a given array. + /// to the `String` each string in a given array. @available(*, unavailable, message="map over paths with URLByAppendingPathComponent instead.") public func stringsByAppendingPaths(paths: [String]) -> [String] { return _ns.stringsByAppendingPaths(paths) diff --git a/stdlib/public/SDK/Foundation/NSValue.swift b/stdlib/public/SDK/Foundation/NSValue.swift index 8b5cd61e931af..820fd3e13e51a 100644 --- a/stdlib/public/SDK/Foundation/NSValue.swift +++ b/stdlib/public/SDK/Foundation/NSValue.swift @@ -1,8 +1,8 @@ -//===--- NSValue.swift - Bridging things in NSValue -------------*-swift-*-===// +//===--- NSValue.swift - Bridging things in NSValue -----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/Foundation/Thunks.mm b/stdlib/public/SDK/Foundation/Thunks.mm index fd1acbbb0d701..db45d8e2bc731 100644 --- a/stdlib/public/SDK/Foundation/Thunks.mm +++ b/stdlib/public/SDK/Foundation/Thunks.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/GLKit/GLKit.swift.gyb b/stdlib/public/SDK/GLKit/GLKit.swift.gyb index a8f76d51c1d76..01d58fb9c4aaa 100644 --- a/stdlib/public/SDK/GLKit/GLKit.swift.gyb +++ b/stdlib/public/SDK/GLKit/GLKit.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/GameplayKit/GameplayKit.mm b/stdlib/public/SDK/GameplayKit/GameplayKit.mm index 611526acf36b4..bcd0b4f4e5724 100644 --- a/stdlib/public/SDK/GameplayKit/GameplayKit.mm +++ b/stdlib/public/SDK/GameplayKit/GameplayKit.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/GameplayKit/GameplayKit.swift b/stdlib/public/SDK/GameplayKit/GameplayKit.swift index dc0bbd8726279..e65365105e70b 100644 --- a/stdlib/public/SDK/GameplayKit/GameplayKit.swift +++ b/stdlib/public/SDK/GameplayKit/GameplayKit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift b/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift index 31cbc10a6fa8a..c7d6a6cc7ecee 100644 --- a/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift +++ b/stdlib/public/SDK/ObjectiveC/ObjectiveC.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,10 +60,10 @@ public struct ObjCBool : BooleanType, BooleanLiteralConvertible { } } -extension ObjCBool : _Reflectable { +extension ObjCBool : CustomReflectable { /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _reflect(boolValue) + public func customMirror() -> Mirror { + return Mirror(reflecting: boolValue) } } @@ -167,10 +167,10 @@ extension String { } } -extension Selector : _Reflectable { +extension Selector : CustomReflectable { /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _reflect(String(_sel: self)) + public func customMirror() -> Mirror { + return Mirror(reflecting: String(_sel: self)) } } @@ -190,6 +190,9 @@ public struct NSZone : NilLiteralConvertible { } } +// Note: NSZone becomes Zone in Swift 3. +typealias Zone = NSZone + //===----------------------------------------------------------------------===// // FIXME: @autoreleasepool substitute //===----------------------------------------------------------------------===// diff --git a/stdlib/public/SDK/OpenCL/OpenCL.swift b/stdlib/public/SDK/OpenCL/OpenCL.swift index 7d03dff926446..0a3012a9f5a95 100644 --- a/stdlib/public/SDK/OpenCL/OpenCL.swift +++ b/stdlib/public/SDK/OpenCL/OpenCL.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/SceneKit/SceneKit.swift b/stdlib/public/SDK/SceneKit/SceneKit.swift index 176b4dc155fb5..d78d1017d4e2b 100644 --- a/stdlib/public/SDK/SceneKit/SceneKit.swift +++ b/stdlib/public/SDK/SceneKit/SceneKit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/SceneKit/Thunks.mm b/stdlib/public/SDK/SceneKit/Thunks.mm index a92639fe4682a..733fc48d7031f 100644 --- a/stdlib/public/SDK/SceneKit/Thunks.mm +++ b/stdlib/public/SDK/SceneKit/Thunks.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/SpriteKit/CMakeLists.txt b/stdlib/public/SDK/SpriteKit/CMakeLists.txt index 1fc4a21819c62..b16bce8598903 100644 --- a/stdlib/public/SDK/SpriteKit/CMakeLists.txt +++ b/stdlib/public/SDK/SpriteKit/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_library(swiftSpriteKit IS_SDK_OVERLAY SpriteKit.swift - SpriteKitMirrors.swift.gyb + SpriteKitQuickLooks.swift.gyb TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR SWIFT_MODULE_DEPENDS Foundation GLKit simd AVFoundation diff --git a/stdlib/public/SDK/SpriteKit/SpriteKit.swift b/stdlib/public/SDK/SpriteKit/SpriteKit.swift index 2ad3548dbccb6..d03e5922e3db0 100644 --- a/stdlib/public/SDK/SpriteKit/SpriteKit.swift +++ b/stdlib/public/SDK/SpriteKit/SpriteKit.swift @@ -15,18 +15,3 @@ public typealias SKColor = UIColor override init() { _sanityCheckFailure("don't touch me") } @objc func _copyImageData() -> NSData! { return nil } } - -extension SKNode { - public subscript (name: String) -> [SKNode] { - // Note: Don't stomp on objectForKeyedSubscript: - @objc(_swiftObjectForKeyedSubscript:) get { - var nodes = [SKNode]() - enumerateChildNodesWithName(name) { node, stop in - nodes.append(node) - } - - return nodes - } - } -} - diff --git a/stdlib/public/SDK/SpriteKit/SpriteKitMirrors.swift.gyb b/stdlib/public/SDK/SpriteKit/SpriteKitMirrors.swift.gyb deleted file mode 100644 index 4f42d6b19230f..0000000000000 --- a/stdlib/public/SDK/SpriteKit/SpriteKitMirrors.swift.gyb +++ /dev/null @@ -1,51 +0,0 @@ -//===----------------------------------------------------------*- swift -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../../common/MirrorBoilerplate.gyb") - -% for Self in ['SKShapeNode','SKSpriteNode','SKTextureAtlas','SKTexture']: -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,introspecteeType=Self) -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,introspecteeType=Self) -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,introspecteeType=Self) - -${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return 0 } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { return _value.description } - - var quickLookObject: PlaygroundQuickLook? { - // this code comes straight from the quicklooks - - guard let data = (_value as AnyObject)._copyImageData?() else { return nil } - // we could send a Raw, but I don't want to make a copy of the - // bytes for no good reason make an NSImage out of them and - // send that -#if os(OSX) - let img = NSImage(data: data) -#elseif os(iOS) || os(watchOS) || os(tvOS) - let img = UIImage(data: data) -#endif - return .Some(.Sprite(img)) - } - -} - -${MirrorConformance} diff --git a/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb b/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb new file mode 100644 index 0000000000000..3632c7d2e0622 --- /dev/null +++ b/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb @@ -0,0 +1,39 @@ +//===----------------------------------------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +%import gyb + +% for Self in ['SKShapeNode', 'SKSpriteNode', 'SKTextureAtlas', 'SKTexture']: + +extension ${Self} : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + // this code comes straight from the quicklooks + + let data = (self as AnyObject)._copyImageData?() + // we could send a Raw, but I don't want to make a copy of the + // bytes for no good reason make an NSImage out of them and + // send that +#if os(OSX) + if let data = data { + return .Sprite(NSImage(data: data)) + } else { + return .Sprite(NSImage()) + } +#elseif os(iOS) || os(watchOS) || os(tvOS) + if let data = data { + return .Sprite(UIImage(data: data)) + } else { + return .Sprite(UIImage()) + } +#endif + } +} diff --git a/stdlib/public/SDK/UIKit/DesignatedInitializers.mm b/stdlib/public/SDK/UIKit/DesignatedInitializers.mm index 297f6f2ef5926..efd85a3eb4cd4 100644 --- a/stdlib/public/SDK/UIKit/DesignatedInitializers.mm +++ b/stdlib/public/SDK/UIKit/DesignatedInitializers.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift index d4e4b47e7c038..7dfb8380e8415 100644 --- a/stdlib/public/SDK/UIKit/UIKit.swift +++ b/stdlib/public/SDK/UIKit/UIKit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -47,25 +47,23 @@ extension UIOffset : Equatable {} #if !os(watchOS) && !os(tvOS) public extension UIDeviceOrientation { var isLandscape: Bool { - get { return self == .LandscapeLeft || self == .LandscapeRight } + return self == .LandscapeLeft || self == .LandscapeRight } var isPortrait: Bool { - get { return self == .Portrait || self == .PortraitUpsideDown } + return self == .Portrait || self == .PortraitUpsideDown } var isFlat: Bool { - get { return self == .FaceUp || self == .FaceDown } + return self == .FaceUp || self == .FaceDown } var isValidInterfaceOrientation: Bool { - get { - switch (self) { - case .Portrait, .PortraitUpsideDown, .LandscapeLeft, .LandscapeRight: - return true - default: - return false - } + switch (self) { + case .Portrait, .PortraitUpsideDown, .LandscapeLeft, .LandscapeRight: + return true + default: + return false } } } @@ -99,11 +97,11 @@ public func UIDeviceOrientationIsValidInterfaceOrientation( #if !os(watchOS) && !os(tvOS) public extension UIInterfaceOrientation { var isLandscape: Bool { - get { return self == .LandscapeLeft || self == .LandscapeRight } + return self == .LandscapeLeft || self == .LandscapeRight } var isPortrait: Bool { - get { return self == .Portrait || self == .PortraitUpsideDown } + return self == .Portrait || self == .PortraitUpsideDown } } @@ -168,74 +166,37 @@ public extension UIAlertView { #endif #if !os(watchOS) -struct _UIViewMirror : _MirrorType { - static var _views = NSMutableSet() +internal struct _UIViewQuickLookState { + static var views = Set() +} - var _v : UIView - - init(_ v : UIView) { _v = v } - - var value: Any { get { return _v } } - - var valueType: Any.Type { get { return (_v as Any).dynamicType } } - - var objectIdentifier: ObjectIdentifier? { get { return .None } } - - var count: Int { get { return 0 } } - - subscript(_: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } +extension UIView : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + if _UIViewQuickLookState.views.contains(self) { + return .View(UIImage()) + } else { + _UIViewQuickLookState.views.insert(self) + // in case of an empty rectangle abort the logging + if (bounds.size.width == 0) || (bounds.size.height == 0) { + return .View(UIImage()) + } - var summary: String { get { return "" } } + UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0) + // UIKit is about to update this to be optional, so make it work + // with both older and newer SDKs. (In this context it should always + // be present.) + let ctx: CGContext! = UIGraphicsGetCurrentContext() + UIColor(white:1.0, alpha:0.0).set() + CGContextFillRect(ctx, bounds) + layer.renderInContext(ctx) + + let image: UIImage! = UIGraphicsGetImageFromCurrentImageContext() - var quickLookObject: PlaygroundQuickLook? { - // iOS 7 or greater only - - var result: PlaygroundQuickLook? = nil - - switch _UIViewMirror._views.member(_v) { - case nil: - _UIViewMirror._views.addObject(_v) - - let bounds = _v.bounds - // in case of an empty rectangle abort the logging - if (bounds.size.width == 0) || (bounds.size.height == 0) { - return nil - } - - UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0) - - // UIKit is about to update this to be optional, so make it work - // with both older and newer SDKs. (In this context it should always - // be present.) - let ctx: CGContext! = UIGraphicsGetCurrentContext() - UIColor(white:1.0, alpha:0.0).set() - CGContextFillRect(ctx, bounds) - _v.layer.renderInContext(ctx) - - let image: UIImage! = UIGraphicsGetImageFromCurrentImageContext() - - UIGraphicsEndImageContext() - - result = .Some(.View(image)) - - _UIViewMirror._views.removeObject(_v) - - default: () - } - - - return result - } + UIGraphicsEndImageContext() - var disposition : _MirrorDisposition { get { return .Aggregate } } -} - -extension UIView : _Reflectable { - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _UIViewMirror(self) + _UIViewQuickLookState.views.remove(self) + return .View(image) + } } } #endif diff --git a/stdlib/public/SDK/WatchKit/WatchKit.swift b/stdlib/public/SDK/WatchKit/WatchKit.swift index 0b181e5c5c7a2..0bf1b20e813cb 100644 --- a/stdlib/public/SDK/WatchKit/WatchKit.swift +++ b/stdlib/public/SDK/WatchKit/WatchKit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SDK/XCTest/XCTest.swift b/stdlib/public/SDK/XCTest/XCTest.swift index e5b0309d432b3..7b8166db1ad73 100644 --- a/stdlib/public/SDK/XCTest/XCTest.swift +++ b/stdlib/public/SDK/XCTest/XCTest.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,10 +20,10 @@ import CoreGraphics // --- Failure Formatting --- /// Register the failure, expected or unexpected, of the current test case. -func _XCTRegisterFailure(expected: Bool, _ condition: String, _ message: String, _ file: String, _ line: UInt) -> Void { +func _XCTRegisterFailure(expected: Bool, _ condition: String, @autoclosure _ message: () -> String, _ file: StaticString, _ line: UInt) -> Void { // Call the real _XCTFailureHandler. let test = _XCTCurrentTestCaseBridge() - _XCTPreformattedFailureHandler(test, expected, file, line, condition, message) + _XCTPreformattedFailureHandler(test, expected, file.stringValue, line, condition, message()) } /// Produce a failure description for the given assertion type. @@ -49,16 +49,27 @@ func _XCTRunThrowableBlockBridge(@noescape _: @convention(block) () -> Void) -> /// The Swift-style result of evaluating a block which may throw an exception. enum _XCTThrowableBlockResult { case Success + case FailedWithError(error: ErrorType) case FailedWithException(className: String, name: String, reason: String) case FailedWithUnknownException } -/// Asks some Objective-C code to evaluate a block which may throw an exception, +/// Asks some Objective-C code to evaluate a block which may throw an exception or error, /// and if it does consume the exception and return information about it. -func _XCTRunThrowableBlock(@noescape block: () -> Void) -> _XCTThrowableBlockResult { - let d = _XCTRunThrowableBlockBridge(block) +func _XCTRunThrowableBlock(@noescape block: () throws -> Void) -> _XCTThrowableBlockResult { + var blockErrorOptional: ErrorType? + + let d = _XCTRunThrowableBlockBridge({ + do { + try block() + } catch { + blockErrorOptional = error + } + }) - if d.count > 0 { + if let blockError = blockErrorOptional { + return .FailedWithError(error: blockError) + } else if d.count > 0 { let t: String = d["type"] as! String if t == "objc" { @@ -73,20 +84,20 @@ func _XCTRunThrowableBlock(@noescape block: () -> Void) -> _XCTThrowableBlockRes // --- Supported Assertions --- -public func XCTFail(message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTFail(message: String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Fail _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, "" as NSString), message, file, line) } -public func XCTAssertNil(@autoclosure expression: () -> Any?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Nil // evaluate the expression exactly once var expressionValueOptional: Any? let result = _XCTRunThrowableBlock { - expressionValueOptional = expression() + expressionValueOptional = try expression() } switch result { @@ -107,22 +118,25 @@ public func XCTAssertNil(@autoclosure expression: () -> Any?, _ message: String _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNil failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertNotNil(@autoclosure expression: () -> Any?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotNil // evaluate the expression exactly once var expressionValueOptional: Any? let result = _XCTRunThrowableBlock { - expressionValueOptional = expression() + expressionValueOptional = try expression() } switch result { @@ -143,27 +157,30 @@ public func XCTAssertNotNil(@autoclosure expression: () -> Any?, _ message: Stri _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotNil failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssert( @autoclosure expression: () -> BooleanType, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssert( @autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { // XCTAssert is just a cover for XCTAssertTrue. XCTAssertTrue(expression, message, file: file, line: line) } -public func XCTAssertTrue(@autoclosure expression: () -> BooleanType, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertTrue(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.True // evaluate the expression exactly once var expressionValueOptional: Bool? let result = _XCTRunThrowableBlock { - expressionValueOptional = expression().boolValue + expressionValueOptional = try expression().boolValue } switch result { @@ -176,22 +193,25 @@ public func XCTAssertTrue(@autoclosure expression: () -> BooleanType, _ message: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertTrue failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertFalse(@autoclosure expression: () -> BooleanType, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertFalse(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.False // evaluate the expression exactly once var expressionValueOptional: Bool? let result = _XCTRunThrowableBlock { - expressionValueOptional = expression().boolValue + expressionValueOptional = try expression().boolValue } switch result { @@ -204,15 +224,18 @@ public func XCTAssertFalse(@autoclosure expression: () -> BooleanType, _ message _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertFalse failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertEqual(@autoclosure expression1: () -> T?, @autoclosure _ expression2: () -> T?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqual(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Equal // evaluate each expression exactly once @@ -220,8 +243,8 @@ public func XCTAssertEqual(@autoclosure expression1: () -> T?, @a var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -236,8 +259,11 @@ public func XCTAssertEqual(@autoclosure expression1: () -> T?, @a _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) @@ -250,7 +276,7 @@ public func XCTAssertEqual(@autoclosure expression1: () -> T?, @a // Array // Dictionary -public func XCTAssertEqual(@autoclosure expression1: () -> ArraySlice, @autoclosure _ expression2: () -> ArraySlice, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqual(@autoclosure expression1: () throws -> ArraySlice, @autoclosure _ expression2: () throws -> ArraySlice, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Equal // evaluate each expression exactly once @@ -258,8 +284,8 @@ public func XCTAssertEqual(@autoclosure expression1: () -> ArrayS var expressionValue2Optional: ArraySlice? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -277,15 +303,18 @@ public func XCTAssertEqual(@autoclosure expression1: () -> ArrayS _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertEqual(@autoclosure expression1: () -> ContiguousArray, @autoclosure _ expression2: () -> ContiguousArray, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqual(@autoclosure expression1: () throws -> ContiguousArray, @autoclosure _ expression2: () throws -> ContiguousArray, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Equal // evaluate each expression exactly once @@ -293,8 +322,8 @@ public func XCTAssertEqual(@autoclosure expression1: () -> Contig var expressionValue2Optional: ContiguousArray? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -312,15 +341,18 @@ public func XCTAssertEqual(@autoclosure expression1: () -> Contig _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertEqual(@autoclosure expression1: () -> [T], @autoclosure _ expression2: () -> [T], _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqual(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Equal // evaluate each expression exactly once @@ -328,8 +360,8 @@ public func XCTAssertEqual(@autoclosure expression1: () -> [T], @ var expressionValue2Optional: [T]? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -347,15 +379,18 @@ public func XCTAssertEqual(@autoclosure expression1: () -> [T], @ _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertEqual(@autoclosure expression1: () -> [T: U], @autoclosure _ expression2: () -> [T: U], _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqual(@autoclosure expression1: () throws -> [T: U], @autoclosure _ expression2: () throws -> [T: U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Equal // evaluate each expression exactly once @@ -363,8 +398,8 @@ public func XCTAssertEqual(@autoclosure expression1: () -> [T: var expressionValue2Optional: [T: U]? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -382,15 +417,18 @@ public func XCTAssertEqual(@autoclosure expression1: () -> [T: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertNotEqual(@autoclosure expression1: () -> T?, @autoclosure _ expression2: () -> T?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqual(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqual // evaluate each expression exactly once @@ -398,8 +436,8 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> T?, var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -414,8 +452,11 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> T?, _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) @@ -428,7 +469,7 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> T?, // Array // Dictionary -public func XCTAssertNotEqual(@autoclosure expression1: () -> ContiguousArray, @autoclosure _ expression2: () -> ContiguousArray, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqual(@autoclosure expression1: () throws -> ContiguousArray, @autoclosure _ expression2: () throws -> ContiguousArray, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqual // evaluate each expression exactly once @@ -436,8 +477,8 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> Con var expressionValue2Optional: ContiguousArray? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -455,15 +496,18 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> Con _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertNotEqual(@autoclosure expression1: () -> ArraySlice, @autoclosure _ expression2: () -> ArraySlice, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqual(@autoclosure expression1: () throws -> ArraySlice, @autoclosure _ expression2: () throws -> ArraySlice, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqual // evaluate each expression exactly once @@ -471,8 +515,8 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> Arr var expressionValue2Optional: ArraySlice? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -490,15 +534,18 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> Arr _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertNotEqual(@autoclosure expression1: () -> [T], @autoclosure _ expression2: () -> [T], _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqual(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqual // evaluate each expression exactly once @@ -506,8 +553,8 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> [T] var expressionValue2Optional: [T]? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -525,15 +572,18 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> [T] _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertNotEqual(@autoclosure expression1: () -> [T: U], @autoclosure _ expression2: () -> [T: U], _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqual(@autoclosure expression1: () throws -> [T: U], @autoclosure _ expression2: () throws -> [T: U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqual // evaluate each expression exactly once @@ -541,8 +591,8 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> var expressionValue2Optional: [T: U]? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -560,8 +610,11 @@ public func XCTAssertNotEqual(@autoclosure expression1: () -> _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) @@ -583,7 +636,7 @@ func _XCTCheckEqualWithAccuracy_CGFloat(value1: CGFloat, _ value2: CGFloat, _ ac && (abs(value1 - value2) <= accuracy) } -public func XCTAssertEqualWithAccuracy(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, accuracy: T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertEqualWithAccuracy(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.EqualWithAccuracy // evaluate each expression exactly once @@ -591,8 +644,8 @@ public func XCTAssertEqualWithAccuracy(@autoclosure expre var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -628,8 +681,11 @@ public func XCTAssertEqualWithAccuracy(@autoclosure expre _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString, accuracyStr as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertEqualWithAccuracy failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) @@ -651,7 +707,7 @@ func _XCTCheckNotEqualWithAccuracy_CGFloat(value1: CGFloat, _ value2: CGFloat, _ || (abs(value1 - value2) > accuracy) } -public func XCTAssertNotEqualWithAccuracy(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ accuracy: T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNotEqualWithAccuracy(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, _ accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.NotEqualWithAccuracy // evaluate each expression exactly once @@ -659,8 +715,8 @@ public func XCTAssertNotEqualWithAccuracy(@autoclosure ex var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -696,15 +752,18 @@ public func XCTAssertNotEqualWithAccuracy(@autoclosure ex _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString, accuracyStr as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertNotEqualWithAccuracy failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertGreaterThan(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertGreaterThan(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.GreaterThan // evaluate each expression exactly once @@ -712,8 +771,8 @@ public func XCTAssertGreaterThan(@autoclosure expression1: () -> var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -731,15 +790,18 @@ public func XCTAssertGreaterThan(@autoclosure expression1: () -> _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertGreaterThan failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertGreaterThanOrEqual(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) +public func XCTAssertGreaterThanOrEqual(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) { let assertionType = _XCTAssertionType.GreaterThanOrEqual @@ -748,8 +810,8 @@ public func XCTAssertGreaterThanOrEqual(@autoclosure expression1 var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -767,15 +829,18 @@ public func XCTAssertGreaterThanOrEqual(@autoclosure expression1 _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertGreaterThanOrEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertLessThan(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertLessThan(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.LessThan // evaluate each expression exactly once @@ -783,8 +848,8 @@ public func XCTAssertLessThan(@autoclosure expression1: () -> T, var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -802,15 +867,18 @@ public func XCTAssertLessThan(@autoclosure expression1: () -> T, _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertLessThan failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } -public func XCTAssertLessThanOrEqual(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) +public func XCTAssertLessThanOrEqual(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) { let assertionType = _XCTAssertionType.LessThanOrEqual @@ -819,8 +887,8 @@ public func XCTAssertLessThanOrEqual(@autoclosure expression1: ( var expressionValue2Optional: T? let result = _XCTRunThrowableBlock { - expressionValue1Optional = expression1() - expressionValue2Optional = expression2() + expressionValue1Optional = try expression1() + expressionValue2Optional = try expression2() } switch result { @@ -838,48 +906,82 @@ public func XCTAssertLessThanOrEqual(@autoclosure expression1: ( _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 0, expressionValueStr1 as NSString, expressionValueStr2 as NSString), message, file, line) } + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertLessThanOrEqual failed: threw error \"\(error)\"", message, file, line) + case .FailedWithException(_, _, let reason): - _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) + _XCTRegisterFailure(false, _XCTFailureDescription(assertionType, 1, reason as NSString), message, file, line) case .FailedWithUnknownException: _XCTRegisterFailure(true, _XCTFailureDescription(assertionType, 2), message, file, line) } } +public func XCTAssertThrowsError(@autoclosure expression: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__, _ errorHandler: (error: ErrorType) -> Void = { _ in }) -> Void { + // evaluate expression exactly once + var caughtErrorOptional: ErrorType? + + let result = _XCTRunThrowableBlock { + do { + _ = try expression() + } catch { + caughtErrorOptional = error + } + } + + switch result { + case .Success: + if let caughtError = caughtErrorOptional { + errorHandler(error: caughtError) + } else { + _XCTRegisterFailure(true, "XCTAssertThrowsError failed: did not throw an error", message, file, line) + } + + case .FailedWithError(let error): + _XCTRegisterFailure(false, "XCTAssertLessThanOrEqual failed: threw error \"\(error)\"", message, file, line) + + case .FailedWithException(_, _, let reason): + _XCTRegisterFailure(true, "XCTAssertThrowsError failed: throwing \(reason)", message, file, line) + + case .FailedWithUnknownException: + _XCTRegisterFailure(true, "XCTAssertThrowsError failed: throwing an unknown exception", message, file, line) + } +} + #if XCTEST_ENABLE_EXCEPTION_ASSERTIONS // --- Currently-Unsupported Assertions --- -public func XCTAssertThrows(@autoclosure expression: () -> Any?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertThrows(@autoclosure expression: () -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_Throws // FIXME: Unsupported } -public func XCTAssertThrowsSpecific(@autoclosure expression: () -> Any?, _ exception: Any, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertThrowsSpecific(@autoclosure expression: () -> Any?, _ exception: Any, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_ThrowsSpecific // FIXME: Unsupported } -public func XCTAssertThrowsSpecificNamed(@autoclosure expression: () -> Any?, _ exception: Any, _ name: String, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertThrowsSpecificNamed(@autoclosure expression: () -> Any?, _ exception: Any, _ name: String, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_ThrowsSpecificNamed // FIXME: Unsupported } -public func XCTAssertNoThrow(@autoclosure expression: () -> Any?, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNoThrow(@autoclosure expression: () -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_NoThrow // FIXME: Unsupported } -public func XCTAssertNoThrowSpecific(@autoclosure expression: () -> Any?, _ exception: Any, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNoThrowSpecific(@autoclosure expression: () -> Any?, _ exception: Any, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_NoThrowSpecific // FIXME: Unsupported } -public func XCTAssertNoThrowSpecificNamed(@autoclosure expression: () -> Any?, _ exception: Any, _ name: String, _ message: String = "", file: String = __FILE__, line: UInt = __LINE__) -> Void { +public func XCTAssertNoThrowSpecificNamed(@autoclosure expression: () -> Any?, _ exception: Any, _ name: String, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) -> Void { let assertionType = _XCTAssertionType.Assertion_NoThrowSpecificNamed // FIXME: Unsupported diff --git a/stdlib/public/SDK/XCTest/XCTestCaseAdditions.mm b/stdlib/public/SDK/XCTest/XCTestCaseAdditions.mm index 774ae730d9098..55491bfecf82b 100644 --- a/stdlib/public/SDK/XCTest/XCTestCaseAdditions.mm +++ b/stdlib/public/SDK/XCTest/XCTestCaseAdditions.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,6 +12,8 @@ #import #include "swift/Runtime/Metadata.h" +#include "swift/Basic/Demangle.h" +#include "swift/Strings.h" // NOTE: This is a temporary workaround. // XCTestCase needs the unmangled version of a test case name, so let -className @@ -22,6 +24,85 @@ @interface XCTest (WarningAvoidance) @property (readonly, copy) NSString *className; @end +static char *scanIdentifier(const char *&mangled) +{ + const char *original = mangled; + + { + if (*mangled == '0') goto fail; // length may not be zero + + size_t length = 0; + while (swift::Demangle::isDigit(*mangled)) { + size_t oldlength = length; + length *= 10; + length += *mangled++ - '0'; + if (length <= oldlength) goto fail; // integer overflow + } + + if (length == 0) goto fail; + if (length > strlen(mangled)) goto fail; + + char *result = strndup(mangled, length); + assert(result); + mangled += length; + return result; + } + +fail: + mangled = original; // rewind + return nullptr; +} + + +/// \brief Demangle a mangled class name into module+class. +/// Returns true if the name was successfully decoded. +/// On success, *outModule and *outClass must be freed with free(). +/// FIXME: this should be replaced by a real demangler +static bool demangleSimpleClass(const char *mangledName, + char **outModule, char **outClass) { + char *moduleName = nullptr; + char *className = nullptr; + + { + // Prefix for a mangled class + const char *m = mangledName; + if (0 != strncmp(m, "_TtC", 4)) + goto fail; + m += 4; + + // Module name + if (strncmp(m, "Ss", 2) == 0) { + moduleName = strdup(swift::STDLIB_NAME); + assert(moduleName); + m += 2; + } else { + moduleName = scanIdentifier(m); + if (!moduleName) + goto fail; + } + + // Class name + className = scanIdentifier(m); + if (!className) + goto fail; + + // Nothing else + if (strlen(m)) + goto fail; + + *outModule = moduleName; + *outClass = className; + return true; + } + +fail: + if (moduleName) free(moduleName); + if (className) free(className); + *outModule = nullptr; + *outClass = nullptr; + return false; +} + @implementation XCTestCase (SwiftAdditions) - (NSString *)className @@ -30,8 +111,8 @@ - (NSString *)className char *modulePart; char *classPart; - bool ok = swift::swift_demangleSimpleClass([className UTF8String], - &modulePart, &classPart); + bool ok = demangleSimpleClass([className UTF8String], + &modulePart, &classPart); if (ok) { className = [NSString stringWithUTF8String:classPart]; diff --git a/stdlib/public/SDK/simd/simd.swift.gyb b/stdlib/public/SDK/simd/simd.swift.gyb index f3b297667b35d..36b64fa8e49f4 100644 --- a/stdlib/public/SDK/simd/simd.swift.gyb +++ b/stdlib/public/SDK/simd/simd.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,7 +30,7 @@ import Darwin // Workaround % vectype = ctype[type] + str(size) % llvm_vectype = "Vec" + str(size) + "x" + llvm_type[type] -% vecsize = (8 if type == 'Double' else 4)*(2 if size == 2 else 4) +% vecsize = (8 if type == 'Double' else 4) * (2 if size == 2 else 4) % extractelement = "extractelement_" + llvm_vectype + "_Int32" % insertelement = "insertelement_" + llvm_vectype + "_" + llvm_type[type] + "_Int32" % is_floating = type in floating_types diff --git a/stdlib/public/SwiftShims/CoreFoundationShims.h b/stdlib/public/SwiftShims/CoreFoundationShims.h index 515eff44d8256..eb586681299f0 100644 --- a/stdlib/public/SwiftShims/CoreFoundationShims.h +++ b/stdlib/public/SwiftShims/CoreFoundationShims.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/FoundationShims.h b/stdlib/public/SwiftShims/FoundationShims.h index c3d044089207b..82d70bdc814cb 100644 --- a/stdlib/public/SwiftShims/FoundationShims.h +++ b/stdlib/public/SwiftShims/FoundationShims.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/GlobalObjects.h b/stdlib/public/SwiftShims/GlobalObjects.h index 8355f22319b35..8891264fccef6 100644 --- a/stdlib/public/SwiftShims/GlobalObjects.h +++ b/stdlib/public/SwiftShims/GlobalObjects.h @@ -1,8 +1,8 @@ -//===--- GlobalObjects.h - Statically-initialized objects -----------------===// +//===--- GlobalObjects.h - Statically-initialized objects -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/HeapObject.h b/stdlib/public/SwiftShims/HeapObject.h index 9c5c89f8f44ed..caf4cddcfa488 100644 --- a/stdlib/public/SwiftShims/HeapObject.h +++ b/stdlib/public/SwiftShims/HeapObject.h @@ -1,8 +1,8 @@ -//===--- HeapObject.h -----------------------------------------------------===// +//===--- HeapObject.h -------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h index 481a51962f375..605113a14a9d7 100644 --- a/stdlib/public/SwiftShims/LibcShims.h +++ b/stdlib/public/SwiftShims/LibcShims.h @@ -1,8 +1,8 @@ -//===--- LibcShims.h - Access to POSIX for Swift's core stdlib -----------===// +//===--- LibcShims.h - Access to POSIX for Swift's core stdlib --*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/RefCount.h b/stdlib/public/SwiftShims/RefCount.h index 648199fcc943f..fcb2a14211963 100644 --- a/stdlib/public/SwiftShims/RefCount.h +++ b/stdlib/public/SwiftShims/RefCount.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -275,8 +275,6 @@ class WeakRefCount { enum : uint32_t { // There isn't really a flag here. - // Making weak RC_ONE == strong RC_ONE saves an - // instruction in allocation on arm64. RC_UNUSED_FLAG = 1, RC_FLAGS_COUNT = 1, diff --git a/stdlib/public/SwiftShims/RuntimeShims.h b/stdlib/public/SwiftShims/RuntimeShims.h index 2dbe8c1521794..f3e34249187a5 100644 --- a/stdlib/public/SwiftShims/RuntimeShims.h +++ b/stdlib/public/SwiftShims/RuntimeShims.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,10 +27,7 @@ namespace swift { extern "C" { #define bool _Bool #endif -bool _swift_usesNativeSwiftReferenceCounting_nonNull(const void *); -bool _swift_usesNativeSwiftReferenceCounting_class(const void *); - -__swift_size_t _swift_class_getInstancePositiveExtentSize(const void *); +bool swift_objc_class_usesNativeSwiftReferenceCounting(const void *); /// Return an NSString to be used as the Mirror summary of the object void *_swift_objCMirrorSummary(const void * nsObject); @@ -51,7 +48,7 @@ struct Metadata; /// Return the superclass, if any. The result is nullptr for root /// classes and class protocol types. -const struct Metadata *_swift_getSuperclass_nonNull( +const struct Metadata *swift_class_getSuperclass( const struct Metadata *); void _swift_stdlib_flockfile_stdout(void); diff --git a/stdlib/public/SwiftShims/RuntimeStubs.h b/stdlib/public/SwiftShims/RuntimeStubs.h index 286b82900d344..622e91a09552b 100644 --- a/stdlib/public/SwiftShims/RuntimeStubs.h +++ b/stdlib/public/SwiftShims/RuntimeStubs.h @@ -1,8 +1,8 @@ -//===--- RuntimeStubs.h ---------------------------------------------------===// +//===--- RuntimeStubs.h -----------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/SwiftStddef.h b/stdlib/public/SwiftShims/SwiftStddef.h index aa9ab9e5a1bd1..758c5c9b6499d 100644 --- a/stdlib/public/SwiftShims/SwiftStddef.h +++ b/stdlib/public/SwiftShims/SwiftStddef.h @@ -1,8 +1,8 @@ -//===--- SwiftStddef.h ----------------------------------------------------===// +//===--- SwiftStddef.h ------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/SwiftStdint.h b/stdlib/public/SwiftShims/SwiftStdint.h index 20bfdc8b2c805..107802ebc7857 100644 --- a/stdlib/public/SwiftShims/SwiftStdint.h +++ b/stdlib/public/SwiftShims/SwiftStdint.h @@ -1,8 +1,8 @@ -//===--- SwiftStdint.h ----------------------------------------------------===// +//===--- SwiftStdint.h ------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/SwiftShims/UnicodeShims.h b/stdlib/public/SwiftShims/UnicodeShims.h index 0431d74140c83..a874e8da2921e 100644 --- a/stdlib/public/SwiftShims/UnicodeShims.h +++ b/stdlib/public/SwiftShims/UnicodeShims.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/common/MirrorBoilerplate.gyb b/stdlib/public/common/MirrorBoilerplate.gyb deleted file mode 100644 index b61a14cc99631..0000000000000 --- a/stdlib/public/common/MirrorBoilerplate.gyb +++ /dev/null @@ -1,49 +0,0 @@ -%{ -#//===--- MirrorBoilerplate.gyb ----------------------------------*- swift -*-===// -#// -#// This source file is part of the Swift.org open source project -#// -#// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -#// Licensed under Apache License v2.0 with Runtime Library Exception -#// -#// See http://swift.org/LICENSE.txt for license information -#// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -#// -#//===----------------------------------------------------------------------===// -# This file contains boilerplate that is common among all the Mirrors in the -# Swift Standard Library. It is meant to be used as a template to be included -# in other .gyb files to generate actual Mirror implementations, by only typing -# as little code as necessary -# Instructions: -# Load the file as a gyb template -# When you want to generate a Mirror, execute this template. Locals are as follows: -# - introspecteeType: the base name of the type to be reflected by your Mirror -# - genericArgs: a list of names of generic argument types that you need for your Mirror -# - genericConstraints: a dictionary that contains constraints on generic argument types -# - disposition: a valid disposition for your Mirror -# You still need to provide count, subscript, summary and quickLookObject manually when using -# this template, which is probably reasonable since those are "the meat" of every Mirror -}% - -%import inspect,os.path,sys -%sys.path = [os.path.split(inspect.getframeinfo(inspect.currentframe()).filename)[0] or '.'] + sys.path -%import MirrorCommon -%genericArgString = MirrorCommon.getGenericArgString( -% genericArgs if 'genericArgs' in locals() else None, -% genericConstraints if 'genericConstraints' in locals() else None) -%disposition = MirrorCommon.getDisposition( -% disposition if 'disposition' in locals() else None) -var _value: ${introspecteeType}${genericArgString} - -init(_ x: ${introspecteeType}${genericArgString}) { - _value = x -} - -var value: Any { return _value } - -var valueType: Any.Type { return (_value as Any).dynamicType } - -var objectIdentifier: ObjectIdentifier? { return .None } - -var disposition: _MirrorDisposition { return ${disposition} } - diff --git a/stdlib/public/common/MirrorCommon.py b/stdlib/public/common/MirrorCommon.py deleted file mode 100644 index 94f394338b491..0000000000000 --- a/stdlib/public/common/MirrorCommon.py +++ /dev/null @@ -1,55 +0,0 @@ -#//===--- MirrorCommon.py -------------------------------------*- python -*-===// -#// -#// This source file is part of the Swift.org open source project -#// -#// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -#// Licensed under Apache License v2.0 with Runtime Library Exception -#// -#// See http://swift.org/LICENSE.txt for license information -#// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -#// -#//===----------------------------------------------------------------------===// -# This file contains utility functions that are used by the gyb template files -# that generate Mirrors for the Swift Standard Library. -# If you edit this, make sure to also accordingly tweak the actual template files. - -def getDisposition(disp=None): - if disp == None: - return '.Aggregate' - if len(disp) == 0 or disp[0] != '.': - disp = '.' + disp - return disp - -def _getGenericArgStrings(genericArgs=None,genericConstraints=None): - if genericArgs == None: - return ('','') - genericArgString = '' - first = True - for arg in genericArgs: - if not first: - genericArgString = genericArgString + ',' - first = False - genericArgString = genericArgString + arg - if genericConstraints == None: - genericConstraintString = genericArgString - else: - genericConstraintString = '' - first = True - for arg in genericArgs: - if not first: - genericConstraintString = genericConstraintString + ',' - first = False - genericConstraintString = genericConstraintString + arg - if arg in genericConstraints: - cons = genericConstraints[arg] - genericConstraintString = genericConstraintString + ' : ' + cons - genericArgString = '<' + genericArgString + '>' - genericConstraintString = '<' + genericConstraintString + '>' - return (genericArgString,genericConstraintString) - -def getGenericArgString(genericArgs=None,genericConstraints=None): - return _getGenericArgStrings(genericArgs,genericConstraints)[0] - -def getGenericConstraintString(genericArgs=None,genericConstraints=None): - return _getGenericArgStrings(genericArgs,genericConstraints)[1] - diff --git a/stdlib/public/common/MirrorConformance.gyb b/stdlib/public/common/MirrorConformance.gyb deleted file mode 100644 index 00f6922ca1765..0000000000000 --- a/stdlib/public/common/MirrorConformance.gyb +++ /dev/null @@ -1,33 +0,0 @@ -%{ -#//===--- MirrorConformance.gyb --------------------------------*- swift -*-===// -#// -#// This source file is part of the Swift.org open source project -#// -#// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -#// Licensed under Apache License v2.0 with Runtime Library Exception -#// -#// See http://swift.org/LICENSE.txt for license information -#// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -#// -#//===----------------------------------------------------------------------===// -# This file contains boilerplate that is common among all the Mirrors in the -# Swift Standard Library. It is meant to be used as a template to be included -# in other .gyb files to generate actual Mirror implementations, by only typing -# as little code as necessary -# Instructions: -# Load the file as a gyb template -# When you want to generate a Mirror, execute this template. Locals are as follows: -# - introspecteeType: the base name of the type to be reflected by your Mirror -# - genericArgs: a list of names of generic argument types that you need for your Mirror -# - genericConstraints: a dictionary that contains constraints on generic argument types -# - disposition: a valid disposition for your Mirror -# You still need to provide count, subscript, summary and quickLookObject manually when using -# this template, which is probably reasonable since those are "the meat" of every Mirror -}% - -extension ${introspecteeType} : _Reflectable { - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _${introspecteeType}Mirror(self) - } -} diff --git a/stdlib/public/common/MirrorDecl.gyb b/stdlib/public/common/MirrorDecl.gyb deleted file mode 100644 index 67b6d4bfebb50..0000000000000 --- a/stdlib/public/common/MirrorDecl.gyb +++ /dev/null @@ -1,35 +0,0 @@ -%{ -#//===--- MirrorDecl.gyb --------------------------------------*- swift -*-===// -#// -#// This source file is part of the Swift.org open source project -#// -#// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -#// Licensed under Apache License v2.0 with Runtime Library Exception -#// -#// See http://swift.org/LICENSE.txt for license information -#// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -#// -#//===----------------------------------------------------------------------===// -# This file contains boilerplate that is common among all the Mirrors in the -# Swift Standard Library. It is meant to be used as a template to be included -# in other .gyb files to generate actual Mirror implementations, by only typing -# as little code as necessary -# Instructions: -# Load the file as a gyb template -# When you want to generate a Mirror, execute this template. Locals are as follows: -# - introspecteeType: the base name of the type to be reflected by your Mirror -# - genericArgs: a list of names of generic argument types that you need for your Mirror -# - genericConstraints: a dictionary that contains constraints on generic argument types -# - disposition: a valid disposition for your Mirror -# You still need to provide count, subscript, summary and quickLookObject manually when using -# this template, which is probably reasonable since those are "the meat" of every Mirror -}% - -%import inspect,os.path,sys -%sys.path = [os.path.split(inspect.getframeinfo(inspect.currentframe()).filename)[0] or '.'] + sys.path -%import MirrorCommon -%genericConstraintString = MirrorCommon.getGenericConstraintString(\ -% genericArgs if 'genericArgs' in locals() else None,\ -% genericConstraints if 'genericConstraints' in locals() else None) - -internal struct _${introspecteeType}Mirror${genericConstraintString} : _MirrorType diff --git a/stdlib/public/core/Algorithm.swift b/stdlib/public/core/Algorithm.swift index f8d829c515e7f..f7d09443d01f1 100644 --- a/stdlib/public/core/Algorithm.swift +++ b/stdlib/public/core/Algorithm.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,59 +44,50 @@ public func find< } /// Returns the lesser of `x` and `y`. +/// +/// If `x == y`, returns `x`. @warn_unused_result public func min(x: T, _ y: T) -> T { - var r = x - if y < x { - r = y - } - return r + // In case `x == y` we pick `x`. + // This preserves any pre-existing order in case `T` has identity, + // which is important for e.g. the stability of sorting algorithms. + // `(min(x, y), max(x, y))` should return `(x, y)` in case `x == y`. + return y < x ? y : x } /// Returns the least argument passed. +/// +/// If there are multiple equal least arguments, returns the first one. @warn_unused_result public func min(x: T, _ y: T, _ z: T, _ rest: T...) -> T { - var r = x - if y < x { - r = y - } - if z < r { - r = z - } - for t in rest { - if t < r { - r = t - } + var minValue = min(min(x, y), z) + // In case `value == minValue`, we pick `minValue`. See min(_:_:). + for value in rest where value < minValue { + minValue = value } - return r + return minValue } /// Returns the greater of `x` and `y`. +/// +/// If `x == y`, returns `y`. @warn_unused_result public func max(x: T, _ y: T) -> T { - var r = y - if y < x { - r = x - } - return r + // In case `x == y`, we pick `y`. See min(_:_:). + return y >= x ? y : x } /// Returns the greatest argument passed. +/// +/// If there are multiple equal greatest arguments, returns the last one. @warn_unused_result public func max(x: T, _ y: T, _ z: T, _ rest: T...) -> T { - var r = y - if y < x { - r = x - } - if r < z { - r = z - } - for t in rest { - if t >= r { - r = t - } + var maxValue = max(max(x, y), z) + // In case `value == maxValue`, we pick `value`. See min(_:_:). + for value in rest where value >= maxValue { + maxValue = value } - return r + return maxValue } /// Returns the result of slicing `elements` into sub-sequences that @@ -177,7 +168,8 @@ public struct EnumerateGenerator< /// - Requires: No preceding call to `self.next()` has returned `nil`. public mutating func next() -> Element? { guard let b = base.next() else { return nil } - return (index: count++, element: b) + defer { count += 1 } + return (index: count, element: b) } } diff --git a/stdlib/public/core/ArrayBody.swift b/stdlib/public/core/ArrayBody.swift index 25d74c4020299..e13d2c8b3a0e6 100644 --- a/stdlib/public/core/ArrayBody.swift +++ b/stdlib/public/core/ArrayBody.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/ArrayBuffer.swift b/stdlib/public/core/ArrayBuffer.swift index 8960f22114ec2..e431343ffadda 100644 --- a/stdlib/public/core/ArrayBuffer.swift +++ b/stdlib/public/core/ArrayBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -49,7 +49,7 @@ public struct _ArrayBuffer : _ArrayBufferType { var deferredTypeCheckMask : Int { return 1 } /// Returns an `_ArrayBuffer` containing the same elements, - /// deffering checking each element's `U`-ness until it is accessed. + /// deferring checking each element's `U`-ness until it is accessed. /// /// - Requires: `U` is a class or `@objc` existential derived from `Element`. @warn_unused_result @@ -201,7 +201,6 @@ extension _ArrayBuffer { /// Copy the given subRange of this buffer into uninitialized memory /// starting at target. Return a pointer past-the-end of the /// just-initialized memory. - @inline(never) // The copy loop blocks retain release matching. public func _uninitializedCopy( subRange: Range, target: UnsafeMutablePointer ) -> UnsafeMutablePointer { diff --git a/stdlib/public/core/ArrayBufferType.swift b/stdlib/public/core/ArrayBufferType.swift index 560ae92318152..80c3b54c6a691 100644 --- a/stdlib/public/core/ArrayBufferType.swift +++ b/stdlib/public/core/ArrayBufferType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -14,7 +14,7 @@ /// `_ArrayBufferType`. This buffer does not provide value semantics. public protocol _ArrayBufferType : MutableCollectionType { /// The type of elements stored in the buffer. - typealias Element + associatedtype Element /// Create an empty buffer. init() @@ -30,7 +30,7 @@ public protocol _ArrayBufferType : MutableCollectionType { ) -> UnsafeMutablePointer /// Get or set the index'th element. - subscript(index: Int) -> Element { get nonmutating set} + subscript(index: Int) -> Element { get nonmutating set } /// If this buffer is backed by a uniquely-referenced mutable /// `_ContiguousArrayBuffer` that can be grown in-place to allow the `self` @@ -73,7 +73,7 @@ public protocol _ArrayBufferType : MutableCollectionType { /// Returns a `_SliceBuffer` containing the given `subRange` of values /// from this buffer. - subscript(subRange: Range) -> _SliceBuffer {get} + subscript(subRange: Range) -> _SliceBuffer { get } /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the /// underlying contiguous storage. If no such storage exists, it is @@ -91,34 +91,34 @@ public protocol _ArrayBufferType : MutableCollectionType { ) rethrows -> R /// The number of elements the buffer stores. - var count: Int {get set} + var count: Int { get set } /// The number of elements the buffer can store without reallocation. - var capacity: Int {get} + var capacity: Int { get } /// An object that keeps the elements stored in this buffer alive. - var owner: AnyObject {get} + var owner: AnyObject { get } /// If the elements are stored contiguously, a pointer to the first /// element. Otherwise, `nil`. - var firstElementAddress: UnsafeMutablePointer {get} + var firstElementAddress: UnsafeMutablePointer { get } /// Return a base address to which you can add an index `i` to get the address /// of the corresponding element at `i`. - var subscriptBaseAddress: UnsafeMutablePointer {get} + var subscriptBaseAddress: UnsafeMutablePointer { get } /// Like `subscriptBaseAddress`, but can assume that `self` is a mutable, /// uniquely referenced native representation. /// - Precondition: `_isNative` is `true`. var _unconditionalMutableSubscriptBaseAddress: - UnsafeMutablePointer {get} + UnsafeMutablePointer { get } /// A value that identifies the storage used by the buffer. Two /// buffers address the same elements when they have the same /// identity and count. - var identity: UnsafePointer {get} + var identity: UnsafePointer { get } - var startIndex: Int {get} + var startIndex: Int { get } } extension _ArrayBufferType { @@ -160,12 +160,12 @@ extension _ArrayBufferType { var i = newValues.startIndex for j in subRange { elements[j] = newValues[i] - i = i.successor() + i._successorInPlace() } // Initialize the hole left by sliding the tail forward for j in oldTailIndex.. {get} + var _baseAddressIfContiguous: UnsafeMutablePointer { get } - subscript(index: Int) -> Generator.Element {get set} + subscript(index: Int) -> Generator.Element { get set } //===--- basic mutations ------------------------------------------------===// @@ -73,39 +73,9 @@ protocol _ArrayType //===--- implementation detail -----------------------------------------===// - typealias _Buffer : _ArrayBufferType + associatedtype _Buffer : _ArrayBufferType init(_ buffer: _Buffer) // For testing. - var _buffer: _Buffer {get} -} - -internal struct _ArrayTypeMirror< - T : _ArrayType where T.Index == Int -> : _MirrorType { - let _value : T - - init(_ v : T) { _value = v } - - var value: Any { return (_value as Any) } - - var valueType: Any.Type { return (_value as Any).dynamicType } - - var objectIdentifier: ObjectIdentifier? { return nil } - - var count: Int { return _value.count } - - subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - return ("[\(i)]", _reflect(_value[_value.startIndex + i])) - } - - var summary: String { - if count == 1 { return "1 element" } - return "\(count) elements" - } - - var quickLookObject: PlaygroundQuickLook? { return nil } - - var disposition: _MirrorDisposition { return .IndexContainer } + var _buffer: _Buffer { get } } diff --git a/stdlib/public/core/Arrays.swift.gyb b/stdlib/public/core/Arrays.swift.gyb index 242ee2f2601e4..d3753f9edddf9 100644 --- a/stdlib/public/core/Arrays.swift.gyb +++ b/stdlib/public/core/Arrays.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,7 +19,7 @@ // contiguous sequence of `Element`s. // // - `Array` is like `ContiguousArray` when `Element` is not -// an reference type or an Objective-C existential. Otherwise, it may use +// a reference type or an Objective-C existential. Otherwise, it may use // an `NSArray` bridged from Cocoa for storage. // //===----------------------------------------------------------------------===// @@ -328,9 +328,6 @@ public struct ${Self} return Builtin.castToNativeObject(_buffer.owner) } - // Don't inline copyBuffer - this would inline the copy loop into the current - // path preventing retains/releases to be matched across that region. - @inline(never) static internal func _copyBuffer(inout buffer: _Buffer) { let newBuffer = _ContiguousArrayBuffer( count: buffer.count, minimumCapacity: buffer.count) @@ -783,11 +780,11 @@ extension ${Self} : _ArrayType { } } -extension ${Self} : _Reflectable { +extension ${Self} : CustomReflectable { /// Returns a mirror that reflects `self`. @warn_unused_result - public func _getMirror() -> _MirrorType { - return _ArrayTypeMirror(self) + public func customMirror() -> Mirror { + return Mirror(self, unlabeledChildren: self, displayStyle: .Collection) } } @@ -1086,7 +1083,7 @@ internal func _forceCreateUniqueMutableBufferImpl<_Buffer : _ArrayBufferType>( } internal protocol _PointerFunctionType { - typealias Element + associatedtype Element func call(_: UnsafeMutablePointer, count: Int) } @@ -1241,7 +1238,8 @@ internal func _arrayAppendSequence< let base = buffer.firstElementAddress while (nextItem != nil) && count < capacity { - (base + count++).initialize(nextItem!) + (base + count).initialize(nextItem!) + count += 1 nextItem = stream.next() } buffer.count = count diff --git a/stdlib/public/core/Assert.swift b/stdlib/public/core/Assert.swift index 10748db8e34c6..25c33ad8f13aa 100644 --- a/stdlib/public/core/Assert.swift +++ b/stdlib/public/core/Assert.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/AssertCommon.swift b/stdlib/public/core/AssertCommon.swift index 29aa769199671..6ff9abd9d8115 100644 --- a/stdlib/public/core/AssertCommon.swift +++ b/stdlib/public/core/AssertCommon.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,26 +60,26 @@ func _isStdlibInternalChecksEnabled() -> Bool { #endif } -@_silgen_name("swift_reportFatalErrorInFile") +@_silgen_name("_swift_stdlib_reportFatalErrorInFile") func _reportFatalErrorInFile( prefix: UnsafePointer, _ prefixLength: UInt, _ message: UnsafePointer, _ messageLength: UInt, _ file: UnsafePointer, _ fileLength: UInt, _ line: UInt) -@_silgen_name("swift_reportFatalError") +@_silgen_name("_swift_stdlib_reportFatalError") func _reportFatalError( prefix: UnsafePointer, _ prefixLength: UInt, _ message: UnsafePointer, _ messageLength: UInt) -@_silgen_name("swift_reportUnimplementedInitializerInFile") +@_silgen_name("_swift_stdlib_reportUnimplementedInitializerInFile") func _reportUnimplementedInitializerInFile( className: UnsafePointer, _ classNameLength: UInt, _ initName: UnsafePointer, _ initNameLength: UInt, _ file: UnsafePointer, _ fileLength: UInt, _ line: UInt, _ column: UInt) -@_silgen_name("swift_reportUnimplementedInitializer") +@_silgen_name("_swift_stdlib_reportUnimplementedInitializer") func _reportUnimplementedInitializer( className: UnsafePointer, _ classNameLength: UInt, _ initName: UnsafePointer, _ initNameLength: UInt) @@ -148,6 +148,7 @@ func _assertionFailed( /// bloats code. @noreturn @inline(never) @_semantics("stdlib_binary_only") +@_semantics("arc.programtermination_point") func _fatalErrorMessage(prefix: StaticString, _ message: StaticString, _ file: StaticString, _ line: UInt) { #if INTERNAL_CHECKS_ENABLED @@ -179,7 +180,7 @@ func _fatalErrorMessage(prefix: StaticString, _ message: StaticString, Builtin.int_trap() } -/// Prints a fatal error message when a unimplemented initializer gets +/// Prints a fatal error message when an unimplemented initializer gets /// called by the Objective-C runtime. @_transparent @noreturn public // COMPILER_INTRINSIC diff --git a/stdlib/public/core/Availability.swift b/stdlib/public/core/Availability.swift index 54aca46b9a7ce..88d4c244b14d6 100644 --- a/stdlib/public/core/Availability.swift +++ b/stdlib/public/core/Availability.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -47,75 +47,43 @@ extension _SwiftNSOperatingSystemVersion : Comparable { } @warn_unused_result public func == ( - left: _SwiftNSOperatingSystemVersion, - right: _SwiftNSOperatingSystemVersion + lhs: _SwiftNSOperatingSystemVersion, + rhs: _SwiftNSOperatingSystemVersion ) -> Bool { - return left.majorVersion == right.majorVersion && - left.minorVersion == right.minorVersion && - left.patchVersion == right.patchVersion + return lhs.majorVersion == rhs.majorVersion && + lhs.minorVersion == rhs.minorVersion && + lhs.patchVersion == rhs.patchVersion } /// Lexicographic comparison of version components. @warn_unused_result public func < ( - _lhs: _SwiftNSOperatingSystemVersion, - _rhs: _SwiftNSOperatingSystemVersion + lhs: _SwiftNSOperatingSystemVersion, + rhs: _SwiftNSOperatingSystemVersion ) -> Bool { - if _lhs.majorVersion > _rhs.majorVersion { - return false + guard lhs.majorVersion == rhs.majorVersion else { + return lhs.majorVersion < rhs.majorVersion } - if _lhs.majorVersion < _rhs.majorVersion { - return true + guard lhs.minorVersion == rhs.minorVersion else { + return lhs.minorVersion < rhs.minorVersion } - if _lhs.minorVersion > _rhs.minorVersion { - return false - } - - if _lhs.minorVersion < _rhs.minorVersion { - return true - } - - if _lhs.patchVersion > _rhs.patchVersion { - return false - } - - if _lhs.patchVersion < _rhs.patchVersion { - return true - } - - return false + return lhs.patchVersion < rhs.patchVersion } @warn_unused_result public func >= ( - _lhs: _SwiftNSOperatingSystemVersion, - _rhs: _SwiftNSOperatingSystemVersion + lhs: _SwiftNSOperatingSystemVersion, + rhs: _SwiftNSOperatingSystemVersion ) -> Bool { - if _lhs.majorVersion < _rhs.majorVersion { - return false - } - - if _lhs.majorVersion > _rhs.majorVersion { - return true - } - - if _lhs.minorVersion < _rhs.minorVersion { - return false - } - - if _lhs.minorVersion > _rhs.minorVersion { - return true - } - - if _lhs.patchVersion < _rhs.patchVersion { - return false + guard lhs.majorVersion == rhs.majorVersion else { + return lhs.majorVersion >= rhs.majorVersion } - if _lhs.patchVersion > _rhs.patchVersion { - return true + guard lhs.minorVersion == rhs.minorVersion else { + return lhs.minorVersion >= rhs.minorVersion } - return true + return lhs.patchVersion >= rhs.patchVersion } diff --git a/stdlib/public/core/Bit.swift b/stdlib/public/core/Bit.swift index 02fd6fc6eb3d7..780b313d49bf1 100644 --- a/stdlib/public/core/Bit.swift +++ b/stdlib/public/core/Bit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,7 +16,7 @@ /// A `RandomAccessIndexType` that has two possible values. Used as /// the `Index` type for `CollectionOfOne`. -public enum Bit : Int, Comparable, RandomAccessIndexType, _Reflectable { +public enum Bit : Int, Comparable, RandomAccessIndexType { public typealias Distance = Int @@ -45,42 +45,6 @@ public enum Bit : Int, Comparable, RandomAccessIndexType, _Reflectable { public func advancedBy(n: Distance) -> Bit { return rawValue.advancedBy(n) > 0 ? One : Zero } - - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _BitMirror(self) - } -} - -internal struct _BitMirror : _MirrorType { - let _value: Bit - - init(_ v: Bit) { - self._value = v - } - - var value: Any { return _value } - - var valueType: Any.Type { return (_value as Any).dynamicType } - - var objectIdentifier: ObjectIdentifier? { return nil } - - var count: Int { return 0 } - - subscript(i: Int) -> (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { - switch _value { - case .Zero: return ".Zero" - case .One: return ".One" - } - } - - var quickLookObject: PlaygroundQuickLook? { return nil } - - var disposition: _MirrorDisposition { return .Enum } } @warn_unused_result @@ -94,11 +58,15 @@ public func < (lhs: Bit, rhs: Bit) -> Bool { } extension Bit : IntegerArithmeticType { - static func _withOverflow(v: (Int, overflow: Bool)) -> (Bit, overflow: Bool) { - if let b = Bit(rawValue: v.0) { - return (b, v.overflow) + static func _withOverflow( + intResult: Int, overflow: Bool + ) -> (Bit, overflow: Bool) { + if let bit = Bit(rawValue: intResult) { + return (bit, overflow: overflow) } else { - return (Bit(rawValue: v.0 % 2)!, true) + let bitRaw = intResult % 2 + (intResult < 0 ? 2 : 0) + let bit = Bit(rawValue: bitRaw)! + return (bit, overflow: true) } } diff --git a/stdlib/public/core/Bool.swift b/stdlib/public/core/Bool.swift index 08cdf6c129249..377acec1f47e5 100644 --- a/stdlib/public/core/Bool.swift +++ b/stdlib/public/core/Bool.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/BooleanType.swift b/stdlib/public/core/BooleanType.swift index f229f06a4b97b..0da99532f7ef6 100644 --- a/stdlib/public/core/BooleanType.swift +++ b/stdlib/public/core/BooleanType.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/BridgeObjectiveC.swift b/stdlib/public/core/BridgeObjectiveC.swift index 49b9c07e31879..bb4c8277cc053 100644 --- a/stdlib/public/core/BridgeObjectiveC.swift +++ b/stdlib/public/core/BridgeObjectiveC.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,7 +17,7 @@ /// or NSDictionary will be the result of calling `_bridgeToObjectiveC` /// on each element of the source container. public protocol _ObjectiveCBridgeable { - typealias _ObjectiveCType : AnyObject + associatedtype _ObjectiveCType : AnyObject /// Return true iff instances of `Self` can be converted to /// Objective-C. Even if this method returns `true`, A given @@ -29,7 +29,7 @@ public protocol _ObjectiveCBridgeable { static func _isBridgedToObjectiveC() -> Bool // _getObjectiveCType is a workaround: right now protocol witness - // tables don't include associated types, so we can not find + // tables don't include associated types, so we cannot find // '_ObjectiveCType.self' from them. /// Must return `_ObjectiveCType.self`. @@ -81,7 +81,7 @@ public protocol _ObjectiveCBridgeable { /// /// The language and runtime do not yet support protocol conformances for /// structural types like metatypes. However, we can use a struct that contains -/// a metatype, make it conform to to _ObjectiveCBridgeable, and its witness table +/// a metatype, make it conform to _ObjectiveCBridgeable, and its witness table /// will be ABI-compatible with one that directly provided conformance to the /// metatype type itself. public struct _BridgeableMetatype: _ObjectiveCBridgeable { diff --git a/stdlib/public/core/BridgeStorage.swift b/stdlib/public/core/BridgeStorage.swift index 2efefabc55313..11abff2693a44 100644 --- a/stdlib/public/core/BridgeStorage.swift +++ b/stdlib/public/core/BridgeStorage.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Builtin.swift b/stdlib/public/core/Builtin.swift index c455ca2f60487..c67e08de5879d 100644 --- a/stdlib/public/core/Builtin.swift +++ b/stdlib/public/core/Builtin.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -175,8 +175,8 @@ func _conditionallyUnreachable() { } @warn_unused_result -@_silgen_name("swift_isClassOrObjCExistential") -func _swift_isClassOrObjCExistential(x: T.Type) -> Bool +@_silgen_name("swift_isClassOrObjCExistentialType") +func _swift_isClassOrObjCExistentialType(x: T.Type) -> Bool /// Returns `true` iff `T` is a class type or an `@objc` existential such as /// `AnyObject`. @@ -194,7 +194,7 @@ internal func _isClassOrObjCExistential(x: T.Type) -> Bool { } // Maybe a class. - return _swift_isClassOrObjCExistential(x) + return _swift_isClassOrObjCExistentialType(x) } /// Returns an `UnsafePointer` to the storage used for `object`. There's @@ -318,7 +318,7 @@ public func _slowPath(x: C) -> Bool { @warn_unused_result internal func _usesNativeSwiftReferenceCounting(theClass: AnyClass) -> Bool { #if _runtime(_ObjC) - return _swift_usesNativeSwiftReferenceCounting_class( + return swift_objc_class_usesNativeSwiftReferenceCounting( unsafeAddressOf(theClass) ) #else @@ -327,25 +327,26 @@ internal func _usesNativeSwiftReferenceCounting(theClass: AnyClass) -> Bool { } @warn_unused_result -@_silgen_name("_swift_class_getInstancePositiveExtentSize_native") -func _swift_class_getInstancePositiveExtentSize_native(theClass: AnyClass) -> UInt +@_silgen_name("swift_class_getInstanceExtents") +func swift_class_getInstanceExtents(theClass: AnyClass) + -> (negative: UInt, positive: UInt) -/// - Returns: `class_getInstanceSize(theClass)`. +@warn_unused_result +@_silgen_name("swift_objc_class_unknownGetInstanceExtents") +func swift_objc_class_unknownGetInstanceExtents(theClass: AnyClass) + -> (negative: UInt, positive: UInt) + +/// - Returns: @inline(__always) @warn_unused_result internal func _class_getInstancePositiveExtentSize(theClass: AnyClass) -> Int { #if _runtime(_ObjC) - return Int(_swift_class_getInstancePositiveExtentSize( - unsafeAddressOf(theClass))) + return Int(swift_objc_class_unknownGetInstanceExtents(theClass).positive) #else - return Int(_swift_class_getInstancePositiveExtentSize_native(theClass)) + return Int(swift_class_getInstanceExtents(theClass).positive) #endif } -@warn_unused_result -@_silgen_name("_swift_isClass") -public func _swift_isClass(x: Any) -> Bool - //===--- Builtin.BridgeObject ---------------------------------------------===// #if arch(i386) || arch(arm) @@ -387,6 +388,19 @@ internal var _objectPointerLowSpareBitShift: UInt { internal var _objCTaggedPointerBits: UInt { @inline(__always) get { return 0x8000_0000_0000_0000 } } +#elseif arch(powerpc64) || arch(powerpc64le) +internal var _objectPointerSpareBits: UInt { + @inline(__always) get { return 0x0000_0000_0000_0007 } +} +internal var _objectPointerIsObjCBit: UInt { + @inline(__always) get { return 0x0000_0000_0000_0002 } +} +internal var _objectPointerLowSpareBitShift: UInt { + @inline(__always) get { return 0 } +} +internal var _objCTaggedPointerBits: UInt { + @inline(__always) get { return 0 } +} #endif /// Extract the raw bits of `x`. @@ -481,7 +495,7 @@ internal func _makeBridgeObject( public // @testable func _getSuperclass(t: AnyClass) -> AnyClass? { return unsafeBitCast( - _swift_getSuperclass_nonNull(unsafeBitCast(t, COpaquePointer.self)), + swift_class_getSuperclass(unsafeBitCast(t, COpaquePointer.self)), AnyClass.self) } @@ -534,7 +548,7 @@ internal func _isUniqueOrPinned(inout object: T) -> Bool { public // @testable func _isUnique_native(inout object: T) -> Bool { // This could be a bridge object, single payload enum, or plain old - // reference. Any any case it's non pointer bits must be zero, so + // reference. Any case it's non pointer bits must be zero, so // force cast it to BridgeObject and check the spare bits. _sanityCheck( (_bitPattern(Builtin.reinterpretCast(object)) & _objectPointerSpareBits) @@ -551,7 +565,7 @@ func _isUnique_native(inout object: T) -> Bool { public // @testable func _isUniqueOrPinned_native(inout object: T) -> Bool { // This could be a bridge object, single payload enum, or plain old - // reference. Any any case it's non pointer bits must be zero. + // reference. Any case it's non pointer bits must be zero. _sanityCheck( (_bitPattern(Builtin.reinterpretCast(object)) & _objectPointerSpareBits) == 0) diff --git a/stdlib/public/core/BuiltinMath.swift.gyb b/stdlib/public/core/BuiltinMath.swift.gyb index 941744a2486ba..9c84e6b01262a 100644 --- a/stdlib/public/core/BuiltinMath.swift.gyb +++ b/stdlib/public/core/BuiltinMath.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,12 +45,13 @@ def cFuncSuffix(bits): # These functions have a corresponding LLVM intrinsic # Note, keep this up to date with Darwin/tgmath.swift.gyb -UnaryIntrinsicFunctions = ['cos', 'sin', - 'exp', 'exp2', - 'log', 'log10', 'log2', - 'fabs', - 'ceil', 'floor', 'nearbyint', 'rint', 'round', 'trunc', - ] +UnaryIntrinsicFunctions = [ + 'cos', 'sin', + 'exp', 'exp2', + 'log', 'log10', 'log2', + 'fabs', + 'ceil', 'floor', 'nearbyint', 'rint', 'round', 'trunc', +] def TypedUnaryIntrinsicFunctions(): for ufunc in UnaryIntrinsicFunctions: diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 5e44d5c14e69c..aa78bc321b63a 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -2,7 +2,7 @@ # # This source file is part of the Swift.org open source project # -# Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ # #===----------------------------------------------------------------------===# -# The list of sources without which it's impossble to build a core +# The list of sources without which it's impossible to build a core # standard library. Try to add new standard library sources to # SWIFTLIB_SOURCES, below, rather than SWIFTLIB_ESSENTIAL, if # possible, to improve layering. Check that you got it right by @@ -76,7 +76,6 @@ set(SWIFTLIB_ESSENTIAL Print.swift REPL.swift Range.swift - RangeMirrors.swift.gyb RangeReplaceableCollectionType.swift Reflection.swift Repeat.swift @@ -92,7 +91,6 @@ set(SWIFTLIB_ESSENTIAL Sort.swift.gyb StaticString.swift Stride.swift - StrideMirrors.swift.gyb StringCharacterView.swift # ORDER DEPENDENCY: Must precede String.swift String.swift StringBridge.swift @@ -103,7 +101,6 @@ set(SWIFTLIB_ESSENTIAL StringUnicodeScalarView.swift StringUTF16.swift StringUTF8.swift - StringUTFViewsMirrors.swift.gyb SwiftNativeNSArray.swift Unicode.swift UnicodeScalar.swift @@ -121,12 +118,12 @@ set(SWIFTLIB_SOURCES ### PLEASE KEEP THIS LIST IN ALPHABETICAL ORDER ### Availability.swift Bit.swift - CollectionMirrors.swift.gyb CollectionOfOne.swift ExistentialCollection.swift.gyb Mirror.swift Process.swift SliceBuffer.swift + Tuple.swift.gyb VarArgs.swift Zip.swift Prespecialized.swift diff --git a/stdlib/public/core/CString.swift b/stdlib/public/core/CString.swift index d763ce8c67c0c..c53058f2c0ad1 100644 --- a/stdlib/public/core/CString.swift +++ b/stdlib/public/core/CString.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -60,8 +60,7 @@ public func _persistCString(s: UnsafePointer) -> [CChar]? { } let length = Int(_swift_stdlib_strlen(s)) var result = [CChar](count: length + 1, repeatedValue: 0) - for var i = 0; i < length; ++i { - // FIXME: this will not compile on platforms where 'CChar' is unsigned. + for i in 0.. Int { var mask: UInt64 = 0xFF - for var i = 0; i < 8; ++i { + for i in 0..<8 { if (value & mask) == mask { return i } @@ -165,7 +165,7 @@ public struct Character : subscript(position: Int) -> UTF8.CodeUnit { _sanityCheck(position >= 0) _sanityCheck(position < Int(count)) - // Note: using unchecked arithmetic because overflow can not happen if the + // Note: using unchecked arithmetic because overflow cannot happen if the // above sanity checks hold. return UTF8.CodeUnit( truncatingBitPattern: data >> (UInt64(position) &* 8)) @@ -237,7 +237,7 @@ public struct Character : subscript(position: Int) -> UTF16.CodeUnit { _sanityCheck(position >= 0) _sanityCheck(position < Int(count)) - // Note: using unchecked arithmetic because overflow can not happen if the + // Note: using unchecked arithmetic because overflow cannot happen if the // above sanity checks hold. return UTF16.CodeUnit(truncatingBitPattern: data >> ((UInt64(count) &- UInt64(position) &- 1) &* 16)) diff --git a/stdlib/public/core/CocoaArray.swift b/stdlib/public/core/CocoaArray.swift index 9957a7bef25da..3991da9e45ed3 100644 --- a/stdlib/public/core/CocoaArray.swift +++ b/stdlib/public/core/CocoaArray.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Collection.swift b/stdlib/public/core/Collection.swift index cf3c136291a76..7717e320879c3 100644 --- a/stdlib/public/core/Collection.swift +++ b/stdlib/public/core/Collection.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,14 +30,14 @@ public protocol Indexable { /// /// Valid indices consist of the position of every element and a /// "past the end" position that's not valid for use as a subscript. - typealias Index : ForwardIndexType + associatedtype Index : ForwardIndexType /// The position of the first element in a non-empty collection. /// /// In an empty collection, `startIndex == endIndex`. /// /// - Complexity: O(1) - var startIndex: Index {get} + var startIndex: Index { get } /// The collection's "past the end" position. /// @@ -46,7 +46,7 @@ public protocol Indexable { /// `successor()`. /// /// - Complexity: O(1) - var endIndex: Index {get} + var endIndex: Index { get } // The declaration of _Element and subscript here is a trick used to // break a cyclic conformance/deduction that Swift can't handle. We @@ -56,23 +56,23 @@ public protocol Indexable { // its subscript. Ideally we'd like to constrain this // Element to be the same as CollectionType.Generator.Element (see // below), but we have no way of expressing it today. - typealias _Element + associatedtype _Element /// Returns the element at the given `position`. /// /// - Complexity: O(1) - subscript(position: Index) -> _Element {get} + subscript(position: Index) -> _Element { get } } public protocol MutableIndexable { - typealias Index : ForwardIndexType + associatedtype Index : ForwardIndexType - var startIndex: Index {get} - var endIndex: Index {get} + var startIndex: Index { get } + var endIndex: Index { get } - typealias _Element + associatedtype _Element - subscript(position: Index) -> _Element {get set} + subscript(position: Index) -> _Element { get set } } /// A *generator* for an arbitrary *collection*. Provided `C` @@ -132,7 +132,7 @@ public protocol CollectionType : Indexable, SequenceType { /// By default, a `CollectionType` satisfies `SequenceType` by /// supplying an `IndexingGenerator` as its associated `Generator` /// type. - typealias Generator: GeneratorType = IndexingGenerator + associatedtype Generator: GeneratorType = IndexingGenerator // FIXME: Needed here so that the Generator is properly deduced from // a custom generate() function. Otherwise we get an @@ -150,16 +150,16 @@ public protocol CollectionType : Indexable, SequenceType { /// `SequenceType`, but is restated here with stricter /// constraints: in a `CollectionType`, the `SubSequence` should /// also be a `CollectionType`. - typealias SubSequence: Indexable, SequenceType = Slice + associatedtype SubSequence: Indexable, SequenceType = Slice /// Returns the element at the given `position`. - subscript(position: Index) -> Generator.Element {get} + subscript(position: Index) -> Generator.Element { get } /// Returns a collection representing a contiguous sub-range of /// `self`'s elements. /// /// - Complexity: O(1) - subscript(bounds: Range) -> SubSequence {get} + subscript(bounds: Range) -> SubSequence { get } /// Returns `self[startIndex.. Generator.Element? { guard !isEmpty else { return nil } @@ -234,17 +234,19 @@ extension CollectionType where SubSequence == Self { self = self[startIndex.successor().. Generator.Element? { guard !isEmpty else { return nil } - let lastElementIndex = startIndex.advancedBy(numericCast(count) - 1) - let element = self[lastElementIndex] - self = self[startIndex..(preprocess: (Self)->R) -> R? { + public func _preprocessingPass(@noescape preprocess: (Self) -> R) -> R? { return preprocess(self) } } @@ -647,7 +654,7 @@ public protocol MutableCollectionType : MutableIndexable, CollectionType { // FIXME: should be constrained to MutableCollectionType // ( Implement recursive protocol // constraints) - typealias SubSequence : CollectionType /*: MutableCollectionType*/ + associatedtype SubSequence : CollectionType /*: MutableCollectionType*/ = MutableSlice /// Access the element at `position`. @@ -728,16 +735,16 @@ internal func _writeBackMutableSlice< newElementIndex != newElementsEndIndex { self_[selfElementIndex] = slice[newElementIndex] - selfElementIndex = selfElementIndex.successor() - newElementIndex = newElementIndex.successor() + selfElementIndex._successorInPlace() + newElementIndex._successorInPlace() } _precondition( selfElementIndex == selfElementsEndIndex, - "Can not replace a slice of a MutableCollectionType with a slice of a larger size") + "Cannot replace a slice of a MutableCollectionType with a slice of a larger size") _precondition( newElementIndex == newElementsEndIndex, - "Can not replace a slice of a MutableCollectionType with a slice of a smaller size") + "Cannot replace a slice of a MutableCollectionType with a slice of a smaller size") } /// Returns the range of `x`'s valid index values. diff --git a/stdlib/public/core/CollectionAlgorithms.swift.gyb b/stdlib/public/core/CollectionAlgorithms.swift.gyb index 02e261adf1367..c40d39ae31b65 100644 --- a/stdlib/public/core/CollectionAlgorithms.swift.gyb +++ b/stdlib/public/core/CollectionAlgorithms.swift.gyb @@ -1,8 +1,8 @@ -//===--- CollectionAlgorithms.swift.gyb -----------------------------------===// +//===--- CollectionAlgorithms.swift.gyb -----------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/CollectionMirrors.swift.gyb b/stdlib/public/core/CollectionMirrors.swift.gyb deleted file mode 100644 index 530a989fb7b07..0000000000000 --- a/stdlib/public/core/CollectionMirrors.swift.gyb +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------*- swift -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../common/MirrorBoilerplate.gyb") - -% for Type in [['CollectionOfOne',1,"element",\ -% 'CollectionOfOne(\( _reflect(_value.element).summary ))'],\ -% ['EmptyCollection',0,"DONTSHOWME",'EmptyCollection']]: -% Self = Type[0] -% Count = Type[1] -% ElementName = Type[2] -% SummaryString = Type[3] -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,\ -% introspecteeType=Self,\ -% genericArgs=['T'],\ -% disposition='Struct') -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,\ -% introspecteeType=Self,\ -% genericArgs=['T'],\ -% disposition='Struct') -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,\ -% introspecteeType=Self,\ -% genericArgs=['T'],\ -% disposition='Struct') - -${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return ${Count} } - - subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - return ("${ElementName}", _reflect(_value[_value.startIndex.advancedBy(i)])) - } - - var summary: String { return "${SummaryString}" } - - var quickLookObject: PlaygroundQuickLook? { return nil } -} - -${MirrorConformance} - diff --git a/stdlib/public/core/CollectionOfOne.swift b/stdlib/public/core/CollectionOfOne.swift index 6ce00e6234eff..1dab7ea4a8386 100644 --- a/stdlib/public/core/CollectionOfOne.swift +++ b/stdlib/public/core/CollectionOfOne.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -87,3 +87,8 @@ public struct CollectionOfOne : CollectionType { let element: Element } +extension CollectionOfOne : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: ["element": element]) + } +} diff --git a/stdlib/public/core/CompilerProtocols.swift b/stdlib/public/core/CompilerProtocols.swift index 1ca8d0b407bf6..6f43f22c3d9e8 100644 --- a/stdlib/public/core/CompilerProtocols.swift +++ b/stdlib/public/core/CompilerProtocols.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,7 @@ public protocol RawRepresentable { /// Every distinct value of `self` has a corresponding unique /// value of `RawValue`, but `RawValue` may have representations /// that do not correspond to a value of `Self`. - typealias RawValue + associatedtype RawValue /// Convert from a value of `RawValue`, yielding `nil` iff /// `rawValue` does not correspond to a value of `Self`. @@ -84,7 +84,7 @@ public protocol _BuiltinIntegerLiteralConvertible { /// Conforming types can be initialized with integer literals. public protocol IntegerLiteralConvertible { - typealias IntegerLiteralType : _BuiltinIntegerLiteralConvertible + associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible /// Create an instance initialized to `value`. init(integerLiteral value: IntegerLiteralType) } @@ -95,7 +95,7 @@ public protocol _BuiltinFloatLiteralConvertible { /// Conforming types can be initialized with floating point literals. public protocol FloatLiteralConvertible { - typealias FloatLiteralType : _BuiltinFloatLiteralConvertible + associatedtype FloatLiteralType : _BuiltinFloatLiteralConvertible /// Create an instance initialized to `value`. init(floatLiteral value: FloatLiteralType) } @@ -107,7 +107,7 @@ public protocol _BuiltinBooleanLiteralConvertible { /// Conforming types can be initialized with the Boolean literals /// `true` and `false`. public protocol BooleanLiteralConvertible { - typealias BooleanLiteralType : _BuiltinBooleanLiteralConvertible + associatedtype BooleanLiteralType : _BuiltinBooleanLiteralConvertible /// Create an instance initialized to `value`. init(booleanLiteral value: BooleanLiteralType) } @@ -119,7 +119,7 @@ public protocol _BuiltinUnicodeScalarLiteralConvertible { /// Conforming types can be initialized with string literals /// containing a single [Unicode scalar value](http://www.unicode.org/glossary/#unicode_scalar_value). public protocol UnicodeScalarLiteralConvertible { - typealias UnicodeScalarLiteralType : _BuiltinUnicodeScalarLiteralConvertible + associatedtype UnicodeScalarLiteralType : _BuiltinUnicodeScalarLiteralConvertible /// Create an instance initialized to `value`. init(unicodeScalarLiteral value: UnicodeScalarLiteralType) } @@ -138,7 +138,7 @@ public protocol _BuiltinExtendedGraphemeClusterLiteralConvertible public protocol ExtendedGraphemeClusterLiteralConvertible : UnicodeScalarLiteralConvertible { - typealias ExtendedGraphemeClusterLiteralType + associatedtype ExtendedGraphemeClusterLiteralType : _BuiltinExtendedGraphemeClusterLiteralConvertible /// Create an instance initialized to `value`. init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) @@ -167,22 +167,22 @@ public protocol StringLiteralConvertible // FIXME: when we have default function implementations in protocols, provide // an implementation of init(extendedGraphemeClusterLiteral:). - typealias StringLiteralType : _BuiltinStringLiteralConvertible + associatedtype StringLiteralType : _BuiltinStringLiteralConvertible /// Create an instance initialized to `value`. init(stringLiteral value: StringLiteralType) } /// Conforming types can be initialized with array literals. public protocol ArrayLiteralConvertible { - typealias Element + associatedtype Element /// Create an instance initialized with `elements`. init(arrayLiteral elements: Element...) } /// Conforming types can be initialized with dictionary literals. public protocol DictionaryLiteralConvertible { - typealias Key - typealias Value + associatedtype Key + associatedtype Value /// Create an instance initialized with `elements`. init(dictionaryLiteral elements: (Key, Value)...) } @@ -216,11 +216,12 @@ public protocol _FileReferenceLiteralConvertible { /// A container is destructor safe if whether it may store to memory on /// destruction only depends on its type parameters. -/// For example, whether `Array` may store to memory on destruction depends -/// only on `T`. -/// If `T` is an `Int` we know the `Array` does not store to memory during -/// destruction. If `T` is an arbitrary class `Array` -/// then the compiler will deduce may store to memory on destruction because -/// `MemoryUnsafeDestructorClass`'s destructor may store to memory on destruction. +/// For example, whether `Array` may store to memory on destruction +/// depends only on `Element`. +/// If `Element` is an `Int` we know the `Array` does not store to memory +/// during destruction. If `Element` is an arbitrary class +/// `Array` then the compiler will deduce may +/// store to memory on destruction because `MemoryUnsafeDestructorClass`'s +/// destructor may store to memory on destruction. public protocol _DestructorSafeContainer { } diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift index e3125b11a0b4e..f74c3cd8aa54b 100644 --- a/stdlib/public/core/ContiguousArrayBuffer.swift +++ b/stdlib/public/core/ContiguousArrayBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -586,7 +586,7 @@ extension _ContiguousArrayBuffer { /// It avoids the extra retain, release overhead from storing the /// ContiguousArrayBuffer into /// _UnsafePartiallyInitializedContiguousArrayBuffer. Since we do not support -/// ARC loops, the extra retain, release overhead can not be eliminated which +/// ARC loops, the extra retain, release overhead cannot be eliminated which /// makes assigning ranges very slow. Once this has been implemented, this code /// should be changed to use _UnsafePartiallyInitializedContiguousArrayBuffer. @warn_unused_result @@ -609,8 +609,8 @@ internal func _copyCollectionToNativeArrayBuffer< for _ in 0.. : CollectionType { init(startIndex: IndexType_, endIndex: IndexType_, - _ subscriptImpl: (IndexType_)->T) { + _ subscriptImpl: (IndexType_) -> T) { self.startIndex = startIndex self.endIndex = endIndex _subscriptImpl = subscriptImpl @@ -44,7 +44,7 @@ internal struct _CollectionOf< return AnyGenerator { () -> T? in if _fastPath(index != self.endIndex) { - index = index.successor() + index._successorInPlace() return self._subscriptImpl(index) } return nil @@ -58,9 +58,9 @@ internal struct _CollectionOf< return _subscriptImpl(i) } - let _subscriptImpl: (IndexType_)->T + let _subscriptImpl: (IndexType_) -> T } -@available(*, unavailable, message="SinkOf has been removed. Use (T)->() closures directly instead.") +@available(*, unavailable, message="SinkOf has been removed. Use (T) -> () closures directly instead.") public struct SinkOf {} diff --git a/stdlib/public/core/ExistentialCollection.swift.gyb b/stdlib/public/core/ExistentialCollection.swift.gyb index 0121a237ec9aa..80e8a220fbc82 100644 --- a/stdlib/public/core/ExistentialCollection.swift.gyb +++ b/stdlib/public/core/ExistentialCollection.swift.gyb @@ -1,8 +1,8 @@ -//===--- ExistentialCollection.swift.gyb ----------------------------------===// +//===--- ExistentialCollection.swift.gyb ----------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -81,14 +81,14 @@ public struct AnyGenerator : GeneratorType { /// traversing the sequence consumes the generator. extension AnyGenerator : SequenceType {} -@available(*, unavailable, renamed="AnyGenerator") +@available(*, deprecated, renamed="AnyGenerator") public func anyGenerator(base: G) -> AnyGenerator { - fatalError("unavailable function can't be called") + return AnyGenerator(base) } -@available(*, unavailable, renamed="AnyGenerator") -public func anyGenerator(body: ()->Element?) -> AnyGenerator { - fatalError("unavailable function can't be called") +@available(*, deprecated, renamed="AnyGenerator") +public func anyGenerator(body: () -> Element?) -> AnyGenerator { + return AnyGenerator(body: body) } internal struct _ClosureBasedGenerator : GeneratorType { @@ -139,6 +139,11 @@ internal class _AnySequenceBox { internal func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { _abstract() } + + internal func _dropFirst(n: Int) -> _AnySequenceBox { _abstract() } + internal func _prefix(maxLength: Int) -> _AnySequenceBox { + _abstract() + } } internal class _AnyCollectionBoxBase : _AnySequenceBox { @@ -154,8 +159,15 @@ internal class _AnyCollectionBoxBase : _AnySequenceBox { % for Kind in ['Sequence', 'Collection']: // FIXME: can't make this a protocol due to -internal class _${Kind}Box - : _Any${Kind}Box { +internal final class _${Kind}Box< + S : ${Kind}Type +% if Kind == 'Sequence': + where + S.SubSequence : ${Kind}Type, + S.SubSequence.Generator.Element == S.Generator.Element, + S.SubSequence.SubSequence == S.SubSequence +% end +> : _Any${Kind}Box { typealias Element = S.Generator.Element override func generate() -> AnyGenerator { @@ -171,6 +183,15 @@ internal class _${Kind}Box override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { return _base._copyToNativeArrayBuffer()._storage } +% if Kind == 'Sequence': + internal override func _dropFirst(n: Int) -> _AnySequenceBox { + return _SequenceBox(_base.dropFirst(n)) + } + internal override func _prefix(maxLength: Int) -> _AnySequenceBox { + return _SequenceBox(_base.prefix(maxLength)) + } +% end + % if Kind == 'Collection': override func _count() -> IntMax { return numericCast(_base.count) @@ -223,8 +244,15 @@ public struct AnySequence : SequenceType { @available(*, unavailable, renamed="Element") public typealias T = Element - /// Wrap and forward operations to to `base`. - public init(_ base: S) { + /// Wrap and forward operations to `base`. + public init< + S: SequenceType + where + S.Generator.Element == Element, + S.SubSequence : SequenceType, + S.SubSequence.Generator.Element == Element, + S.SubSequence.SubSequence == S.SubSequence + >(_ base: S) { _box = _SequenceBox(base) } @@ -236,6 +264,10 @@ public struct AnySequence : SequenceType { self.init(_ClosureBasedSequence(makeUnderlyingGenerator)) } + internal init(_ box: _AnySequenceBox) { + _box = box + } + /// Return a *generator* over the elements of this *sequence*. /// /// - Complexity: O(1). @@ -246,6 +278,18 @@ public struct AnySequence : SequenceType { internal let _box: _AnySequenceBox } +extension AnySequence { + @warn_unused_result + public func dropFirst(n: Int) -> AnySequence { + return AnySequence(_box._dropFirst(n)) + } + + @warn_unused_result + public func prefix(maxLength: Int) -> AnySequence { + return AnySequence(_box._prefix(maxLength)) + } +} + % for Kind in ['Sequence'] + [t + 'Collection' for t in traversals]: extension Any${Kind} { public func underestimateCount() -> Int { @@ -268,7 +312,7 @@ extension Any${Kind} { //===----------------------------------------------------------------------===// internal protocol _ForwardIndexBoxType : class { - var typeID: ObjectIdentifier {get} + var typeID: ObjectIdentifier { get } @warn_unused_result func successor() -> _ForwardIndexBoxType @@ -378,7 +422,7 @@ internal class _BidirectionalIndexBox< } } -//===--- RandomAccessIndex -----------------------------------------------===// +//===--- RandomAccessIndex ------------------------------------------------===// //===----------------------------------------------------------------------===// internal protocol _RandomAccessIndexBoxType : _BidirectionalIndexBoxType {} @@ -520,7 +564,7 @@ internal class _AnyCollectionBox : _AnyCollectionBoxBase { public protocol AnyCollectionType : CollectionType { /// Identifies the underlying collection stored by `self`. Instances /// copied from one another have the same `_underlyingCollectionID`. - var _underlyingCollectionID: ObjectIdentifier {get} + var _underlyingCollectionID: ObjectIdentifier { get } } /// Return true iff `lhs` and `rhs` store the same underlying collection. diff --git a/stdlib/public/core/Filter.swift b/stdlib/public/core/Filter.swift index 020bcb2b4d836..c045b847aba94 100644 --- a/stdlib/public/core/Filter.swift +++ b/stdlib/public/core/Filter.swift @@ -1,8 +1,8 @@ -//===--- Filter.swift -----------------------------------------*- swift -*-===// +//===--- Filter.swift -----------------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -37,7 +37,7 @@ public struct LazyFilterGenerator< /// for which `predicate(x) == true`. public init( _ base: Base, - whereElementsSatisfy predicate: (Base.Element)->Bool + whereElementsSatisfy predicate: (Base.Element) -> Bool ) { self._base = base self._predicate = predicate @@ -50,7 +50,7 @@ public struct LazyFilterGenerator< /// The predicate used to determine which elements produced by /// `base` are also produced by `self`. - internal var _predicate: (Base.Element)->Bool + internal var _predicate: (Base.Element) -> Bool } /// A sequence whose elements consist of the elements of some base @@ -73,7 +73,7 @@ public struct LazyFilterSequence /// which `predicate(x) == true`. public init( _ base: Base, - whereElementsSatisfy predicate: (Base.Generator.Element)->Bool + whereElementsSatisfy predicate: (Base.Generator.Element) -> Bool ) { self.base = base self._include = predicate @@ -84,7 +84,7 @@ public struct LazyFilterSequence /// The predicate used to determine which elements of `base` are /// also elements of `self`. - internal let _include: (Base.Generator.Element)->Bool + internal let _include: (Base.Generator.Element) -> Bool } /// The `Index` used for subscripting a `LazyFilterCollection`. @@ -130,7 +130,7 @@ public struct LazyFilterIndex< /// The predicate used to determine which elements of `base` are /// also elements of `self`. - internal let _include: (BaseElements.Generator.Element)->Bool + internal let _include: (BaseElements.Generator.Element) -> Bool @available(*, unavailable, renamed="BaseElements") public typealias Base = BaseElements @@ -148,12 +148,12 @@ public func == ( /// A lazy `CollectionType` wrapper that includes the elements of an /// underlying collection that satisfy a predicate. /// -/// - Note: The performance of advancing a `LazyFilterIndex` -/// depends on how sparsely the filtering predicate is satisfied, -/// and may not offer the usual performance given by models of -/// `ForwardIndexType`. Be aware, therefore, that general operations -/// on `LazyFilterCollection` instances may not have the -/// documented complexity. +/// - Note: The performance of accessing `startIndex`, `first`, any methods +/// that depend on `startIndex`, or of advancing a `LazyFilterIndex` depends +/// on how sparsely the filtering predicate is satisfied, and may not offer +/// the usual performance given by `CollectionType` or `ForwardIndexType`. Be +/// aware, therefore, that general operations on `LazyFilterCollection` +/// instances may not have the documented complexity. public struct LazyFilterCollection< Base : CollectionType > : LazyCollectionType { @@ -168,7 +168,7 @@ public struct LazyFilterCollection< /// satisfy `predicate`. public init( _ base: Base, - whereElementsSatisfy predicate: (Base.Generator.Element)->Bool + whereElementsSatisfy predicate: (Base.Generator.Element) -> Bool ) { self._base = base self._predicate = predicate @@ -221,7 +221,7 @@ public struct LazyFilterCollection< } var _base: Base - var _predicate: (Base.Generator.Element)->Bool + var _predicate: (Base.Generator.Element) -> Bool } extension LazySequenceType { @@ -233,7 +233,7 @@ extension LazySequenceType { /// elements. @warn_unused_result public func filter( - predicate: (Elements.Generator.Element)->Bool + predicate: (Elements.Generator.Element) -> Bool ) -> LazyFilterSequence { return LazyFilterSequence( self.elements, whereElementsSatisfy: predicate) @@ -249,7 +249,7 @@ extension LazyCollectionType { /// elements. @warn_unused_result public func filter( - predicate: (Elements.Generator.Element)->Bool + predicate: (Elements.Generator.Element) -> Bool ) -> LazyFilterCollection { return LazyFilterCollection( self.elements, whereElementsSatisfy: predicate) diff --git a/stdlib/public/core/FixedPoint.swift.gyb b/stdlib/public/core/FixedPoint.swift.gyb index 64de500134a81..424c85f9d2508 100644 --- a/stdlib/public/core/FixedPoint.swift.gyb +++ b/stdlib/public/core/FixedPoint.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types, int_max_bits, should_define_truncating_bit_pattern_init # # Utility code for later in this template @@ -94,7 +94,7 @@ public protocol _DisallowMixedSignArithmetic : _IntegerType { // Int(1), which would otherwise compile due to the arithmetic // operators defined for Strideable types (unsigned types are // Strideable). - typealias _DisallowMixedSignArithmetic : SignedIntegerType = Int + associatedtype _DisallowMixedSignArithmetic : SignedIntegerType = Int } /// A set of common requirements for Swift's unsigned integer types. @@ -244,8 +244,10 @@ public struct ${Self} /// byte order if necessary. @_transparent public init(bigEndian value: ${Self}) { -#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) +#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le) self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) ) +#elseif arch(powerpc64) + self = value #else _UnsupportedArchitectureError() #endif @@ -255,8 +257,10 @@ public struct ${Self} /// byte order if necessary. @_transparent public init(littleEndian value: ${Self}) { -#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) +#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le) self = value +#elseif arch(powerpc64) + self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) ) #else _UnsupportedArchitectureError() #endif @@ -278,8 +282,10 @@ public struct ${Self} /// Returns the big-endian representation of the integer, changing the /// byte order if necessary. public var bigEndian: ${Self} { -#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) +#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le) return ${Self}(Builtin.int_bswap_${BuiltinName}(_value)) +#elseif arch(powerpc64) + return self #else _UnsupportedArchitectureError() #endif @@ -287,8 +293,10 @@ public struct ${Self} /// Returns the little-endian representation of the integer, changing the /// byte order if necessary. public var littleEndian: ${Self} { -#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) +#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le) return self +#elseif arch(powerpc64) + return ${Self}(Builtin.int_bswap_${BuiltinName}(_value)) #else _UnsupportedArchitectureError() #endif @@ -353,7 +361,7 @@ extension ${Self} : CustomStringConvertible { // restrictive than the full range of ${Self}---against which we're // not able to check. Overflows are not useful indicators of // precondition violations in this context. Therefore, we use masked -// arithmetic in this conformance, and we need to be be sure that +// arithmetic in this conformance, and we need to be sure that // generic implementations of the arithmetic operators for // RandomAccessIndexType's are all shadowed by more-specific // implementations that *do* check for overflows. @@ -606,12 +614,14 @@ public func ${op}=(inout lhs: ${Self}, rhs: ${Self}) { // FIXME: After is fixed, we should be able // to remove these. @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func ++ (inout x: ${Self}) -> ${Self} { x = x + 1 return x } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func ++ (inout x: ${Self}) -> ${Self} { let ret = x x = x + 1 @@ -619,12 +629,14 @@ public postfix func ++ (inout x: ${Self}) -> ${Self} { } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func -- (inout x: ${Self}) -> ${Self} { x = x - 1 return x } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func -- (inout x: ${Self}) -> ${Self} { let ret = x x = x - 1 diff --git a/stdlib/public/core/FlatMap.swift b/stdlib/public/core/FlatMap.swift index c5f00a1db0d45..e7408d5ec9f81 100644 --- a/stdlib/public/core/FlatMap.swift +++ b/stdlib/public/core/FlatMap.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -19,7 +19,7 @@ extension LazySequenceType { /// - Complexity: O(1) @warn_unused_result public func flatMap( - transform: (Elements.Generator.Element)->Intermediate + transform: (Elements.Generator.Element) -> Intermediate ) -> LazySequence< FlattenSequence>> { return self.map(transform).flatten() @@ -35,7 +35,7 @@ extension LazyCollectionType { /// - Complexity: O(1) @warn_unused_result public func flatMap( - transform: (Elements.Generator.Element)->Intermediate + transform: (Elements.Generator.Element) -> Intermediate ) -> LazyCollection< FlattenCollection< LazyMapCollection> @@ -57,7 +57,7 @@ extension LazyCollectionType where Elements.Index : BidirectionalIndexType Intermediate: CollectionType where Intermediate.Index : BidirectionalIndexType >( - transform: (Elements.Generator.Element)->Intermediate + transform: (Elements.Generator.Element) -> Intermediate ) -> LazyCollection< FlattenBidirectionalCollection< LazyMapCollection diff --git a/stdlib/public/core/Flatten.swift.gyb b/stdlib/public/core/Flatten.swift.gyb index 913f6aacbd162..baff3c3ad3680 100644 --- a/stdlib/public/core/Flatten.swift.gyb +++ b/stdlib/public/core/Flatten.swift.gyb @@ -1,8 +1,8 @@ -//===--- Flatten.swift.gyb ------------------------------------------------===// +//===--- Flatten.swift.gyb ------------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -144,11 +144,18 @@ public struct ${Index}< /// - Requires: The previous value is representable. public func predecessor() -> ${Index} { var prevOuter = _outer - var prevInnerCollection = _innerCollection ?? _base[--prevOuter] + var prevInnerCollection : BaseElements.Generator.Element + if let ic = _innerCollection { + prevInnerCollection = ic + } else { + prevOuter._predecessorInPlace() + prevInnerCollection = _base[prevOuter] + } var prevInner = _inner ?? prevInnerCollection.endIndex while prevInner == prevInnerCollection.startIndex { - prevInnerCollection = _base[--prevOuter] + prevOuter._predecessorInPlace() + prevInnerCollection = _base[prevOuter] prevInner = prevInnerCollection.endIndex } @@ -218,6 +225,14 @@ public func == ( /// * `c.flatten().map(f)` maps eagerly and returns a new array /// * `c.lazy.flatten().map(f)` maps lazily and returns a `LazyMapCollection` /// +/// - Note: The performance of accessing `startIndex`, `first`, any methods +/// that depend on `startIndex`, or of advancing a `${Collection}Index` +/// depends on how many empty subcollections are found in the base +/// collection, and may not offer the usual performance given by +/// `CollectionType` or `${traversal}IndexType`. Be aware, therefore, that +/// general operations on `${Collection}` instances may not have the +/// documented complexity. +/// /// - See also: `FlattenSequence` public struct ${Collection}< Base: CollectionType where ${constraints % {'Base': 'Base.'}} diff --git a/stdlib/public/core/FloatingPoint.swift.gyb b/stdlib/public/core/FloatingPoint.swift.gyb index 62c7f40a89cbb..e9bbb2694bd01 100644 --- a/stdlib/public/core/FloatingPoint.swift.gyb +++ b/stdlib/public/core/FloatingPoint.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -158,12 +158,6 @@ def getMinFloat(floatBits, intBits): minFloat = negativePrefix(floatBits) + negativeExponent(floatBits, intBits) return "0x%0.x" % minFloat -def incIfSigned(bits, signed): - if not(signed): - return bits + 1 - else: - return bits - }% % for bits in allFloatBits: @@ -181,7 +175,7 @@ public struct ${Self} { @_transparent public init() { let zero: Int64 = 0 - self._value = Builtin.uitofp_Int64_FPIEEE${bits}(zero._value) + self._value = Builtin.sitofp_Int64_FPIEEE${bits}(zero._value) } @_transparent @@ -574,12 +568,16 @@ extension ${Self} { //===----------------------------------------------------------------------===// @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func ++ (inout rhs: ${Self}) -> ${Self} { rhs += 1.0; return rhs } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func -- (inout rhs: ${Self}) -> ${Self} { rhs -= 1.0; return rhs } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func ++ (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs += 1.0; return tmp } @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func -- (inout lhs: ${Self}) -> ${Self} { let tmp = lhs; lhs -= 1.0; return tmp } @@ -645,6 +643,7 @@ public func ${op}= (inout lhs: ${Self}, rhs: ${Self}) { lhs = lhs ${op} rhs } % sign = 's' if signed else 'u' % Self = intName(bits, signed) % BuiltinName = builtinIntName(bits) +% intBits = intFormatFix(bits) @_transparent extension ${Self} { % for srcBits in allFloatBits: @@ -662,23 +661,28 @@ extension ${Self} { // Float80.isFinite is missing _precondition( other.isFinite, - "floating point value can not be converted to ${Self} because it is either infinite or NaN") + "floating point value cannot be converted to ${Self} because it is either infinite or NaN") % if signed: // FIXME: Float80 doesn't have a _fromBitPattern // ${That}(roundTowardsZero: ${Self}.min) - // > ${getMinFloat(srcBits, incIfSigned(intFormatFix(bits), signed))} - _precondition(other >= ${That}._fromBitPattern(${getMinFloat(srcBits, - incIfSigned(intFormatFix(bits), signed))}), - "floating point value can not be converted to ${Self} because it is less than ${Self}.min") + // > ${getMinFloat(srcBits, intBits)} + _precondition(other >= ${That}._fromBitPattern(${getMinFloat(srcBits, intBits)}), + "floating point value cannot be converted to ${Self} because it is less than ${Self}.min") + // ${That}(roundTowardsZero: ${Self}.max) + // > ${getMaxFloat(srcBits, intBits)} + _precondition(other <= ${That}._fromBitPattern(${getMaxFloat(srcBits, intBits)}), + "floating point value cannot be converted to ${Self} because it is greater than ${Self}.max") % else: _precondition(other >= (0.0 as ${That}), - "floating point value can not be converted to ${Self} because it is less than ${Self}.min") -% end + "floating point value cannot be converted to ${Self} because it is less than ${Self}.min") +% # NOTE: Since unsigned ints effectively have one more bit than signed ints +% # for storing positive numbers, we use `intBits + 1` when calculating the +% # max acceptable float value in the following lines. // ${That}(roundTowardsZero: ${Self}.max) - // > ${getMaxFloat(srcBits, incIfSigned(intFormatFix(bits), signed))} - _precondition(other <= ${That}._fromBitPattern(${getMaxFloat(srcBits, - incIfSigned(intFormatFix(bits), signed))}), - "floating point value can not be converted to ${Self} because it is greater than ${Self}.max") + // > ${getMaxFloat(srcBits, intBits + 1)} + _precondition(other <= ${That}._fromBitPattern(${getMaxFloat(srcBits, intBits + 1)}), + "floating point value cannot be converted to ${Self} because it is greater than ${Self}.max") +% end % end self._value = diff --git a/stdlib/public/core/FloatingPointOperations.swift.gyb b/stdlib/public/core/FloatingPointOperations.swift.gyb index 3b8f516caef39..c8c1f4ea7b06b 100644 --- a/stdlib/public/core/FloatingPointOperations.swift.gyb +++ b/stdlib/public/core/FloatingPointOperations.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 @@ -33,31 +33,9 @@ public enum FloatingPointClassification { case PositiveInfinity } -extension FloatingPointClassification : Equatable {} - -public -func ==(lhs: FloatingPointClassification, rhs: FloatingPointClassification) -> Bool { - switch (lhs, rhs) { - case (.SignalingNaN, .SignalingNaN), - (.QuietNaN, .QuietNaN), - (.NegativeInfinity, .NegativeInfinity), - (.NegativeNormal, .NegativeNormal), - (.NegativeSubnormal, .NegativeSubnormal), - (.NegativeZero, .NegativeZero), - (.PositiveZero, .PositiveZero), - (.PositiveSubnormal, .PositiveSubnormal), - (.PositiveNormal, .PositiveNormal), - (.PositiveInfinity, .PositiveInfinity): - return true - - default: - return false - } -} - /// A set of common requirements for Swift's floating point types. public protocol FloatingPointType : Strideable { - typealias _BitsType + associatedtype _BitsType @warn_unused_result static func _fromBitPattern(bits: _BitsType) -> Self diff --git a/stdlib/public/core/FloatingPointParsing.swift.gyb b/stdlib/public/core/FloatingPointParsing.swift.gyb index b3d985d7c202f..f662ae5a2b97f 100644 --- a/stdlib/public/core/FloatingPointParsing.swift.gyb +++ b/stdlib/public/core/FloatingPointParsing.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/HashedCollections.swift.gyb b/stdlib/public/core/HashedCollections.swift.gyb index cffd0c65a97b2..fb7742ee81691 100644 --- a/stdlib/public/core/HashedCollections.swift.gyb +++ b/stdlib/public/core/HashedCollections.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -201,10 +201,10 @@ import SwiftShims /// This protocol is only used for compile-time checks that /// every storage type implements all required operations. internal protocol _HashStorageType { - typealias Key - typealias Value - typealias Index - typealias SequenceElement + associatedtype Key + associatedtype Value + associatedtype Index + associatedtype SequenceElement var startIndex: Index { get } var endIndex: Index { get } @@ -713,15 +713,18 @@ public func == (lhs: Set, rhs: Set) -> Boo } let endIndex = lhsNative.endIndex - for var i = lhsNative.startIndex; i != endIndex; i = i.successor() { + var i = lhsNative.startIndex + while i != endIndex { let key = lhsNative.assertingGet(i) let bridgedKey: AnyObject = _bridgeToObjectiveCUnconditional(key) let optRhsValue: AnyObject? = rhsCocoa.maybeGet(bridgedKey) if let rhsValue = optRhsValue { if key == _forceBridgeFromObjectiveC(rhsValue, Element.self) { + i = i.successor() continue } } + i = i.successor() return false } return true @@ -1230,16 +1233,18 @@ public func == ( } let endIndex = lhsNative.endIndex - for var index = lhsNative.startIndex; index != endIndex; - index = index.successor() { + var index = lhsNative.startIndex + while index != endIndex { let (key, value) = lhsNative.assertingGet(index) let optRhsValue: AnyObject? = rhsCocoa.maybeGet(_bridgeToObjectiveCUnconditional(key)) if let rhsValue = optRhsValue { if value == _forceBridgeFromObjectiveC(rhsValue, Value.self) { + index._successorInPlace() continue } } + index._successorInPlace() return false } return true @@ -1313,7 +1318,7 @@ internal func _stdlib_NSDictionary_allKeys(nsd: _NSDictionaryType) } #endif -//===--- Compiler conversion/casting entry points for Dictionary =// +//===--- Compiler conversion/casting entry points for Dictionary ----===// #if _runtime(_ObjC) /// Perform a non-bridged upcast that always succeeds. @@ -1420,7 +1425,7 @@ public func _dictionaryDownCast( switch source._variantStorage { case .Native(let nativeOwner): // FIXME(performance): this introduces an indirection through Objective-C - // runtime, even though we access native storage. But we can not + // runtime, even though we access native storage. But we cannot // unsafeBitCast the owner object, because that would change the generic // arguments. // @@ -2113,7 +2118,7 @@ struct _Native${Self}Storage<${TypeParametersDecl}> : var description: String { var result = "" #if INTERNAL_CHECKS_ENABLED - for var i = 0; i != capacity; ++i { + for i in 0.. : continue } nativeStorage.initializeKey(key, at: i.offset) - ++count + count += 1 } nativeStorage.count = count @@ -2252,7 +2257,7 @@ struct _Native${Self}Storage<${TypeParametersDecl}> : #if _runtime(_ObjC) /// Storage for bridged `${Self}` elements. We could have used -/// `${Self}<${AnyTypeParameters}>`, but `AnyObject` can not be a Key because +/// `${Self}<${AnyTypeParameters}>`, but `AnyObject` cannot be a Key because /// it is not `Hashable`. internal struct _BridgedNative${Self}Storage { internal typealias StorageImpl = @@ -2390,7 +2395,7 @@ final internal class _Native${Self}StorageKeyNSEnumerator< return nil } let bridgedKey: AnyObject = nativeStorageOwner._getBridgedKey(nextIndex) - nextIndex = nextIndex.successor() + nextIndex._successorInPlace() return bridgedKey } @@ -2415,7 +2420,7 @@ final internal class _Native${Self}StorageKeyNSEnumerator< // Return only a single element so that code can start iterating via fast // enumeration, terminate it, and continue via NSEnumerator. let bridgedKey: AnyObject = nativeStorageOwner._getBridgedKey(nextIndex) - nextIndex = nextIndex.successor() + nextIndex._successorInPlace() let unmanagedObjects = _UnmanagedAnyObjectArray(objects) unmanagedObjects[0] = bridgedKey @@ -2601,7 +2606,7 @@ final internal class _Native${Self}StorageOwner<${TypeParametersDecl}> let bridged = _createBridgedNativeStorage(nativeStorage.capacity) // Bridge everything. - for var i = 0; i < nativeStorage.capacity; ++i { + for i in 0.. while position < count { if bridgedNativeStorage.isInitializedEntry(position) { unmanagedObjects[i] = bridgedNativeStorage.valueAt(position) - i++ + i += 1 } - position++ + position += 1 } } } else { @@ -2695,9 +2700,9 @@ final internal class _Native${Self}StorageOwner<${TypeParametersDecl}> while position < count { if bridgedNativeStorage.isInitializedEntry(position) { unmanagedKeys[i] = bridgedNativeStorage.keyAt(position) - i++ + i += 1 } - position++ + position += 1 } } else { // keys nonnull, objects nonnull @@ -2705,9 +2710,9 @@ final internal class _Native${Self}StorageOwner<${TypeParametersDecl}> if bridgedNativeStorage.isInitializedEntry(position) { unmanagedObjects[i] = bridgedNativeStorage.valueAt(position) unmanagedKeys[i] = bridgedNativeStorage.keyAt(position) - i++ + i += 1 } - position++ + position += 1 } } } @@ -2766,8 +2771,8 @@ final internal class _Native${Self}StorageOwner<${TypeParametersDecl}> let bridgedKey: AnyObject = _getBridgedKey(currIndex) unmanagedObjects[i] = bridgedKey - ++stored - currIndex = currIndex.successor() + stored += 1 + currIndex._successorInPlace() } theState.extra.0 = CUnsignedLong(currIndex.offset) state.memory = theState @@ -2860,19 +2865,19 @@ internal struct _Cocoa${Self}Storage : _HashStorageType { } internal mutating func updateValue(value: Value, forKey: Key) -> Value? { - _sanityCheckFailure("can not mutate NS${Self}") + _sanityCheckFailure("cannot mutate NS${Self}") } internal mutating func removeAtIndex(index: Index) -> SequenceElement { - _sanityCheckFailure("can not mutate NS${Self}") + _sanityCheckFailure("cannot mutate NS${Self}") } internal mutating func removeValueForKey(key: Key) -> Value? { - _sanityCheckFailure("can not mutate NS${Self}") + _sanityCheckFailure("cannot mutate NS${Self}") } internal mutating func removeAll(keepCapacity keepCapacity: Bool) { - _sanityCheckFailure("can not mutate NS${Self}") + _sanityCheckFailure("cannot mutate NS${Self}") } internal var count: Int { @@ -2910,7 +2915,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { @_transparent internal var guaranteedNative: Bool { - return _canBeClass(Key.self) == 0 && _canBeClass(Value.self) == 0 + return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 } @warn_unused_result @@ -3051,6 +3056,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { internal typealias Index = ${Self}Index<${TypeParameters}> internal var startIndex: Index { + if _fastPath(guaranteedNative) { + return ._Native(native.startIndex) + } + switch self { case .Native: return ._Native(native.startIndex) @@ -3064,6 +3073,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { } internal var endIndex: Index { + if _fastPath(guaranteedNative) { + return ._Native(native.endIndex) + } + switch self { case .Native: return ._Native(native.endIndex) @@ -3078,6 +3091,13 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { @warn_unused_result internal func indexForKey(key: Key) -> Index? { + if _fastPath(guaranteedNative) { + if let nativeIndex = native.indexForKey(key) { + return ._Native(nativeIndex) + } + return nil + } + switch self { case .Native: if let nativeIndex = native.indexForKey(key) { @@ -3099,6 +3119,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { @warn_unused_result internal func assertingGet(i: Index) -> SequenceElement { + if _fastPath(guaranteedNative) { + return native.assertingGet(i._nativeIndex) + } + switch self { case .Native: return native.assertingGet(i._nativeIndex) @@ -3123,6 +3147,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { @warn_unused_result internal func assertingGet(key: Key) -> Value { + if _fastPath(guaranteedNative) { + return native.assertingGet(key) + } + switch self { case .Native: return native.assertingGet(key) @@ -3153,6 +3181,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { @warn_unused_result internal func maybeGet(key: Key) -> Value? { + if _fastPath(guaranteedNative) { + return native.maybeGet(key) + } + switch self { case .Native: return native.maybeGet(key) @@ -3187,7 +3219,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { native.setKey(key, at: i.offset) } else { native.initializeKey(key, at: i.offset) - ++native.count + native.count += 1 } %elif Self == 'Dictionary': let oldValue: Value? = found ? native.valueAt(i.offset) : nil @@ -3195,7 +3227,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { native.setKey(key, value: value, at: i.offset) } else { native.initializeKey(key, value: value, at: i.offset) - ++native.count + native.count += 1 } %end @@ -3234,7 +3266,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { // remove the element nativeStorage.destroyEntryAt(offset) - --nativeStorage.count + nativeStorage.count -= 1 // If we've put a hole in a chain of contiguous elements, some // element after the hole may belong where the new hole is. @@ -3248,10 +3280,10 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { // Find the last bucket in the contiguous chain var lastInChain = hole - for var b = nativeStorage._next(lastInChain); - nativeStorage.isInitializedEntry(b); - b = nativeStorage._next(b) { + var b = nativeStorage._next(lastInChain) + while nativeStorage.isInitializedEntry(b) { lastInChain = b + b = nativeStorage._next(b) } // Relocate out-of-place elements in the chain, repeating until @@ -3259,8 +3291,8 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { while hole != lastInChain { // Walk backwards from the end of the chain looking for // something out-of-place. - var b: Int - for b = lastInChain; b != hole; b = nativeStorage._prev(b) { + var b = lastInChain + while b != hole { let idealBucket = nativeStorage._bucket(nativeStorage.keyAt(b)) // Does this element belong between start and hole? We need @@ -3271,6 +3303,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { if start <= hole ? (c0 && c1) : (c0 || c1) { break // Found it } + b = nativeStorage._prev(b) } if b == hole { // No out-of-place elements found; we're done adjusting @@ -3398,7 +3431,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { var nativeStorage = native // FIXME(performance): if the storage is non-uniquely referenced, we - // shouldn’t be copying the elements into new storage and then immediately + // shouldn't be copying the elements into new storage and then immediately // deleting the elements. We should detect that the storage is not uniquely // referenced and allocate new empty storage of appropriate capacity. @@ -3409,7 +3442,7 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType { nativeStorage = native } - for var b = 0; b != nativeStorage.capacity; ++b { + for b in 0.. : _HashStorageType { } internal var count: Int { + if _fastPath(guaranteedNative) { + return native.count + } + switch self { case .Native: return native.count @@ -3510,7 +3547,7 @@ internal struct _Native${Self}Index<${TypeParametersDecl}> : break } // end workaround - ++i + i += 1 } return NativeIndex(nativeStorage: nativeStorage, offset: i) } @@ -3584,7 +3621,7 @@ internal struct _Cocoa${Self}Index : ForwardIndexType, Comparable { @warn_unused_result internal func successor() -> _Cocoa${Self}Index { _precondition( - currentKeyIndex < allKeys.value, "can not increment endIndex") + currentKeyIndex < allKeys.value, "cannot increment endIndex") return _Cocoa${Self}Index(cocoa${Self}, allKeys, currentKeyIndex + 1) } } @@ -3592,7 +3629,7 @@ internal struct _Cocoa${Self}Index : ForwardIndexType, Comparable { @warn_unused_result internal func ==(lhs: _Cocoa${Self}Index, rhs: _Cocoa${Self}Index) -> Bool { _precondition(lhs.cocoa${Self} === rhs.cocoa${Self}, - "can not compare indexes pointing to different ${Self}s") + "cannot compare indexes pointing to different ${Self}s") _precondition(lhs.allKeys.value == rhs.allKeys.value, "one or both of the indexes have been invalidated") @@ -3602,7 +3639,7 @@ internal func ==(lhs: _Cocoa${Self}Index, rhs: _Cocoa${Self}Index) -> Bool { @warn_unused_result internal func <(lhs: _Cocoa${Self}Index, rhs: _Cocoa${Self}Index) -> Bool { _precondition(lhs.cocoa${Self} === rhs.cocoa${Self}, - "can not compare indexes pointing to different ${Self}s") + "cannot compare indexes pointing to different ${Self}s") _precondition(lhs.allKeys.value == rhs.allKeys.value, "one or both of the indexes have been invalidated") @@ -3648,7 +3685,7 @@ public struct ${Self}Index<${TypeParametersDecl}> : // not, because neither NSEnumerator nor fast enumeration support moving // backwards. Even if they did, there is another issue: NSEnumerator does // not support NSCopying, and fast enumeration does not document that it is - // safe to copy the state. So, we can not implement Index that is a value + // safe to copy the state. So, we cannot implement Index that is a value // type for bridged NS${Self} in terms of Cocoa enumeration facilities. internal typealias _NativeIndex = _Native${Self}Index<${TypeParameters}> @@ -3771,7 +3808,7 @@ public func < <${TypeParametersDecl}> ( final internal class _Cocoa${Self}Generator : GeneratorType { internal typealias Element = ${AnySequenceType} - // Cocoa ${Self} generator has to be a class, otherwise we can not + // Cocoa ${Self} generator has to be a class, otherwise we cannot // guarantee that the fast enumeration struct is pinned to a certain memory // location. @@ -3796,7 +3833,7 @@ final internal class _Cocoa${Self}Generator : GeneratorType { return UnsafeMutablePointer(_fastEnumerationStatePtr + 1) } - // These members have to be word-sized integers, they can not be limited to + // These members have to be word-sized integers, they cannot be limited to // Int8 just because our buffer holds 16 elements: fast enumeration is // allowed to return inner pointers to the container, which can be much // larger. @@ -3832,7 +3869,7 @@ final internal class _Cocoa${Self}Generator : GeneratorType { UnsafeMutablePointer(_fastEnumerationState.itemsPtr) let itemsPtr = _UnmanagedAnyObjectArray(itemsPtrUP) let key: AnyObject = itemsPtr[itemIndex] - ++itemIndex + itemIndex += 1 %if Self == 'Set': return key %elif Self == 'Dictionary': @@ -3905,7 +3942,7 @@ public struct ${Self}Generator<${TypeParametersDecl}> : GeneratorType { %if Self == 'Set': return _canBeClass(Element.self) == 0 %elif Self == 'Dictionary': - return _canBeClass(Key.self) == 0 && _canBeClass(Value.self) == 0 + return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 %end } @@ -3970,7 +4007,7 @@ internal struct ${Self}MirrorPosition<${TypeParametersDecl}> { internal mutating func successor() { _intPos = _intPos + 1 - ${Self}Pos = ${Self}Pos.successor() + ${Self}Pos._successorInPlace() } } @@ -3996,69 +4033,16 @@ internal func < <${TypeParametersDecl}> ( return lhs._intPos < rhs } -internal class ${Self}Mirror<${TypeParametersDecl}> : _MirrorType { - typealias MirroredType = ${Self}<${TypeParameters}> - internal let _mirror : MirroredType - internal var _pos : ${Self}MirrorPosition<${TypeParameters}> - - internal init(_ m : MirroredType) { - _mirror = m - _pos = ${Self}MirrorPosition(m) - } - - internal var value: Any { return (_mirror as Any) } - - internal var valueType: Any.Type { return (_mirror as Any).dynamicType } - - internal var objectIdentifier: ObjectIdentifier? { return nil } - - internal var count: Int { return _mirror.count } - - internal subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - - if _pos > i { - _pos._intPos = 0 - } - - while _pos < i && !(_pos == i) { - _pos.successor() - } -%if Self == 'Set': - return ("[\(_pos._intPos)]", _reflect(_mirror[_pos.${Self}Pos])) -%elif Self == 'Dictionary': - return ("[\(_pos._intPos)]", _reflect(_mirror[_pos.${Self}Pos])) -%end - } - - internal var summary: String { -%if Self == 'Set': - if count == 1 { - return "1 member" - } - return "\(count) members" -%elif Self == 'Dictionary': - if count == 1 { - return "1 key/value pair" - } - return "\(count) key/value pairs" -%end - } - - internal var quickLookObject: PlaygroundQuickLook? { return nil } - +extension ${Self} : CustomReflectable { + /// Returns a mirror that reflects `self`. + @warn_unused_result + public func customMirror() -> Mirror { %if Self == 'Set': - internal var disposition: _MirrorDisposition { return .MembershipContainer } + let style = Mirror.DisplayStyle.Set %elif Self == 'Dictionary': - internal var disposition: _MirrorDisposition { return .KeyContainer } + let style = Mirror.DisplayStyle.Dictionary %end -} - -extension ${Self} : _Reflectable { - /// Returns a mirror that reflects `self`. - @warn_unused_result - public func _getMirror() -> _MirrorType { - return ${Self}Mirror(self) + return Mirror(self, unlabeledChildren: self, displayStyle: style) } } @@ -4094,13 +4078,13 @@ public struct _${Self}Builder<${TypeParametersDecl}> { public mutating func add(key newKey: Key, value: Value) { _nativeStorage.unsafeAddNew(key: newKey, value: value) %end - _actualCount++ + _actualCount += 1 } @warn_unused_result public mutating func take() -> ${Self}<${TypeParameters}> { _precondition(_actualCount >= 0, - "can not take the result twice") + "cannot take the result twice") _precondition(_actualCount == _requestedCount, "the number of members added does not match the promised count") diff --git a/stdlib/public/core/Hashing.swift b/stdlib/public/core/Hashing.swift index e265efddea646..417046140d3f6 100644 --- a/stdlib/public/core/Hashing.swift +++ b/stdlib/public/core/Hashing.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -116,7 +116,7 @@ public // @testable func _mixUInt(value: UInt) -> UInt { #if arch(i386) || arch(arm) return UInt(_mixUInt32(UInt32(value))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return UInt(_mixUInt64(UInt64(value))) #endif } @@ -127,7 +127,7 @@ public // @testable func _mixInt(value: Int) -> Int { #if arch(i386) || arch(arm) return Int(_mixInt32(Int32(value))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return Int(_mixInt64(Int64(value))) #endif } @@ -166,7 +166,7 @@ func _squeezeHashValue(hashValue: Int, _ resultRange: Range) -> Int { // We perform the unchecked arithmetic on `UInt` (instead of doing // straightforward computations on `Int`) in order to handle the following // tricky case: `startIndex` is negative, and `resultCardinality >= Int.max`. - // We can not convert the latter to `Int`. + // We cannot convert the latter to `Int`. return Int(bitPattern: UInt(bitPattern: resultRange.startIndex) &+ unsignedResult) diff --git a/stdlib/public/core/HeapBuffer.swift b/stdlib/public/core/HeapBuffer.swift index 3b7e7258e473d..0ba2662a89074 100644 --- a/stdlib/public/core/HeapBuffer.swift +++ b/stdlib/public/core/HeapBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/ImplicitlyUnwrappedOptional.swift b/stdlib/public/core/ImplicitlyUnwrappedOptional.swift index f4e732c0c6d4c..feebf8f7f59c1 100644 --- a/stdlib/public/core/ImplicitlyUnwrappedOptional.swift +++ b/stdlib/public/core/ImplicitlyUnwrappedOptional.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,8 +16,7 @@ /// The compiler has special knowledge of the existence of /// `ImplicitlyUnwrappedOptional`, but always interacts with it using /// the library intrinsics below. -public enum ImplicitlyUnwrappedOptional - : _Reflectable, NilLiteralConvertible { +public enum ImplicitlyUnwrappedOptional : NilLiteralConvertible { case None case Some(Wrapped) @@ -71,16 +70,6 @@ public enum ImplicitlyUnwrappedOptional return .None } } - - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - // FIXME: This should probably use _OptionalMirror in both cases. - if let value = self { - return _reflect(value) - } else { - return _OptionalMirror(.None) - } - } } extension ImplicitlyUnwrappedOptional : CustomStringConvertible { diff --git a/stdlib/public/core/Index.swift b/stdlib/public/core/Index.swift index 708cc390f6de6..68d2f21ef5ce0 100644 --- a/stdlib/public/core/Index.swift +++ b/stdlib/public/core/Index.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -73,6 +73,7 @@ public struct _DisabledRangeIndex_ { /// Replace `i` with its `successor()` and return the updated value of /// `i`. @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func ++ (inout i: T) -> T { i._successorInPlace() return i @@ -81,6 +82,7 @@ public prefix func ++ (inout i: T) -> T { /// Replace `i` with its `successor()` and return the original /// value of `i`. @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func ++ (inout i: T) -> T { let ret = i i._successorInPlace() @@ -96,11 +98,11 @@ public protocol ForwardIndexType : _Incrementable { /// /// Reachability is defined by the ability to produce one value from /// the other via zero or more applications of `successor`. - typealias Distance : _SignedIntegerType = Int + associatedtype Distance : _SignedIntegerType = Int // See the implementation of Range for an explanation of this // associated type - typealias _DisabledRangeIndex = _DisabledRangeIndex_ + associatedtype _DisabledRangeIndex = _DisabledRangeIndex_ /// Performs a range check in O(1), or a no-op when a range check is not /// implementable in O(1). @@ -216,7 +218,7 @@ extension ForwardIndexType { var p = self var i : Distance = 0 while i != n { - p = p.successor() + p._successorInPlace() i = i + 1 } return p @@ -232,7 +234,7 @@ extension ForwardIndexType { var i : Distance = 0 while i != n { if p == limit { break } - p = p.successor() + p._successorInPlace() i = i + 1 } return p @@ -254,7 +256,7 @@ extension ForwardIndexType { var count: Distance = 0 while p != end { count += 1 - p = p.successor() + p._successorInPlace() } return count } @@ -319,6 +321,7 @@ extension BidirectionalIndexType { /// Replace `i` with its `predecessor()` and return the updated value /// of `i`. @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public prefix func -- (inout i: T) -> T { i._predecessorInPlace() return i @@ -328,6 +331,7 @@ public prefix func -- (inout i: T) -> T { /// Replace `i` with its `predecessor()` and return the original /// value of `i`. @_transparent +@available(*, deprecated, message="it will be removed in Swift 3") public postfix func -- (inout i: T) -> T { let ret = i i._predecessorInPlace() @@ -340,13 +344,13 @@ public postfix func -- (inout i: T) -> T { /// Used to force conformers of RandomAccessIndexType to implement /// `advancedBy` methods and `distanceTo`. public protocol _RandomAccessAmbiguity { - typealias Distance : _SignedIntegerType = Int + associatedtype Distance : _SignedIntegerType = Int } extension _RandomAccessAmbiguity { @warn_unused_result public func advancedBy(n: Distance) -> Self { - fatalError("advancedBy(n) not implememented") + fatalError("advancedBy(n) not implemented") } } diff --git a/stdlib/public/core/InputStream.swift b/stdlib/public/core/InputStream.swift index 78add15a21322..c66fca4cd9dcb 100644 --- a/stdlib/public/core/InputStream.swift +++ b/stdlib/public/core/InputStream.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/IntegerArithmetic.swift.gyb b/stdlib/public/core/IntegerArithmetic.swift.gyb index 1f19cc0cf3297..d6c46369efe9a 100644 --- a/stdlib/public/core/IntegerArithmetic.swift.gyb +++ b/stdlib/public/core/IntegerArithmetic.swift.gyb @@ -1,8 +1,8 @@ -//===--- IntegerArithmetic.swift.gyb -------------------------*- swift -*--===// +//===--- IntegerArithmetic.swift.gyb --------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/IntegerParsing.swift.gyb b/stdlib/public/core/IntegerParsing.swift.gyb index 66e64f977e264..3f32e266c6be6 100644 --- a/stdlib/public/core/IntegerParsing.swift.gyb +++ b/stdlib/public/core/IntegerParsing.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types, int_max_bits # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 @@ -67,21 +67,21 @@ internal func _parseUnsignedAsciiAsUIntMax( /// non-negative number <= `maximum`, return that number. Otherwise, /// return `nil`. /// -/// - Note: If `text` begins with `"+"` or `"-"`, even if the rest of -/// the characters are `"0"`, the result is `nil`. +/// - Note: For text matching the regular expression "-0+", the result +/// is `0`, not `nil`. internal func _parseAsciiAsUIntMax( - u16: String.UTF16View, _ radix: Int, _ maximum: UIntMax + utf16: String.UTF16View, _ radix: Int, _ maximum: UIntMax ) -> UIntMax? { - if u16.isEmpty { return nil } - let c = u16.first - if _fastPath(c != _ascii16("-")) { - let unsignedText - = c == _ascii16("+") ? u16.dropFirst() : u16 - return _parseUnsignedAsciiAsUIntMax(unsignedText, radix, maximum) - } - else { - return _parseAsciiAsIntMax(u16, radix, 0) == 0 ? 0 : nil - } + if utf16.isEmpty { return nil } + // Parse (optional) sign. + let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16) + // Parse digits. + guard let result = _parseUnsignedAsciiAsUIntMax(digitsUTF16, radix, maximum) + else { return nil } + // Disallow < 0. + if hasMinus && result != 0 { return nil } + + return result } /// If text is an ASCII representation in the given `radix` of a @@ -91,23 +91,30 @@ internal func _parseAsciiAsUIntMax( /// - Note: For text matching the regular expression "-0+", the result /// is `0`, not `nil`. internal func _parseAsciiAsIntMax( - u16: String.UTF16View, _ radix: Int, _ maximum: IntMax + utf16: String.UTF16View, _ radix: Int, _ maximum: IntMax ) -> IntMax? { _sanityCheck(maximum >= 0, "maximum should be non-negative") + if utf16.isEmpty { return nil } + // Parse (optional) sign. + let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16) + // Parse digits. +1 for negatives because e.g. Int8's range is -128...127. + let absValueMax = UIntMax(bitPattern: maximum) + (hasMinus ? 1 : 0) + guard let absValue = + _parseUnsignedAsciiAsUIntMax(digitsUTF16, radix, absValueMax) + else { return nil } + // Convert to signed. + return IntMax(bitPattern: hasMinus ? 0 &- absValue : absValue) +} - if u16.isEmpty { return nil } - - // Drop any leading "-" - let negative = u16.first == _ascii16("-") - let absResultText = negative ? u16.dropFirst() : u16 - - let absResultMax = UIntMax(bitPattern: maximum) + (negative ? 1 : 0) - - // Parse the result as unsigned - if let absResult = _parseAsciiAsUIntMax(absResultText, radix, absResultMax) { - return IntMax(bitPattern: negative ? 0 &- absResult : absResult) +/// Strip an optional single leading ASCII plus/minus sign from `utf16`. +private func _parseOptionalAsciiSign( + utf16: String.UTF16View +) -> (digitsUTF16: String.UTF16View, isMinus: Bool) { + switch utf16.first { + case _ascii16("-")?: return (utf16.dropFirst(), true) + case _ascii16("+")?: return (utf16.dropFirst(), false) + default: return (utf16, false) } - return nil } //===--- Loop over all integer types --------------------------------------===// diff --git a/stdlib/public/core/Interval.swift.gyb b/stdlib/public/core/Interval.swift.gyb index 3c0c846c401db..114e9d1aefd44 100644 --- a/stdlib/public/core/Interval.swift.gyb +++ b/stdlib/public/core/Interval.swift.gyb @@ -1,8 +1,8 @@ -//===--- Interval.swift.gyb ----------------------------------*- swift -*--===// +//===--- Interval.swift.gyb -----------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,7 +13,7 @@ /// An interval over a `Comparable` type. public protocol IntervalType { /// The type of the `Interval`'s endpoints. - typealias Bound : Comparable + associatedtype Bound : Comparable /// Returns `true` iff the interval contains `value`. @warn_unused_result @@ -25,17 +25,17 @@ public protocol IntervalType { func clamp(intervalToClamp: Self) -> Self /// `true` iff `self` is empty. - var isEmpty: Bool {get} + var isEmpty: Bool { get } /// The `Interval`'s lower bound. /// /// Invariant: `start` <= `end`. - var start: Bound {get} + var start: Bound { get } /// The `Interval`'s upper bound. /// /// Invariant: `start` <= `end`. - var end: Bound {get} + var end: Bound { get } } % for Kind, rangeOperator, upperBoundCompare in [ @@ -58,7 +58,8 @@ selfDocComment += """ ${selfDocComment} public struct ${Self} - : IntervalType, Equatable, CustomStringConvertible, CustomDebugStringConvertible, _Reflectable { + : IntervalType, Equatable, CustomStringConvertible, CustomDebugStringConvertible, + CustomReflectable, CustomPlaygroundQuickLookable { @available(*, unavailable, renamed="Bound") public typealias T = Bound @@ -129,8 +130,12 @@ public struct ${Self} /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _IntervalMirror(self) + public func customMirror() -> Mirror { + return Mirror(self, children: ["start": start, "end": end]) + } + + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(description) } internal var _start: Bound @@ -199,33 +204,3 @@ public func ... ( public func ~= (pattern: I, value: I.Bound) -> Bool { return pattern.contains(value) } - -// Reflection support -%import gyb -%TBoilerplate = gyb.parseTemplate("../common/MirrorBoilerplate.gyb") - -%Boilerplate = gyb.executeTemplate(TBoilerplate,\ -% introspecteeType='T',\ -% disposition='Struct') - -internal struct _IntervalMirror< - T : protocol -> : _MirrorType { - ${Boilerplate} - - internal var count: Int { return 2 } - - internal subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: return ("start", _reflect(_value.start)) - case 1: return ("end", _reflect(_value.end)) - default: _preconditionFailure("_MirrorType access out of bounds") - } - } - - internal var summary: String { return _value.description } - - internal var quickLookObject: PlaygroundQuickLook? { - return .Text(summary) - } -} diff --git a/stdlib/public/core/Join.swift b/stdlib/public/core/Join.swift index 901d6e0cc410b..8a18093826fc0 100644 --- a/stdlib/public/core/Join.swift +++ b/stdlib/public/core/Join.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/LazyCollection.swift b/stdlib/public/core/LazyCollection.swift index d811b87ce4359..6a56394772825 100644 --- a/stdlib/public/core/LazyCollection.swift +++ b/stdlib/public/core/LazyCollection.swift @@ -1,8 +1,8 @@ -//===--- LazyCollection.swift ---------------------------------*- swift -*-===// +//===--- LazyCollection.swift ---------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -27,7 +27,7 @@ public protocol LazyCollectionType /// possibly with a simpler type. /// /// - See also: `elements` - typealias Elements: CollectionType = Self + associatedtype Elements: CollectionType = Self } diff --git a/stdlib/public/core/LazySequence.swift b/stdlib/public/core/LazySequence.swift index 590b8910349d1..c6a6a47c39ce2 100644 --- a/stdlib/public/core/LazySequence.swift +++ b/stdlib/public/core/LazySequence.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -47,7 +47,7 @@ /// /// - Complexity: O(N) /// func scan( /// initial: ResultElement, -/// @noescape combine: (ResultElement, Generator.Element)->ResultElement +/// @noescape combine: (ResultElement, Generator.Element) -> ResultElement /// ) -> [ResultElement] { /// var result = [initial] /// for x in self { @@ -70,7 +70,7 @@ /// } /// private var nextElement: ResultElement? // The next result of next(). /// private var base: Base // The underlying generator. -/// private let combine: (ResultElement, Base.Element)->ResultElement +/// private let combine: (ResultElement, Base.Element) -> ResultElement /// } /// /// struct LazyScanSequence @@ -83,7 +83,7 @@ /// private let initial: ResultElement /// private let base: Base /// private let combine: -/// (ResultElement, Base.Generator.Element)->ResultElement +/// (ResultElement, Base.Generator.Element) -> ResultElement /// } /// /// and finally, we can give all lazy sequences a lazy `scan` method: @@ -101,7 +101,7 @@ /// /// - Complexity: O(1) /// func scan( /// initial: ResultElement, -/// combine: (ResultElement, Generator.Element)->ResultElement +/// combine: (ResultElement, Generator.Element) -> ResultElement /// ) -> LazyScanSequence { /// return LazyScanSequence( /// initial: initial, base: self, combine: combine) @@ -132,7 +132,7 @@ public protocol LazySequenceType : SequenceType { /// possibly with a simpler type. /// /// - See also: `elements` - typealias Elements: SequenceType = Self + associatedtype Elements: SequenceType = Self /// A sequence containing the same elements as this one, possibly with /// a simpler type. @@ -146,9 +146,9 @@ public protocol LazySequenceType : SequenceType { /// Note: this property need not be implemented by conforming types, /// it has a default implementation in a protocol extension that /// just returns `self`. - var elements: Elements {get} + var elements: Elements { get } - var array: [Generator.Element] {get} + var array: [Generator.Element] { get } } extension LazySequenceType { diff --git a/stdlib/public/core/LifetimeManager.swift b/stdlib/public/core/LifetimeManager.swift index 8984029cbed1a..474951729b5e3 100644 --- a/stdlib/public/core/LifetimeManager.swift +++ b/stdlib/public/core/LifetimeManager.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/ManagedBuffer.swift b/stdlib/public/core/ManagedBuffer.swift index da15cf4d2d215..38789e3a021c5 100644 --- a/stdlib/public/core/ManagedBuffer.swift +++ b/stdlib/public/core/ManagedBuffer.swift @@ -1,8 +1,8 @@ -//===--- ManagedBuffer.swift - variable-sized buffer of aligned memory ---===// +//===--- ManagedBuffer.swift - variable-sized buffer of aligned memory ----===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,7 +45,7 @@ public class ManagedProtoBuffer : NonObjectiveCBase { /// - Note: This pointer is only valid for the duration of the /// call to `body`. public final func withUnsafeMutablePointerToValue( - body: (UnsafeMutablePointer)->R + body: (UnsafeMutablePointer) -> R ) -> R { return withUnsafeMutablePointers { (v, e) in return body(v) } } @@ -56,7 +56,7 @@ public class ManagedProtoBuffer : NonObjectiveCBase { /// - Note: This pointer is only valid for the duration of the /// call to `body`. public final func withUnsafeMutablePointerToElements( - body: (UnsafeMutablePointer)->R + body: (UnsafeMutablePointer) -> R ) -> R { return withUnsafeMutablePointers { return body($0.1) } } @@ -67,7 +67,7 @@ public class ManagedProtoBuffer : NonObjectiveCBase { /// - Note: These pointers are only valid for the duration of the /// call to `body`. public final func withUnsafeMutablePointers( - body: (_: UnsafeMutablePointer, _: UnsafeMutablePointer)->R + body: (_: UnsafeMutablePointer, _: UnsafeMutablePointer) -> R ) -> R { return ManagedBufferPointer(self).withUnsafeMutablePointers(body) } @@ -99,7 +99,7 @@ public class ManagedBuffer /// generate an initial `Value`. public final class func create( minimumCapacity: Int, - initialValue: (ManagedProtoBuffer)->Value + initialValue: (ManagedProtoBuffer) -> Value ) -> ManagedBuffer { let p = ManagedBufferPointer( @@ -146,7 +146,7 @@ public class ManagedBuffer /// typealias Manager = ManagedBufferPointer<(Int,String), Element> /// deinit { /// Manager(unsafeBufferObject: self).withUnsafeMutablePointers { -/// (pointerToValue, pointerToElements)->Void in +/// (pointerToValue, pointerToElements) -> Void in /// pointerToElements.destroy(self.count) /// pointerToValue.destroy() /// } @@ -181,7 +181,7 @@ public struct ManagedBufferPointer : Equatable { public init( bufferClass: AnyClass, minimumCapacity: Int, - initialValue: (buffer: AnyObject, allocatedCount: (AnyObject)->Int)->Value + initialValue: (buffer: AnyObject, allocatedCount: (AnyObject) -> Int) -> Value ) { self = ManagedBufferPointer(bufferClass: bufferClass, minimumCapacity: minimumCapacity) @@ -253,7 +253,7 @@ public struct ManagedBufferPointer : Equatable { /// - Note: This pointer is only valid /// for the duration of the call to `body`. public func withUnsafeMutablePointerToValue( - body: (UnsafeMutablePointer)->R + body: (UnsafeMutablePointer) -> R ) -> R { return withUnsafeMutablePointers { (v, e) in return body(v) } } @@ -264,7 +264,7 @@ public struct ManagedBufferPointer : Equatable { /// - Note: This pointer is only valid for the duration of the /// call to `body`. public func withUnsafeMutablePointerToElements( - body: (UnsafeMutablePointer)->R + body: (UnsafeMutablePointer) -> R ) -> R { return withUnsafeMutablePointers { return body($0.1) } } @@ -275,7 +275,7 @@ public struct ManagedBufferPointer : Equatable { /// - Note: These pointers are only valid for the duration of the /// call to `body`. public func withUnsafeMutablePointers( - body: (_: UnsafeMutablePointer, _: UnsafeMutablePointer)->R + body: (_: UnsafeMutablePointer, _: UnsafeMutablePointer) -> R ) -> R { let result = body(_valuePointer, _elementPointer) _fixLifetime(_nativeBuffer) diff --git a/stdlib/public/core/Map.swift b/stdlib/public/core/Map.swift index 0ab8e660ca80c..b525643e9e5b6 100644 --- a/stdlib/public/core/Map.swift +++ b/stdlib/public/core/Map.swift @@ -1,8 +1,8 @@ -//===--- Map.swift - Lazily map over a SequenceType -----------*- swift -*-===// +//===--- Map.swift - Lazily map over a SequenceType -----------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -32,7 +32,7 @@ public struct LazyMapGenerator< public var base: Base { return _base } internal var _base: Base - internal var _transform: (Base.Element)->Element + internal var _transform: (Base.Element) -> Element } /// A `SequenceType` whose elements consist of those in a `Base` @@ -61,13 +61,13 @@ public struct LazyMapSequence /// Create an instance with elements `transform(x)` for each element /// `x` of base. - public init(_ base: Base, transform: (Base.Generator.Element)->Element) { + public init(_ base: Base, transform: (Base.Generator.Element) -> Element) { self._base = base self._transform = transform } public var _base: Base - internal var _transform: (Base.Generator.Element)->Element + internal var _transform: (Base.Generator.Element) -> Element @available(*, unavailable, renamed="Element") public typealias T = Element @@ -123,19 +123,19 @@ public struct LazyMapCollection /// Create an instance with elements `transform(x)` for each element /// `x` of base. - public init(_ base: Base, transform: (Base.Generator.Element)->Element) { + public init(_ base: Base, transform: (Base.Generator.Element) -> Element) { self._base = base self._transform = transform } public var _base: Base - var _transform: (Base.Generator.Element)->Element + var _transform: (Base.Generator.Element) -> Element @available(*, unavailable, renamed="Element") public typealias T = Element } -//===--- Support for s.lazy ----------------------------------------------===// +//===--- Support for s.lazy -----------------------------------------------===// extension LazySequenceType { /// Return a `LazyMapSequence` over this `Sequence`. The elements of diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift index bcc76bf7dde4c..13fccfa476dc5 100644 --- a/stdlib/public/core/Mirror.swift +++ b/stdlib/public/core/Mirror.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -83,7 +83,7 @@ public struct Mirror { /// children: ["someProperty": self.someProperty], /// ancestorRepresentation: .Customized(super.customMirror)) // <== /// } - case Customized(()->Mirror) + case Customized(() -> Mirror) /// Suppress the representation of all ancestor classes. The /// resulting `Mirror`'s `superclassMirror()` is `nil`. @@ -169,7 +169,7 @@ public struct Mirror { @warn_unused_result internal static func _superclassGenerator( subject: T, _ ancestorRepresentation: AncestorRepresentation - ) -> ()->Mirror? { + ) -> () -> Mirror? { if let subject = subject as? AnyObject, let subjectClass = T.self as? AnyClass, @@ -338,7 +338,7 @@ public struct Mirror { return _makeSuperclassMirror() } - internal let _makeSuperclassMirror: ()->Mirror? + internal let _makeSuperclassMirror: () -> Mirror? internal let _defaultDescendantRepresentation: DefaultDescendantRepresentation } @@ -552,7 +552,7 @@ internal extension Mirror { internal init( legacy legacyMirror: _MirrorType, subjectType: Any.Type, - makeSuperclassMirror: (()->Mirror?)? = nil + makeSuperclassMirror: (() -> Mirror?)? = nil ) { if let makeSuperclassMirror = makeSuperclassMirror { self._makeSuperclassMirror = makeSuperclassMirror diff --git a/stdlib/public/core/Mirrors.swift.gyb b/stdlib/public/core/Mirrors.swift.gyb index e846b2bc7efe7..dac2c2f7d1bbb 100644 --- a/stdlib/public/core/Mirrors.swift.gyb +++ b/stdlib/public/core/Mirrors.swift.gyb @@ -1,8 +1,8 @@ -//===--- Mirrors.swift.gyb - Common _MirrorType implementations -*- swift -*-==// +//===--- Mirrors.swift.gyb - Common _MirrorType impls. --------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,26 +12,26 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 Types = [ - ('Float', '.Float', '$0'), - ('Double', '.Double', '$0'), - ('Bool', '.Logical', '$0'), - ('String', '.Text', '$0'), - ('Character', '.Text', 'String($0)'), - ('UnicodeScalar', '.UInt', 'UInt64($0)'), + ('Float', '.Float', 'self'), + ('Double', '.Double', 'self'), + ('Bool', '.Logical', 'self'), + ('String', '.Text', 'self'), + ('Character', '.Text', 'String(self)'), + ('UnicodeScalar', '.UInt', 'UInt64(self)'), ] for self_ty in all_integer_types(word_bits): Self = self_ty.stdlib_name if self_ty.is_signed: - Types.append( (Self, '.Int', 'Int64($0)') ) + Types.append( (Self, '.Int', 'Int64(self)') ) else: - Types.append( (Self, '.UInt', 'UInt64($0)') ) + Types.append( (Self, '.UInt', 'UInt64(self)') ) }% @@ -39,11 +39,18 @@ internal func _toString(x: T) -> String { return String(x) } -% for Type in Types: -extension ${Type[0]} : _Reflectable { +%for Type in Types: + +extension ${Type[0]} : CustomReflectable { /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _LeafMirror(self, _toString, { ${Type[1]}(${Type[2]}) }) + public func customMirror() -> Mirror { + return Mirror(self, unlabeledChildren: [Any]()) + } +} + +extension ${Type[0]} : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return ${Type[1]}(${Type[2]}) } } % end diff --git a/stdlib/public/core/Misc.swift b/stdlib/public/core/Misc.swift index 6a2eb92828522..c96d9d92a0a0e 100644 --- a/stdlib/public/core/Misc.swift +++ b/stdlib/public/core/Misc.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -83,6 +83,42 @@ func _typeName(type: Any.Type, qualified: Bool = true) -> String { input: UnsafeBufferPointer(start: stringPtr, count: count)) } +@_silgen_name("swift_getTypeByMangledName") +func _getTypeByMangledName( + name: UnsafePointer, + _ nameLength: UInt) + -> Any.Type? + +/// Lookup a class given a name. Until the demangled encoding of type +/// names is stabilized, this is limited to top-level class names (Foo.bar). +@warn_unused_result +public // SPI(Foundation) +func _typeByName(name: String) -> Any.Type? { + let components = name.characters.split{$0 == "."}.map(String.init) + guard components.count == 2 else { + return nil + } + + // Note: explicitly build a class name to match on, rather than matching + // on the result of _typeName(), to ensure the type we are resolving is + // actually a class. + var name = "C" + if components[0] == "Swift" { + name += "Ss" + } else { + name += String(components[0].characters.count) + components[0] + } + name += String(components[1].characters.count) + components[1] + + let nameUTF8 = Array(name.utf8) + return nameUTF8.withUnsafeBufferPointer { (nameUTF8) in + let type = _getTypeByMangledName(nameUTF8.baseAddress, + UInt(nameUTF8.endIndex)) + + return type + } +} + @warn_unused_result @_silgen_name("swift_stdlib_demangleName") func _stdlib_demangleNameImpl( @@ -124,7 +160,7 @@ func _stdlib_demangleName(mangledName: String) -> String { public // @testable func _floorLog2(x: Int64) -> Int { _sanityCheck(x > 0, "_floorLog2 operates only on non-negative integers") - // Note: use unchecked subtraction because we this expression can not + // Note: use unchecked subtraction because we this expression cannot // overflow. return 63 &- Int(_countLeadingZeros(x)) } diff --git a/stdlib/public/core/ObjCMirrors.swift b/stdlib/public/core/ObjCMirrors.swift index 40609b5587af5..ffb1525de07f3 100644 --- a/stdlib/public/core/ObjCMirrors.swift +++ b/stdlib/public/core/ObjCMirrors.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/OptionSet.swift b/stdlib/public/core/OptionSet.swift index 1498921a6ad4a..5ba7904508fa5 100644 --- a/stdlib/public/core/OptionSet.swift +++ b/stdlib/public/core/OptionSet.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -34,7 +34,7 @@ public protocol OptionSetType : SetAlgebraType, RawRepresentable { // constrained extension /// An `OptionSet`'s `Element` type is normally `Self`. - typealias Element = Self + associatedtype Element = Self // FIXME: This initializer should just be the failable init from // RawRepresentable. Unfortunately, current language limitations diff --git a/stdlib/public/core/Optional.swift b/stdlib/public/core/Optional.swift index 1fa1ac8557726..301179a37a527 100644 --- a/stdlib/public/core/Optional.swift +++ b/stdlib/public/core/Optional.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ // The compiler has special knowledge of Optional, including the fact // that it is an enum with cases named 'None' and 'Some'. -public enum Optional : _Reflectable, NilLiteralConvertible { +public enum Optional : NilLiteralConvertible { case None case Some(Wrapped) @@ -49,12 +49,6 @@ public enum Optional : _Reflectable, NilLiteralConvertible { } } - /// Returns a mirror that reflects `self`. - @warn_unused_result - public func _getMirror() -> _MirrorType { - return _OptionalMirror(self) - } - /// Create an instance initialized with `nil`. @_transparent public init(nilLiteral: ()) { @@ -86,14 +80,14 @@ extension Optional : CustomDebugStringConvertible { // /// Haskell's fmap for Optionals. @available(*, unavailable, message="call the 'map()' method on the optional value") -public func map(x: T?, @noescape _ f: (T)->U) -> U? { +public func map(x: T?, @noescape _ f: (T) -> U) -> U? { fatalError("unavailable function can't be called") } /// Returns `f(self)!` iff `self` and `f(self)` are not `nil`. @available(*, unavailable, message="call the 'flatMap()' method on the optional value") -public func flatMap(x: T?, @noescape _ f: (T)->U?) -> U? { +public func flatMap(x: T?, @noescape _ f: (T) -> U?) -> U? { fatalError("unavailable function can't be called") } @@ -214,41 +208,6 @@ public func != (lhs: _OptionalNilComparisonType, rhs: T?) -> Bool { } } -internal struct _OptionalMirror : _MirrorType { - let _value : Optional - - init(_ x : Optional) { - _value = x - } - - var value: Any { return _value } - - var valueType: Any.Type { return (_value as Any).dynamicType } - - var objectIdentifier: ObjectIdentifier? { return .None } - - var count: Int { return (_value != nil) ? 1 : 0 } - - subscript(i: Int) -> (String, _MirrorType) { - switch (_value, i) { - case (.Some(let contents), 0) : return ("Some", _reflect(contents)) - default: _preconditionFailure("cannot extract this child index") - } - } - - var summary: String { - switch _value { - case let contents?: return _reflect(contents).summary - default: return "nil" - } - } - - var quickLookObject: PlaygroundQuickLook? { return .None } - - var disposition: _MirrorDisposition { return .Optional } -} - - @warn_unused_result public func < (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { diff --git a/stdlib/public/core/OutputStream.swift b/stdlib/public/core/OutputStream.swift index 4043eeb105c2a..5a4a48138a208 100644 --- a/stdlib/public/core/OutputStream.swift +++ b/stdlib/public/core/OutputStream.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -82,81 +82,93 @@ public protocol CustomDebugStringConvertible { // Default (ad-hoc) printing //===----------------------------------------------------------------------===// +@_silgen_name("swift_EnumCaseName") +func _getEnumCaseName(value: T) -> UnsafePointer + +@_silgen_name("swift_OpaqueSummary") +func _opaqueSummary(metadata: Any.Type) -> UnsafePointer + /// Do our best to print a value that cannot be printed directly. internal func _adHocPrint( - value: T, inout _ target: TargetStream, isDebugPrint: Bool + value: T, _ mirror: Mirror, inout _ target: TargetStream, + isDebugPrint: Bool ) { func printTypeName(type: Any.Type) { // Print type names without qualification, unless we're debugPrint'ing. target.write(_typeName(type, qualified: isDebugPrint)) } - let mirror = _reflect(value) - switch mirror { - // Checking the mirror kind is not a good way to implement this, but we don't - // have a more expressive reflection API now. - case is _TupleMirror: - target.write("(") - var first = true - for i in 0..( return } - _adHocPrint(value, &target, isDebugPrint: false) + let mirror = Mirror(reflecting: value) + _adHocPrint(value, mirror, &target, isDebugPrint: false) } /// Returns the result of `print`'ing `x` into a `String`. @@ -235,7 +248,72 @@ public func _debugPrint_unlocked( return } - _adHocPrint(value, &target, isDebugPrint: true) + let mirror = Mirror(reflecting: value) + _adHocPrint(value, mirror, &target, isDebugPrint: true) +} + +internal func _dumpPrint( + value: T, _ mirror: Mirror, inout _ target: TargetStream +) { + if let displayStyle = mirror.displayStyle { + // Containers and tuples are always displayed in terms of their element count + switch displayStyle { + case .Tuple: + let count = mirror.children.count + target.write(count == 1 ? "(1 element)" : "(\(count) elements)") + return + case .Collection: + let count = mirror.children.count + target.write(count == 1 ? "1 element" : "\(count) elements") + return + case .Dictionary: + let count = mirror.children.count + target.write(count == 1 ? "1 key/value pair" : "\(count) key/value pairs") + return + case .Set: + let count = mirror.children.count + target.write(count == 1 ? "1 member" : "\(count) members") + return + default: + break + } + } + + if let debugPrintableObject = value as? CustomDebugStringConvertible { + debugPrintableObject.debugDescription.writeTo(&target) + return + } + + if let printableObject = value as? CustomStringConvertible { + printableObject.description.writeTo(&target) + return + } + + if let streamableObject = value as? Streamable { + streamableObject.writeTo(&target) + return + } + + if let displayStyle = mirror.displayStyle { + switch displayStyle { + case .Class, .Struct: + // Classes and structs without custom representations are displayed as + // their fully qualified type name + target.write(_typeName(mirror.subjectType, qualified: true)) + return + case .Enum: + target.write(_typeName(mirror.subjectType, qualified: true)) + if let caseName = String.fromCString(_getEnumCaseName(value)) { + target.write(".") + target.write(caseName) + } + return + default: + break + } + } + + _adHocPrint(value, mirror, &target, isDebugPrint: true) } //===----------------------------------------------------------------------===// @@ -343,7 +421,7 @@ public func toDebugString(x: T) -> String { } /// A hook for playgrounds to print through. -public var _playgroundPrintHook : ((String)->Void)? = {_ in () } +public var _playgroundPrintHook : ((String) -> Void)? = {_ in () } internal struct _TeeStream< L : OutputStreamType, diff --git a/stdlib/public/core/Pointer.swift b/stdlib/public/core/Pointer.swift index ac10075644e27..96eddcc18b254 100644 --- a/stdlib/public/core/Pointer.swift +++ b/stdlib/public/core/Pointer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift index b0f73d19dbcfb..e4cf45b9edff0 100644 --- a/stdlib/public/core/Policy.swift +++ b/stdlib/public/core/Policy.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -85,10 +85,10 @@ public typealias Any = protocol<> /// @objc func getCValue() -> Int { return 42 } /// } /// -/// // If x has a method @objc getValue()->Int, call it and +/// // If x has a method @objc getValue() -> Int, call it and /// // return the result. Otherwise, return `nil`. /// func getCValue1(x: AnyObject) -> Int? { -/// if let f: ()->Int = x.getCValue { // <=== +/// if let f: () -> Int = x.getCValue { // <=== /// return f() /// } /// return nil @@ -142,6 +142,10 @@ public protocol AnyObject : class {} /// - SeeAlso: `AnyObject` public typealias AnyClass = AnyObject.Type +/// Returns true iff `lhs` and `rhs` are references to the same object +/// instance (in other words, are identical pointers). +/// +/// - SeeAlso: `Equatable`, `==` @warn_unused_result public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool { switch (lhs, rhs) { @@ -327,7 +331,7 @@ public protocol Hashable : Equatable { } public protocol _SinkType {} -@available(*, unavailable, message="SinkType has been removed. Use (T)->() closures directly instead.") +@available(*, unavailable, message="SinkType has been removed. Use (T) -> () closures directly instead.") public typealias SinkType = _SinkType //===----------------------------------------------------------------------===// @@ -447,4 +451,3 @@ infix operator |= { associativity right precedence 90 assignment } // example of how this operator is used, and how its use can be hidden // from users. infix operator ~> { associativity left precedence 255 } - diff --git a/stdlib/public/core/Prespecialized.swift b/stdlib/public/core/Prespecialized.swift index 41772a059707d..f258d07bc9d2d 100644 --- a/stdlib/public/core/Prespecialized.swift +++ b/stdlib/public/core/Prespecialized.swift @@ -2,14 +2,14 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// -// Pre-specializaiton of some popular generic classes and functions. +// Pre-specialization of some popular generic classes and functions. //===----------------------------------------------------------------------===// struct _Prespecialize { @@ -29,8 +29,8 @@ struct _Prespecialize { a[0] = a[j] } - for var i1 = 0; i1 < a.count; ++i1 { - for var i2 = 0; i2 < a.count; ++i2 { + for i1 in 0.. Mirror { + return Mirror(self, children: ["startIndex": startIndex, "endIndex": endIndex]) + } +} + +/// O(1) implementation of `contains()` for ranges of comparable elements. +extension Range where Element: Comparable { + @warn_unused_result + func _customContainsEquatableElement(element: Generator.Element) -> Bool? { + return element >= self.startIndex && element < self.endIndex + } + + // FIXME: copied from SequenceAlgorithms as a workaround for https://bugs.swift.org/browse/SR-435 + @warn_unused_result + public func contains(element: Generator.Element) -> Bool { + if let result = _customContainsEquatableElement(element) { + return result + } + + for e in self { + if e == element { + return true + } + } + return false + } +} + @warn_unused_result public func == (lhs: Range, rhs: Range) -> Bool { return lhs.startIndex == rhs.startIndex && @@ -201,8 +230,6 @@ public func ... ( public func ~= ( pattern: Range, value: I ) -> Bool { - // Intervals can check for containment in O(1). - return - HalfOpenInterval(pattern.startIndex, pattern.endIndex).contains(value) + return pattern.contains(value) } diff --git a/stdlib/public/core/RangeMirrors.swift.gyb b/stdlib/public/core/RangeMirrors.swift.gyb deleted file mode 100644 index 69197c94ca608..0000000000000 --- a/stdlib/public/core/RangeMirrors.swift.gyb +++ /dev/null @@ -1,45 +0,0 @@ -//===- RangeMirrors.swift.gyb ---------------------------------*- swift -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -% import gyb -% -% common_args = dict( -% introspecteeType='Range', -% genericArgs=['T'], -% genericConstraints={'T':'ForwardIndexType'}, -% disposition='Struct') -% -% for x in ('Decl', 'Conformance', 'Boilerplate'): -% locals()['Mirror' + x] = gyb.executeTemplate( -% gyb.parseTemplate('../common/Mirror%s.gyb' % x), **common_args) -% end - -${MirrorDecl} { - ${MirrorBoilerplate} - var count: Int { return 2 } - - subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: return ("startIndex",_reflect(_value.startIndex)) - case 1: return ("endIndex",_reflect(_value.endIndex)) - default: _preconditionFailure("cannot extract this child index") - } - } - - var summary: String { - return "\(self[0].1.summary)..<\(self[1].1.summary)" - } - - var quickLookObject: PlaygroundQuickLook? { return nil } -} - -${MirrorConformance} diff --git a/stdlib/public/core/RangeReplaceableCollectionType.swift b/stdlib/public/core/RangeReplaceableCollectionType.swift index 9017e8a895bae..565db3fea2af8 100644 --- a/stdlib/public/core/RangeReplaceableCollectionType.swift +++ b/stdlib/public/core/RangeReplaceableCollectionType.swift @@ -1,8 +1,8 @@ -//===--- RangeReplaceableCollectionType.swift -----------------*- swift -*-===// +//===--- RangeReplaceableCollectionType.swift -----------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -448,6 +448,7 @@ public func +< >(lhs: C, rhs: S) -> C { var lhs = lhs // FIXME: what if lhs is a reference type? This will mutate it. + lhs.reserveCapacity(lhs.count + numericCast(rhs.underestimateCount())) lhs.appendContentsOf(rhs) return lhs } @@ -459,25 +460,12 @@ public func +< where S.Generator.Element == C.Generator.Element >(lhs: S, rhs: C) -> C { var result = C() - result.reserveCapacity(rhs.count + numericCast(rhs.underestimateCount())) + result.reserveCapacity(rhs.count + numericCast(lhs.underestimateCount())) result.appendContentsOf(lhs) result.appendContentsOf(rhs) return result } -@warn_unused_result -public func +< - C : RangeReplaceableCollectionType, - S : CollectionType - where S.Generator.Element == C.Generator.Element ->(lhs: C, rhs: S) -> C { - var lhs = lhs - // FIXME: what if lhs is a reference type? This will mutate it. - lhs.reserveCapacity(lhs.count + numericCast(rhs.count)) - lhs.appendContentsOf(rhs) - return lhs -} - @warn_unused_result public func +< RRC1 : RangeReplaceableCollectionType, diff --git a/stdlib/public/core/Reflection.swift b/stdlib/public/core/Reflection.swift index 1d3ffb982acd6..452065aeefea5 100644 --- a/stdlib/public/core/Reflection.swift +++ b/stdlib/public/core/Reflection.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -133,7 +133,7 @@ public protocol _MirrorType { @_silgen_name("swift_getSummary") public // COMPILER_INTRINSIC func _getSummary(out: UnsafeMutablePointer, x: T) { - out.initialize(_reflect(x).summary) + out.initialize(String(reflecting: x)) } /// Produce a mirror for any value. If the value's type conforms to @@ -152,8 +152,8 @@ public func dump( ) -> T { var maxItemCounter = maxItems var visitedItems = [ObjectIdentifier : Int]() - _dumpWithMirror( - _reflect(x), name, indent, maxDepth, &maxItemCounter, &visitedItems, + _dumpObject( + x, name, indent, maxDepth, &maxItemCounter, &visitedItems, &targetStream) return x } @@ -167,19 +167,20 @@ public func dump(x: T, name: String? = nil, indent: Int = 0, maxItems: maxItems) } -/// Dump an object's contents using a mirror. User code should use dump(). -func _dumpWithMirror( - mirror: _MirrorType, _ name: String?, _ indent: Int, _ maxDepth: Int, +/// Dump an object's contents. User code should use dump(). +internal func _dumpObject( + object: Any, _ name: String?, _ indent: Int, _ maxDepth: Int, inout _ maxItemCounter: Int, inout _ visitedItems: [ObjectIdentifier : Int], inout _ targetStream: TargetStream ) { - if maxItemCounter <= 0 { return } + guard maxItemCounter > 0 else { return } maxItemCounter -= 1 for _ in 0..( if let nam = name { print("\(nam): ", terminator: "", toStream: &targetStream) } - print(mirror.summary, terminator: "", toStream: &targetStream) - - if let id = mirror.objectIdentifier { - if let previous = visitedItems[id] { + // This takes the place of the old mirror API's 'summary' property + _dumpPrint(object, mirror, &targetStream) + + let id: ObjectIdentifier? + if let classInstance = object as? AnyObject where object.dynamicType is AnyObject.Type { + // Object is a class (but not an ObjC-bridged struct) + id = ObjectIdentifier(classInstance) + } else if let metatypeInstance = object as? Any.Type { + // Object is a metatype + id = ObjectIdentifier(metatypeInstance) + } else { + id = nil + } + if let theId = id { + if let previous = visitedItems[theId] { print(" #\(previous)", toStream: &targetStream) return } let identifier = visitedItems.count - visitedItems[id] = identifier + visitedItems[theId] = identifier print(" #\(identifier)", terminator: "", toStream: &targetStream) } print("", toStream: &targetStream) - if maxDepth <= 0 { return } + guard maxDepth > 0 else { return } + + if let superclassMirror = mirror.superclassMirror() { + _dumpSuperclass(superclassMirror, indent + 2, maxDepth - 1, &maxItemCounter, &visitedItems, &targetStream) + } + var currentIndex = mirror.children.startIndex for i in 0..( return } - let (name, child) = mirror[i] - _dumpWithMirror(child, name, indent + 2, maxDepth - 1, + let (name, child) = mirror.children[currentIndex] + currentIndex = currentIndex.successor() + _dumpObject(child, name, indent + 2, maxDepth - 1, &maxItemCounter, &visitedItems, &targetStream) } } -// -- _MirrorType implementations for basic data types +/// Dump information about an object's superclass, given a mirror reflecting +/// that superclass. +internal func _dumpSuperclass( + mirror: Mirror, _ indent: Int, _ maxDepth: Int, + inout _ maxItemCounter: Int, + inout _ visitedItems: [ObjectIdentifier : Int], + inout _ targetStream: TargetStream +) { + guard maxItemCounter > 0 else { return } + maxItemCounter -= 1 + + for _ in 0..: _MirrorType { - let _value: T - let summaryFunction: T -> String - let quickLookFunction: T -> PlaygroundQuickLook? + guard maxDepth > 0 else { return } - init(_ value: T, _ summaryFunction: T -> String, - _ quickLookFunction: T -> PlaygroundQuickLook?) { - self._value = value - self.summaryFunction = summaryFunction - self.quickLookFunction = quickLookFunction + if let superclassMirror = mirror.superclassMirror() { + _dumpSuperclass(superclassMirror, indent + 2, maxDepth - 1, + &maxItemCounter, &visitedItems, &targetStream) } - var value: Any { return _value } - var valueType: Any.Type { return value.dynamicType } - var objectIdentifier: ObjectIdentifier? { return nil } - var count: Int { return 0 } - subscript(i: Int) -> (String, _MirrorType) { - _preconditionFailure("no children") + var currentIndex = mirror.children.startIndex + for i in 0.. 0 { print(" more", terminator: "", toStream: &targetStream) } + if remainder == 1 { + print(" child)", toStream: &targetStream) + } else { + print(" children)", toStream: &targetStream) + } + return + } + + let (name, child) = mirror.children[currentIndex] + currentIndex = currentIndex.successor() + _dumpObject(child, name, indent + 2, maxDepth - 1, + &maxItemCounter, &visitedItems, &targetStream) } - var summary: String { return summaryFunction(_value) } - var quickLookObject: PlaygroundQuickLook? { return quickLookFunction(_value) } - var disposition: _MirrorDisposition { return .Aggregate } } // -- Implementation details for the runtime's _MirrorType implementation diff --git a/stdlib/public/core/Repeat.swift b/stdlib/public/core/Repeat.swift index a05ac9beb77f2..1eee24b3531fc 100644 --- a/stdlib/public/core/Repeat.swift +++ b/stdlib/public/core/Repeat.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Reverse.swift b/stdlib/public/core/Reverse.swift index cf24fb34847d6..fe08bebe34c3a 100644 --- a/stdlib/public/core/Reverse.swift +++ b/stdlib/public/core/Reverse.swift @@ -1,8 +1,8 @@ -//===--- Reverse.swift - Lazy sequence reversal ---------------*- swift -*-===// +//===--- Reverse.swift - Lazy sequence reversal ---------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,11 +11,11 @@ //===----------------------------------------------------------------------===// public protocol ReverseIndexType : BidirectionalIndexType { - typealias Base : BidirectionalIndexType + associatedtype Base : BidirectionalIndexType /// A type that can represent the number of steps between pairs of /// `ReverseIndex` values where one value is reachable from the other. - typealias Distance: _SignedIntegerType = Base.Distance + associatedtype Distance: _SignedIntegerType = Base.Distance /// The successor position in the underlying (un-reversed) /// collection. @@ -104,9 +104,9 @@ public struct ReverseRandomAccessIndex } public protocol _ReverseCollectionType : CollectionType { - typealias Index : ReverseIndexType - typealias Base : CollectionType - var _base: Base {get} + associatedtype Index : ReverseIndexType + associatedtype Base : CollectionType + var _base: Base { get } } extension CollectionType diff --git a/stdlib/public/core/Runtime.swift.gyb b/stdlib/public/core/Runtime.swift.gyb index ebfb629db3a4b..a915f8e529f95 100644 --- a/stdlib/public/core/Runtime.swift.gyb +++ b/stdlib/public/core/Runtime.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -51,7 +51,7 @@ func _stdlib_atomicCompareExchangeStrongPtrImpl( /// you need to manually make sure that: /// /// - all properties in the chain are physical (to make sure that no writeback -/// happens; the compare-and-exchange instruction should operate on on the +/// happens; the compare-and-exchange instruction should operate on the /// shared memory); and /// /// - the shared memory that you are accessing is located inside a heap @@ -194,7 +194,7 @@ func _stdlib_atomicCompareExchangeStrongInt( object: UnsafeMutablePointer(target), expected: UnsafeMutablePointer(expected), desired: UInt32(bitPattern: Int32(desired))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return _stdlib_atomicCompareExchangeStrongUInt64( object: UnsafeMutablePointer(target), expected: UnsafeMutablePointer(expected), @@ -209,7 +209,7 @@ func _swift_stdlib_atomicStoreInt( return _swift_stdlib_atomicStoreUInt32( object: UnsafeMutablePointer(target), desired: UInt32(bitPattern: Int32(desired))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return _swift_stdlib_atomicStoreUInt64( object: UnsafeMutablePointer(target), desired: UInt64(bitPattern: Int64(desired))) @@ -224,7 +224,7 @@ public func _swift_stdlib_atomicLoadInt( return Int(Int32(bitPattern: _swift_stdlib_atomicLoadUInt32( object: UnsafeMutablePointer(target)))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return Int(Int64(bitPattern: _swift_stdlib_atomicLoadUInt64( object: UnsafeMutablePointer(target)))) @@ -265,7 +265,7 @@ public func _swift_stdlib_atomicFetch${operation}Int( _swift_stdlib_atomicFetch${operation}UInt32( object: UnsafeMutablePointer(target), operand: UInt32(bitPattern: Int32(operand))))) -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) return Int(Int64(bitPattern: _swift_stdlib_atomicFetch${operation}UInt64( object: UnsafeMutablePointer(target), @@ -503,7 +503,7 @@ class _SwiftNativeNSEnumerator {} // Use 'dynamic' to prevent this call to be duplicated into other modules. @objc dynamic func initializeReturnAutoreleased() { - // On x86_64 it is sufficient to perform one cycle of return-autorelesed + // On x86_64 it is sufficient to perform one cycle of return-autoreleased // call sequence in order to initialize all required PLT entries. self.returnsAutoreleased(self) } diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift index 6e8ee13b53b87..ff17584679f91 100644 --- a/stdlib/public/core/Sequence.swift +++ b/stdlib/public/core/Sequence.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -24,7 +24,7 @@ /// *sequence's* `generate()` method, rather than by copying. public protocol GeneratorType { /// The type of element generated by `self`. - typealias Element + associatedtype Element /// Advance to the next element and return it, or `nil` if no next /// element exists. @@ -65,14 +65,14 @@ public protocol GeneratorType { public protocol SequenceType { /// A type that provides the *sequence*'s iteration interface and /// encapsulates its iteration state. - typealias Generator : GeneratorType + associatedtype Generator : GeneratorType // FIXME: should be constrained to SequenceType // ( Implement recursive protocol // constraints) /// A type that represents a subsequence of some of the elements. - typealias SubSequence + associatedtype SubSequence /// Return a *generator* over the elements of this *sequence*. /// @@ -189,7 +189,7 @@ public protocol SequenceType { /// If `self` is multi-pass (i.e., a `CollectionType`), invoke /// `preprocess` on `self` and return its result. Otherwise, return /// `nil`. - func _preprocessingPass(preprocess: (Self)->R) -> R? + func _preprocessingPass(@noescape preprocess: (Self) -> R) -> R? /// Create a native array buffer containing the elements of `self`, /// in the same order. @@ -244,6 +244,16 @@ internal class _DropFirstSequence } return generator.next() } + + internal func dropFirst(n: Int) -> AnySequence { + // If this is already a _DropFirstSequence, we need to fold in + // the current drop count and drop limit so no data is lost. + // + // i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to + // [1,2,3,4].dropFirst(2). + return AnySequence( + _DropFirstSequence(generator, limit: limit + n, dropped: dropped)) + } } /// A sequence that only consumes up to `n` elements from an underlying @@ -253,7 +263,8 @@ internal class _DropFirstSequence /// /// This is a class - we require reference semantics to keep track /// of how many elements we've already taken from the underlying sequence. -internal class _PrefixSequence : SequenceType, GeneratorType { +internal class _PrefixSequence + : SequenceType, GeneratorType { internal let maxLength: Int internal var generator: Base internal var taken: Int @@ -279,6 +290,12 @@ internal class _PrefixSequence : SequenceType, GeneratorTy taken = maxLength return nil } + + internal func prefix(maxLength: Int) -> AnySequence { + return AnySequence( + _PrefixSequence(generator, + maxLength: min(maxLength, self.maxLength), taken: taken)) + } } //===----------------------------------------------------------------------===// @@ -331,83 +348,6 @@ extension SequenceType { return Array(result) } - /// Returns a subsequence containing all but the first `n` elements. - /// - /// - Requires: `n >= 0` - /// - Complexity: O(`n`) - @warn_unused_result - public func dropFirst(n: Int) -> AnySequence { - _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") - if n == 0 { return AnySequence(self) } - // If this is already a _DropFirstSequence, we need to fold in - // the current drop count and drop limit so no data is lost. - // - // i.e. [1,2,3,4].dropFirst(1).dropFirst(1) should be equivalent to - // [1,2,3,4].dropFirst(2). - // FIXME: Use method dispatch to fold - // _PrefixSequence and _DropFirstSequence counts - if let any = self as? AnySequence, - let box = any._box as? _SequenceBox<_DropFirstSequence> { - let base = box._base - let folded = _DropFirstSequence(base.generator, limit: base.limit + n, - dropped: base.dropped) - return AnySequence(folded) - } - - return AnySequence(_DropFirstSequence(generate(), limit: n)) - } - - /// Returns a subsequence containing all but the last `n` elements. - /// - /// - Requires: `self` is a finite collection. - /// - Requires: `n >= 0` - /// - Complexity: O(`self.count`) - @warn_unused_result - public func dropLast(n: Int) -> AnySequence { - _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") - if n == 0 { return AnySequence(self) } - // FIXME: Create reusable RingBuffer - // Put incoming elements from this sequence in a holding tank, a ring buffer - // of size <= n. If more elements keep coming in, pull them out of the - // holding tank into the result, an `Array`. This saves - // `n` * sizeof(Generator.Element) of memory, because slices keep the entire - // memory of an `Array` alive. - var result: [Generator.Element] = [] - var ringBuffer: [Generator.Element] = [] - var i = ringBuffer.startIndex - - for element in self { - if ringBuffer.count < n { - ringBuffer.append(element) - } else { - result.append(ringBuffer[i]) - ringBuffer[i] = element - i = i.successor() % n - } - } - return AnySequence(result) - } - - @warn_unused_result - public func prefix(maxLength: Int) -> AnySequence { - _precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence") - if maxLength == 0 { - return AnySequence(EmptyCollection()) - } - // FIXME: Use method dispatch to fold - // _PrefixSequence and _DropFirstSequence counts - if let any = self as? AnySequence, - let box = any._box as? _SequenceBox<_PrefixSequence> { - let base = box._base - let folded = _PrefixSequence( - base.generator, - maxLength: min(base.maxLength, maxLength), - taken: base.taken) - return AnySequence(folded) - } - return AnySequence(_PrefixSequence(generate(), maxLength: maxLength)) - } - @warn_unused_result public func suffix(maxLength: Int) -> AnySequence { _precondition(maxLength >= 0, "Can't take a suffix of negative length from a sequence") @@ -516,7 +456,7 @@ extension SequenceType { return 0 } - public func _preprocessingPass(preprocess: (Self)->R) -> R? { + public func _preprocessingPass(@noescape preprocess: (Self) -> R) -> R? { return nil } @@ -526,9 +466,7 @@ extension SequenceType { ) -> Bool? { return nil } -} -extension SequenceType { /// Call `body` on each element in `self` in the same order as a /// *for-in loop.* /// @@ -585,6 +523,64 @@ extension SequenceType where Generator.Element : Equatable { } } +extension SequenceType where + SubSequence : SequenceType, + SubSequence.Generator.Element == Generator.Element, + SubSequence.SubSequence == SubSequence { + + /// Returns a subsequence containing all but the first `n` elements. + /// + /// - Requires: `n >= 0` + /// - Complexity: O(`n`) + @warn_unused_result + public func dropFirst(n: Int) -> AnySequence { + _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") + if n == 0 { return AnySequence(self) } + return AnySequence(_DropFirstSequence(generate(), limit: n)) + } + + /// Returns a subsequence containing all but the last `n` elements. + /// + /// - Requires: `self` is a finite collection. + /// - Requires: `n >= 0` + /// - Complexity: O(`self.count`) + @warn_unused_result + public func dropLast(n: Int) -> AnySequence { + _precondition(n >= 0, "Can't drop a negative number of elements from a sequence") + if n == 0 { return AnySequence(self) } + + // FIXME: Create reusable RingBuffer + // Put incoming elements from this sequence in a holding tank, a ring buffer + // of size <= n. If more elements keep coming in, pull them out of the + // holding tank into the result, an `Array`. This saves + // `n` * sizeof(Generator.Element) of memory, because slices keep the entire + // memory of an `Array` alive. + var result: [Generator.Element] = [] + var ringBuffer: [Generator.Element] = [] + var i = ringBuffer.startIndex + + for element in self { + if ringBuffer.count < n { + ringBuffer.append(element) + } else { + result.append(ringBuffer[i]) + ringBuffer[i] = element + i = i.successor() % n + } + } + return AnySequence(result) + } + + @warn_unused_result + public func prefix(maxLength: Int) -> AnySequence { + _precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence") + if maxLength == 0 { + return AnySequence(EmptyCollection()) + } + return AnySequence(_PrefixSequence(generate(), maxLength: maxLength)) + } +} + extension SequenceType { /// Returns a subsequence containing all but the first element. /// diff --git a/stdlib/public/core/SequenceAlgorithms.swift.gyb b/stdlib/public/core/SequenceAlgorithms.swift.gyb index c1647a791d1c5..7bada844fda19 100644 --- a/stdlib/public/core/SequenceAlgorithms.swift.gyb +++ b/stdlib/public/core/SequenceAlgorithms.swift.gyb @@ -1,8 +1,8 @@ -//===--- SequenceAlgorithms.swift.gyb -------------------------------------===// +//===--- SequenceAlgorithms.swift.gyb -------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -53,7 +53,7 @@ extension SequenceType { if preds: orderingRequirement = """ /// - Requires: `isOrderedBefore` is a - /// [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings). + /// [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings) /// over `self`.""" rethrows_ = "rethrows " else: diff --git a/stdlib/public/core/SequenceWrapper.swift b/stdlib/public/core/SequenceWrapper.swift index 971d8e8992905..37e58f0c49c5a 100644 --- a/stdlib/public/core/SequenceWrapper.swift +++ b/stdlib/public/core/SequenceWrapper.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -10,19 +10,18 @@ // //===----------------------------------------------------------------------===// // -// To create a SequenceType or CollectionType that forwards -// requirements to an underlying SequenceType or CollectionType, -// have it conform to one of these protocols. +// To create a SequenceType that forwards requirements to an +// underlying SequenceType, have it conform to this protocol. // //===----------------------------------------------------------------------===// /// A type that is just a wrapper over some base Sequence public // @testable protocol _SequenceWrapperType { - typealias Base : SequenceType - typealias Generator : GeneratorType = Base.Generator + associatedtype Base : SequenceType + associatedtype Generator : GeneratorType = Base.Generator - var _base: Base {get} + var _base: Base { get } } extension SequenceType @@ -61,7 +60,7 @@ extension SequenceType /// If `self` is multi-pass (i.e., a `CollectionType`), invoke /// `preprocess` on `self` and return its result. Otherwise, return /// `nil`. - public func _preprocessingPass(preprocess: (Self)->R) -> R? { + public func _preprocessingPass(@noescape preprocess: (Self) -> R) -> R? { return _base._preprocessingPass { _ in preprocess(self) } } @@ -79,78 +78,3 @@ extension SequenceType return _base._initializeTo(ptr) } } - -public // @testable -protocol _CollectionWrapperType : _SequenceWrapperType { - typealias Base : CollectionType - typealias Index : ForwardIndexType = Base.Index - var _base: Base {get} -} - -extension CollectionType - where Self : _CollectionWrapperType, Self.Index == Self.Base.Index { - /// The position of the first element in a non-empty collection. - /// - /// In an empty collection, `startIndex == endIndex`. - public var startIndex: Base.Index { - return _base.startIndex - } - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: Base.Index { - return _base.endIndex - } - - /// Access the element at `position`. - /// - /// - Requires: `position` is a valid position in `self` and - /// `position != endIndex`. - public subscript(position: Base.Index) -> Base.Generator.Element { - return _base[position] - } - - //===--- Restatements From SequenceWrapperType break ambiguity ----------===// - @warn_unused_result - public func map( - @noescape transform: (Base.Generator.Element) -> T - ) -> [T] { - return _base.map(transform) - } - - @warn_unused_result - public func filter( - @noescape includeElement: (Base.Generator.Element) -> Bool - ) -> [Base.Generator.Element] { - return _base.filter(includeElement) - } - - public func _customContainsEquatableElement( - element: Base.Generator.Element - ) -> Bool? { - return _base._customContainsEquatableElement(element) - } - - /// If `self` is multi-pass (i.e., a `CollectionType`), invoke - /// `preprocess` on `self` and return its result. Otherwise, return - /// `nil`. - public func _preprocessingPass(preprocess: (Self)->R) -> R? { - return _base._preprocessingPass { _ in preprocess(self) } - } - - /// Create a native array buffer containing the elements of `self`, - /// in the same order. - public func _copyToNativeArrayBuffer() - -> _ContiguousArrayBuffer { - return _base._copyToNativeArrayBuffer() - } - - /// Copy a Sequence into an array. - public func _initializeTo(ptr: UnsafeMutablePointer) - -> UnsafeMutablePointer { - return _base._initializeTo(ptr) - } -} diff --git a/stdlib/public/core/SetAlgebra.swift b/stdlib/public/core/SetAlgebra.swift index 372c71e830c37..70d75cbbc86ae 100644 --- a/stdlib/public/core/SetAlgebra.swift +++ b/stdlib/public/core/SetAlgebra.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,7 @@ /// /// > `a` **subsumes** `b` iff `([a] as Self).isSupersetOf([b])` /// -/// In many models of `SetAlgebraType` such as `Set`, `a` +/// In many models of `SetAlgebraType` such as `Set`, `a` /// *subsumes* `b` if and only if `a == b`, but that is not always the /// case. For example, option sets typically do not satisfy that /// property. @@ -47,7 +47,7 @@ /// - `x.isStrictSubsetOf(y)` iff `x.isSubsetOf(y) && x != y` public protocol SetAlgebraType : Equatable, ArrayLiteralConvertible { /// A type for which `Self` provides a containment test. - typealias Element + associatedtype Element /// Creates an empty set. /// diff --git a/stdlib/public/core/ShadowProtocols.swift b/stdlib/public/core/ShadowProtocols.swift index d881c77e813e8..a6055267af0a3 100644 --- a/stdlib/public/core/ShadowProtocols.swift +++ b/stdlib/public/core/ShadowProtocols.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Shims.swift b/stdlib/public/core/Shims.swift index ca3f90a82b1d7..86aace93ab91b 100644 --- a/stdlib/public/core/Shims.swift +++ b/stdlib/public/core/Shims.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Slice.swift.gyb b/stdlib/public/core/Slice.swift.gyb index 535f7b67881ba..fb7454ef4c19c 100644 --- a/stdlib/public/core/Slice.swift.gyb +++ b/stdlib/public/core/Slice.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -36,7 +36,7 @@ def get_slice_doc_comment(Self): /// the slice may prolong the lifetime of elements that are no longer /// accessible, which can manifest as apparent memory and object leakage. To /// prevent this effect, use slices only for transient computation.\ -""" % (Self, Self, Self, Self, Self) +""" % (Self, Self, Self, Self, Self) }% ${get_slice_doc_comment('Slice')} diff --git a/stdlib/public/core/SliceBuffer.swift b/stdlib/public/core/SliceBuffer.swift index dac0740eb70cc..cdd68ac0caab7 100644 --- a/stdlib/public/core/SliceBuffer.swift +++ b/stdlib/public/core/SliceBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Sort.swift.gyb b/stdlib/public/core/Sort.swift.gyb index 7288fdc9e87b4..1c7ac61b9c05c 100644 --- a/stdlib/public/core/Sort.swift.gyb +++ b/stdlib/public/core/Sort.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,11 +11,11 @@ //===----------------------------------------------------------------------===// %{ -def cmp(a,b,p): +def cmp(a, b, p): if p: - return "isOrderedBefore("+a+", "+b+")" + return "isOrderedBefore(" + a + ", " + b + ")" else: - return "("+a+" < "+b+")" + return "(" + a + " < " + b + ")" }% @@ -45,7 +45,7 @@ func _insertionSort< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { if !range.isEmpty { let start = range.startIndex @@ -56,7 +56,7 @@ func _insertionSort< // One element is trivially already-sorted, thus pre-increment // Continue until the sorted elements cover the whole sequence - sortedEnd = sortedEnd.successor() + sortedEnd._successorInPlace() while sortedEnd != range.endIndex { // get the first unsorted element let x: C.Generator.Element = elements[sortedEnd] @@ -74,14 +74,14 @@ func _insertionSort< // Move y forward elements[i] = predecessor - } - while --i != start + i._predecessorInPlace() + } while i != start if i != sortedEnd { // Plop x into position elements[i] = x } - sortedEnd = sortedEnd.successor() + sortedEnd._successorInPlace() } } } @@ -102,7 +102,7 @@ public func partition< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) -> C.Index { fatalError("unavailable function can't be called") } @@ -113,7 +113,7 @@ func _partition< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) -> C.Index { var lo = range.startIndex var hi = range.endIndex @@ -141,8 +141,10 @@ Loop: while true { } while false FindHi: repeat { - while --hi != lo { + hi._predecessorInPlace() + while hi != lo { if ${cmp("elements[hi]", "pivot", p)} { break FindHi } + hi._predecessorInPlace() } break Loop } while false @@ -150,7 +152,7 @@ Loop: while true { swap(&elements[lo], &elements[hi]) } - --lo + lo._predecessorInPlace() if lo != range.startIndex { // swap the pivot into place swap(&elements[lo], &elements[range.startIndex]) @@ -166,7 +168,7 @@ func _introSort< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { % if p: var comp = isOrderedBefore @@ -187,7 +189,7 @@ func _introSortImpl< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""}, + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""}, _ depthLimit: Int ) { @@ -219,7 +221,7 @@ func _siftDown< inout elements: C, _ index: C.Index, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { let countToIndex = (range.startIndex..( inout elements: C, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { // Here we build a heap starting from the lowest nodes and moving to the root. // On every step we sift down the current node to obey the max-heap property: @@ -263,7 +265,8 @@ func _heapify< // any children. let root = range.startIndex var node = root.advancedBy(C.Index.Distance(range.count.toIntMax()/2)) - while node-- != root { + while node != root { + node._predecessorInPlace() _siftDown(&elements, node, range ${", &isOrderedBefore" if p else ""}) } } @@ -273,14 +276,16 @@ func _heapSort< >( inout elements: C, _ range: Range ${"," if p else ""} - ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"inout _ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { var hi = range.endIndex let lo = range.startIndex _heapify(&elements, range ${", &isOrderedBefore" if p else ""}) - while --hi != lo { + hi._predecessorInPlace() + while hi != lo { swap(&elements[lo], &elements[hi]) _siftDown(&elements, lo, lo..( inout collection: C ${"," if p else ""} - ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) { fatalError("unavailable function can't be called") } @@ -355,7 +360,7 @@ public func sorted< C: SequenceType${"" if p else " where C.Generator.Element : Comparable"} >( source: C ${"," if p else ""} - ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element)->Bool" if p else ""} + ${"_ isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool" if p else ""} ) -> [C.Generator.Element] { fatalError("unavailable function can't be called") } diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index d23174bb4e9b9..c526f37a7a787 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,7 +17,7 @@ // are involved in its construction. This feature is crucial for // preventing infinite recursion even in non-asserting cases. -/// An simple string designed to represent text that is "knowable at +/// A simple string designed to represent text that is "knowable at /// compile-time". /// /// Logically speaking, each instance looks something like this: @@ -36,7 +36,7 @@ public struct StaticString StringLiteralConvertible, CustomStringConvertible, CustomDebugStringConvertible, - _Reflectable { + CustomReflectable { /// Either a pointer to the start of UTF-8 data, or an integer representation /// of a single Unicode scalar. @@ -226,7 +226,7 @@ public struct StaticString return self.stringValue.debugDescription } - public func _getMirror() -> _MirrorType { - return _reflect(self.stringValue) + public func customMirror() -> Mirror { + return Mirror(reflecting: stringValue) } } diff --git a/stdlib/public/core/Stride.swift b/stdlib/public/core/Stride.swift index 5ac66735a1d22..e7dc30712b1f8 100644 --- a/stdlib/public/core/Stride.swift +++ b/stdlib/public/core/Stride.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,7 +16,7 @@ public protocol Strideable : Comparable { // FIXME: We'd like to name this type "Distance" but for // /// A type that can represent the distance between two values of `Self`. - typealias Stride : SignedNumberType + associatedtype Stride : SignedNumberType /// Returns a stride `x` such that `self.advancedBy(x)` approximates /// `other`. @@ -135,14 +135,14 @@ public struct StrideToGenerator : GeneratorType { if stride > 0 ? current >= end : current <= end { return nil } - let ret = current + let result = current current += stride - return ret + return result } } /// A `SequenceType` of values formed by striding over a half-open interval. -public struct StrideTo : SequenceType { +public struct StrideTo : SequenceType, CustomReflectable { // FIXME: should really be a CollectionType, as it is multipass @available(*, unavailable, renamed="Element") @@ -167,6 +167,10 @@ public struct StrideTo : SequenceType { let start: Element let end: Element let stride: Element.Stride + + public func customMirror() -> Mirror { + return Mirror(self, children: ["from": start, "to": end, "by": stride]) + } } extension Strideable { @@ -209,14 +213,14 @@ public struct StrideThroughGenerator : GeneratorType { } return nil } - let ret = current + let result = current current += stride - return ret + return result } } /// A `SequenceType` of values formed by striding over a closed interval. -public struct StrideThrough : SequenceType { +public struct StrideThrough : SequenceType, CustomReflectable { // FIXME: should really be a CollectionType, as it is multipass @available(*, unavailable, renamed="Element") @@ -240,6 +244,10 @@ public struct StrideThrough : SequenceType { let start: Element let end: Element let stride: Element.Stride + + public func customMirror() -> Mirror { + return Mirror(self, children: ["from": start, "through": end, "by": stride]) + } } extension Strideable { diff --git a/stdlib/public/core/StrideMirrors.swift.gyb b/stdlib/public/core/StrideMirrors.swift.gyb deleted file mode 100644 index 40e581b0d274f..0000000000000 --- a/stdlib/public/core/StrideMirrors.swift.gyb +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../common/MirrorBoilerplate.gyb") - -% for Self in [['StrideTo','from','to','by'],['StrideThrough','from','through','by']]: -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,introspecteeType=Self[0],genericArgs=['T'],genericConstraints={'T':'Strideable'}) -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,introspecteeType=Self[0],genericArgs=['T'],genericConstraints={'T':'Strideable'}) -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,introspecteeType=Self[0],genericArgs=['T'],genericConstraints={'T':'Strideable'}) - -${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return 3 } - - subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - switch i { - case 0: return ("${Self[1]}",_reflect(_value.start)) - case 1: return ("${Self[2]}",_reflect(_value.end)) - case 2: fallthrough - default: return ("${Self[3]}",_reflect(_value.stride)) - } - } - - var summary: String { return "" } - - var quickLookObject: PlaygroundQuickLook? { return nil } -} - -${MirrorConformance} - - diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift index 32f30ed949087..d0a6a65935d12 100644 --- a/stdlib/public/core/String.swift +++ b/stdlib/public/core/String.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -272,7 +272,7 @@ extension String { Encoding: UnicodeCodecType >(encoding: Encoding.Type) -> Int { var codeUnitCount = 0 - let output: (Encoding.CodeUnit) -> Void = { _ in ++codeUnitCount } + let output: (Encoding.CodeUnit) -> Void = { _ in codeUnitCount += 1 } self._encode(encoding, output: output) return codeUnitCount } @@ -306,11 +306,11 @@ extension String { /// - returns: /// * an unspecified value less than zero if `lhs < rhs`, /// * zero if `lhs == rhs`, -/// * an unspecified value greater than zero if `lhs > rhs`. +/// * an unspecified value greater than zero if `lhs > rhs`. @_silgen_name("swift_stdlib_compareNSStringDeterministicUnicodeCollation") public func _stdlib_compareNSStringDeterministicUnicodeCollation( lhs: AnyObject, _ rhs: AnyObject -)-> Int32 +) -> Int32 #endif extension String : Equatable { diff --git a/stdlib/public/core/StringBridge.swift b/stdlib/public/core/StringBridge.swift index fdbb5d03dbecd..70fc3196601ee 100644 --- a/stdlib/public/core/StringBridge.swift +++ b/stdlib/public/core/StringBridge.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/StringBuffer.swift b/stdlib/public/core/StringBuffer.swift index 60f99f60d55ea..b0285a6395c74 100644 --- a/stdlib/public/core/StringBuffer.swift +++ b/stdlib/public/core/StringBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -112,7 +112,7 @@ public struct _StringBuffer { let hadError = transcode( encoding, UTF32.self, input.generate(), sink, stopOnError: true) - _sanityCheck(!hadError, "string can not be ASCII if there were decoding errors") + _sanityCheck(!hadError, "string cannot be ASCII if there were decoding errors") return (result, hadError) } else { @@ -186,7 +186,7 @@ public struct _StringBuffer { /// Attempt to claim unused capacity in the buffer. /// /// Operation succeeds if there is sufficient capacity, and either: - /// - the buffer is uniquely-refereced, or + /// - the buffer is uniquely-referenced, or /// - `oldUsedEnd` points to the end of the currently used capacity. /// /// - parameter subRange: Range of the substring that the caller tries diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift index 57a0f3c4b32a7..b892d2ec59a57 100644 --- a/stdlib/public/core/StringCharacterView.swift +++ b/stdlib/public/core/StringCharacterView.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -46,7 +46,7 @@ extension String { /// that is the target of this method) during the execution of /// `body`: it may not appear to have its correct value. Instead, /// use only the `String.CharacterView` argument to `body`. - public mutating func withMutableCharacters(body: (inout CharacterView)->R) -> R { + public mutating func withMutableCharacters(body: (inout CharacterView) -> R) -> R { // Naively mutating self.characters forces multiple references to // exist at the point of mutation. Instead, temporarily move the // core of this string into a CharacterView. @@ -72,7 +72,7 @@ extension String.CharacterView : CollectionType { } /// A character position. - public struct Index : BidirectionalIndexType, Comparable, _Reflectable { + public struct Index : BidirectionalIndexType, Comparable, CustomPlaygroundQuickLookable { public // SPI(Foundation) init(_base: String.UnicodeScalarView.Index) { self._base = _base @@ -88,7 +88,7 @@ extension String.CharacterView : CollectionType { /// /// - Requires: The next value is representable. public func successor() -> Index { - _precondition(_base != _base._viewEndIndex, "can not increment endIndex") + _precondition(_base != _base._viewEndIndex, "cannot increment endIndex") return Index(_base: _endBase) } @@ -97,7 +97,7 @@ extension String.CharacterView : CollectionType { /// - Requires: The previous value is representable. public func predecessor() -> Index { _precondition(_base != _base._viewStartIndex, - "can not decrement startIndex") + "cannot decrement startIndex") let predecessorLengthUTF16 = Index._measureExtendedGraphemeClusterBackward(_base) return Index( @@ -143,9 +143,9 @@ extension String.CharacterView : CollectionType { var gcb0 = graphemeClusterBreakProperty.getPropertyRawValue( unicodeScalars[start].value) - start = start.successor() + start._successorInPlace() - for ; start != end; start = start.successor() { + while start != end { // FIXME(performance): consider removing this "fast path". A branch // that is hard to predict could be worse for performance than a few // loads from cache to fetch the property 'gcb1'. @@ -158,6 +158,7 @@ extension String.CharacterView : CollectionType { break } gcb0 = gcb1 + start._successorInPlace() } return start._position - startIndexUTF16 @@ -182,14 +183,14 @@ extension String.CharacterView : CollectionType { var graphemeClusterStart = end - --graphemeClusterStart + graphemeClusterStart._predecessorInPlace() var gcb0 = graphemeClusterBreakProperty.getPropertyRawValue( unicodeScalars[graphemeClusterStart].value) var graphemeClusterStartUTF16 = graphemeClusterStart._position while graphemeClusterStart != start { - --graphemeClusterStart + graphemeClusterStart._predecessorInPlace() let gcb1 = graphemeClusterBreakProperty.getPropertyRawValue( unicodeScalars[graphemeClusterStart].value) if segmenter.isBoundary(gcb1, gcb0) { @@ -202,9 +203,8 @@ extension String.CharacterView : CollectionType { return endIndexUTF16 - graphemeClusterStartUTF16 } - /// Returns a mirror that reflects `self`. - public func _getMirror() -> _MirrorType { - return _IndexMirror(self) + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Int(Int64(_utf16Index)) } } @@ -230,34 +230,6 @@ extension String.CharacterView : CollectionType { public subscript(i: Index) -> Character { return Character(String(unicodeScalars[i._base.. (String, _MirrorType) { - _preconditionFailure("_MirrorType access out of bounds") - } - - var summary: String { return "\(_value._utf16Index)" } - - var quickLookObject: PlaygroundQuickLook? { - return .Int(Int64(_value._utf16Index)) - } - } } extension String.CharacterView : RangeReplaceableCollectionType { diff --git a/stdlib/public/core/StringCore.swift b/stdlib/public/core/StringCore.swift index a4a77f561859f..a7f473e51a1bc 100644 --- a/stdlib/public/core/StringCore.swift +++ b/stdlib/public/core/StringCore.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/StringInterpolation.swift.gyb b/stdlib/public/core/StringInterpolation.swift.gyb index 720fc2fea67ae..e4083386f685e 100644 --- a/stdlib/public/core/StringInterpolation.swift.gyb +++ b/stdlib/public/core/StringInterpolation.swift.gyb @@ -1,8 +1,8 @@ -//===--- StringInterpolation.swift.gyb - String Interpolation --*- swift -*-==// +//===--- StringInterpolation.swift.gyb - String Interpolation -*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 diff --git a/stdlib/public/core/StringLegacy.swift b/stdlib/public/core/StringLegacy.swift index 55c5862ba87ea..2db97ce268184 100644 --- a/stdlib/public/core/StringLegacy.swift +++ b/stdlib/public/core/StringLegacy.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -158,13 +158,13 @@ extension String { let rng = unicodeScalars var startIndex = rng.startIndex for _ in 0.. (before: String, after: String, wasFound : Bool) @@ -182,8 +182,8 @@ extension String { /// Split the given string at the first character for which the given /// predicate returns true. Returns the string before that character, the - /// character that matches, the string after that character, and a boolean value - /// indicating whether any character was found. + /// character that matches, the string after that character, + /// and a boolean value indicating whether any character was found. public func _splitFirstIf(@noescape predicate: (UnicodeScalar) -> Bool) -> (before: String, found: UnicodeScalar, after: String, wasFound: Bool) { diff --git a/stdlib/public/core/StringUTF16.swift b/stdlib/public/core/StringUTF16.swift index 526f9afb64789..708eb32426136 100644 --- a/stdlib/public/core/StringUTF16.swift +++ b/stdlib/public/core/StringUTF16.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,8 +13,7 @@ extension String { /// A collection of UTF-16 code units that encodes a `String` value. public struct UTF16View - : CollectionType, _Reflectable, CustomStringConvertible, - CustomDebugStringConvertible { + : CollectionType, CustomStringConvertible, CustomDebugStringConvertible { public struct Index { // Foundation needs access to these fields so it can expose @@ -122,12 +121,6 @@ extension String { self._core = _core } - /// Returns a mirror that reflects `self`. - @warn_unused_result - public func _getMirror() -> _MirrorType { - return _UTF16ViewMirror(self) - } - public var description: String { let start = _toInternalIndex(0) let end = _toInternalIndex(_length) @@ -305,3 +298,18 @@ extension String.UTF16View.Index { return String.Index(self, within: characters) } } + +// Reflection +extension String.UTF16View : CustomReflectable { + /// Returns a mirror that reflects `self`. + @warn_unused_result + public func customMirror() -> Mirror { + return Mirror(self, unlabeledChildren: self) + } +} + +extension String.UTF16View : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(description) + } +} diff --git a/stdlib/public/core/StringUTF8.swift b/stdlib/public/core/StringUTF8.swift index d51b0719e3795..a7af21b955b7b 100644 --- a/stdlib/public/core/StringUTF8.swift +++ b/stdlib/public/core/StringUTF8.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -86,8 +86,7 @@ extension _StringCore { extension String { /// A collection of UTF-8 code units that encodes a `String` value. - public struct UTF8View : CollectionType, _Reflectable, CustomStringConvertible, - CustomDebugStringConvertible { + public struct UTF8View : CollectionType, CustomStringConvertible, CustomDebugStringConvertible { internal let _core: _StringCore internal let _startIndex: Index internal let _endIndex: Index @@ -217,7 +216,7 @@ extension String { /// `position != endIndex`. public subscript(position: Index) -> UTF8.CodeUnit { let result: UTF8.CodeUnit = numericCast(position._buffer & 0xFF) - _precondition(result != 0xFF, "can not subscript using endIndex") + _precondition(result != 0xFF, "cannot subscript using endIndex") return result } @@ -230,12 +229,6 @@ extension String { return UTF8View(_core, subRange.startIndex, subRange.endIndex) } - /// Returns a mirror that reflects `self`. - @warn_unused_result - public func _getMirror() -> _MirrorType { - return _UTF8ViewMirror(self) - } - public var description: String { return String._fromCodeUnitSequenceWithRepair(UTF8.self, input: self).0 } @@ -411,3 +404,18 @@ extension String.UTF8View.Index { return String.Index(self, within: characters) } } + +// Reflection +extension String.UTF8View : CustomReflectable { + /// Returns a mirror that reflects `self`. + @warn_unused_result + public func customMirror() -> Mirror { + return Mirror(self, unlabeledChildren: self) + } +} + +extension String.UTF8View : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(description) + } +} diff --git a/stdlib/public/core/StringUTFViewsMirrors.swift.gyb b/stdlib/public/core/StringUTFViewsMirrors.swift.gyb deleted file mode 100644 index 316f2a1ac288e..0000000000000 --- a/stdlib/public/core/StringUTFViewsMirrors.swift.gyb +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -%import gyb -%TMirrorDecl = gyb.parseTemplate("../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../common/MirrorBoilerplate.gyb") - -% for Self in ['UTF8View', 'UTF16View', 'UnicodeScalarView']: -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,introspecteeType=Self) -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,introspecteeType=Self) -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,introspecteeType=Self) - -extension String { - ${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return _value.startIndex.distanceTo(_value.endIndex) } - - subscript(i: Int) -> (String, _MirrorType) { - _precondition(i >= 0 && i < count, "_MirrorType access out of bounds") - // FIXME(performance): optimize for sequential access. - return ("[\(i)]", _reflect(_value[_value.startIndex.advancedBy(i)])) - } - - var summary: String { return _value.description } - - var quickLookObject: PlaygroundQuickLook? { return .Text(summary) } - } -} diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift index 281653b1bdd6e..013ccf937fe2c 100644 --- a/stdlib/public/core/StringUnicodeScalarView.swift +++ b/stdlib/public/core/StringUnicodeScalarView.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -29,8 +29,7 @@ public func <( extension String { /// A collection of [Unicode scalar values](http://www.unicode.org/glossary/#unicode_scalar_value) that /// encode a `String` . - public struct UnicodeScalarView : CollectionType, _Reflectable, - CustomStringConvertible, CustomDebugStringConvertible { + public struct UnicodeScalarView : CollectionType, CustomStringConvertible, CustomDebugStringConvertible { init(_ _core: _StringCore) { self._core = _core } @@ -46,7 +45,8 @@ extension String { if idx == core.endIndex { return nil } - return self.core[idx++] + defer { idx += 1 } + return self.core[idx] } } @@ -73,8 +73,8 @@ extension String { /// - Requires: The previous value is representable. @warn_unused_result public func predecessor() -> Index { - var i = _position - let codeUnit = _core[--i] + var i = _position-1 + let codeUnit = _core[i] if _slowPath((codeUnit >> 10) == 0b1101_11) { if i != 0 && (_core[i - 1] >> 10) == 0b1101_10 { i -= 1 @@ -123,7 +123,7 @@ extension String { case .Result(let us): return us case .EmptyInput: - _sanityCheckFailure("can not subscript using an endIndex") + _sanityCheckFailure("cannot subscript using an endIndex") case .Error: return UnicodeScalar(0xfffd) } @@ -210,12 +210,6 @@ extension String { return Generator(_core) } - /// Returns a mirror that reflects `self`. - @warn_unused_result - public func _getMirror() -> _MirrorType { - return _UnicodeScalarViewMirror(self) - } - public var description: String { return String(_core[startIndex._position.. Mirror { + return Mirror(self, unlabeledChildren: self) + } +} + +extension String.UnicodeScalarView : CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(description) + } +} diff --git a/stdlib/public/core/SwiftNativeNSArray.swift b/stdlib/public/core/SwiftNativeNSArray.swift index e08db177f5942..c36203e8d37da 100644 --- a/stdlib/public/core/SwiftNativeNSArray.swift +++ b/stdlib/public/core/SwiftNativeNSArray.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/Tuple.swift.gyb b/stdlib/public/core/Tuple.swift.gyb new file mode 100644 index 0000000000000..4e6baf631dc66 --- /dev/null +++ b/stdlib/public/core/Tuple.swift.gyb @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// Generate comparison functions for tuples up to some reasonable arity. + +% for arity in range(2,7): +% typeParams = [chr(ord("A") + i) for i in range(arity)] +% tupleT = "({})".format(",".join(typeParams)) + +% equatableTypeParams = ", ".join(["{} : Equatable".format(c) for c in typeParams]) + +/// Returns `true` iff each component of `lhs` is equal to the corresponding +/// component of `rhs`. +@warn_unused_result +public func == <${equatableTypeParams}>(lhs: ${tupleT}, rhs: ${tupleT}) -> Bool { + guard lhs.0 == rhs.0 else { return false } + /*tail*/ return ( + ${", ".join("lhs.{}".format(i) for i in range(1, arity))} + ) == ( + ${", ".join("rhs.{}".format(i) for i in range(1, arity))} + ) +} + +/// Returns `true` iff any component of `lhs` is not equal to the corresponding +/// component of `rhs`. +@warn_unused_result +public func != <${equatableTypeParams}>(lhs: ${tupleT}, rhs: ${tupleT}) -> Bool { + guard lhs.0 == rhs.0 else { return true } + /*tail*/ return ( + ${", ".join("lhs.{}".format(i) for i in range(1, arity))} + ) != ( + ${", ".join("rhs.{}".format(i) for i in range(1, arity))} + ) +} + +% comparableTypeParams = ", ".join(["{} : Comparable".format(c) for c in typeParams]) +% for op in ["<", ">"]: +% for opeq in ["", "="]: +/// A [lexicographical order](https://en.wikipedia.org/wiki/Lexicographical_order) +/// over tuples of `Comparable` elements. +/// +/// Given two tuples `(a1, a2, ..., aN)` and `(b1, b2, ..., bN)`, the +/// first tuple is `${op}${opeq}` the second tuple iff `a1 ${op} b1` or +/// (`a1 == b1` and `(a2, ..., aN) ${op}${opeq} (b2, ..., bN)`). +@warn_unused_result +public func ${op}${opeq} <${comparableTypeParams}>(lhs: ${tupleT}, rhs: ${tupleT}) -> Bool { + if lhs.0 != rhs.0 { return lhs.0 ${op}${opeq} rhs.0 } + /*tail*/ return ( + ${", ".join("lhs.{}".format(i) for i in range(1, arity))} + ) ${op}${opeq} ( + ${", ".join("rhs.{}".format(i) for i in range(1, arity))} + ) +} +% end +% end +% end diff --git a/stdlib/public/core/UnavailableStringAPIs.swift.gyb b/stdlib/public/core/UnavailableStringAPIs.swift.gyb index 084b58b6b449b..20c3761f9a00e 100644 --- a/stdlib/public/core/UnavailableStringAPIs.swift.gyb +++ b/stdlib/public/core/UnavailableStringAPIs.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,7 +18,7 @@ stringSubscriptComment = """ /// different interpretations in different libraries and system /// components. The correct interpretation should be selected /// according to the use case and the APIs involved, so `String` - /// can not be subscripted with an integer. + /// cannot be subscripted with an integer. /// /// Swift provides several different ways to access the character /// data stored inside strings. @@ -38,7 +38,7 @@ stringSubscriptComment = """ /// Use this API when you are performing low-level manipulation /// of character data. /// - /// - `String.chracters` is a collection of extended grapheme + /// - `String.characters` is a collection of extended grapheme /// clusters, which are an approximation of user-perceived /// characters. /// @@ -98,7 +98,7 @@ ${stringSubscriptComment} /// Unicode scalars in the string. Use this API when you are /// performing low-level manipulation of character data. /// - /// - `String.chracters.count` property returns the number of + /// - `String.characters.count` property returns the number of /// extended grapheme clusters. Use this API to count the /// number of user-perceived characters in the string. @available( diff --git a/stdlib/public/core/Unicode.swift b/stdlib/public/core/Unicode.swift index 1f79d2e7e7bcc..bc133ff73f43f 100644 --- a/stdlib/public/core/Unicode.swift +++ b/stdlib/public/core/Unicode.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,7 +44,7 @@ public protocol UnicodeCodecType { /// A type that can hold [code unit](http://www.unicode.org/glossary/#code_unit) values for this /// encoding. - typealias CodeUnit + associatedtype CodeUnit init() @@ -79,7 +79,7 @@ public struct UTF8 : UnicodeCodecType { public init() {} /// Returns the number of expected trailing bytes for a given first byte: 0, - /// 1, 2 or 3. If the first byte can not start a valid UTF-8 code unit + /// 1, 2 or 3. If the first byte cannot start a valid UTF-8 code unit /// sequence, returns 4. @warn_unused_result public static func _numTrailingBytes(cu0: CodeUnit) -> UInt8 { @@ -705,9 +705,8 @@ public func transcode< var inputDecoder = inputEncoding.init() var hadError = false - for var scalar = inputDecoder.decode(&input); - !scalar.isEmptyInput(); - scalar = inputDecoder.decode(&input) { + var scalar = inputDecoder.decode(&input) + while !scalar.isEmptyInput() { switch scalar { case .Result(let us): OutputEncoding.encode(us, output: output) @@ -721,6 +720,7 @@ public func transcode< hadError = true } } + scalar = inputDecoder.decode(&input) } return hadError } diff --git a/stdlib/public/core/UnicodeScalar.swift b/stdlib/public/core/UnicodeScalar.swift index 4057da78e66ad..3a46ec3efd32c 100644 --- a/stdlib/public/core/UnicodeScalar.swift +++ b/stdlib/public/core/UnicodeScalar.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -20,11 +20,7 @@ public struct UnicodeScalar : var _value: UInt32 /// A numeric representation of `self`. - public var value: UInt32 { - get { - return _value - } - } + public var value: UInt32 { return _value } @_transparent public init(_builtinUnicodeScalarLiteral value: Builtin.Int32) { @@ -159,7 +155,7 @@ public struct UnicodeScalar : return (self >= "A" && self <= "Z") || (self >= "a" && self <= "z") } - // FIXME: Is there an similar term of art in Unicode? + // FIXME: Is there a similar term of art in Unicode? @warn_unused_result public func _isASCIIDigit() -> Bool { return self >= "0" && self <= "9" diff --git a/stdlib/public/core/UnicodeTrie.swift.gyb b/stdlib/public/core/UnicodeTrie.swift.gyb index 93788027b7498..1247009eecefd 100644 --- a/stdlib/public/core/UnicodeTrie.swift.gyb +++ b/stdlib/public/core/UnicodeTrie.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -45,7 +45,7 @@ SuppDataBytesOffset = 12817 import SwiftShims public // @testable -enum _GraphemeClusterBreakPropertyValue : Int, CustomStringConvertible { +enum _GraphemeClusterBreakPropertyValue : Int { case Other = 0 case CR = 1 case LF = 2 @@ -59,39 +59,6 @@ enum _GraphemeClusterBreakPropertyValue : Int, CustomStringConvertible { case T = 10 case LV = 11 case LVT = 12 - - /// A textual representation of `self`. - public // @testable - var description: String { - switch self { - case Other: - return "Other" - case CR: - return "CR" - case LF: - return "LF" - case Control: - return "Control" - case Extend: - return "Extend" - case Regional_Indicator: - return "Regional_Indicator" - case Prepend: - return "Prepend" - case SpacingMark: - return "SpacingMark" - case L: - return "L" - case V: - return "V" - case T: - return "T" - case LV: - return "LV" - case LVT: - return "LVT" - } - } } // It is expensive to convert a raw enum value to an enum, so we use this type diff --git a/stdlib/public/core/Unmanaged.swift b/stdlib/public/core/Unmanaged.swift index d055d558c19dc..086b2b52b735c 100644 --- a/stdlib/public/core/Unmanaged.swift +++ b/stdlib/public/core/Unmanaged.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index baf9a5effb638..12e3b4f388b7b 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb index e83423ff4d840..340ef891f4867 100644 --- a/stdlib/public/core/UnsafePointer.swift.gyb +++ b/stdlib/public/core/UnsafePointer.swift.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -11,16 +11,10 @@ //===----------------------------------------------------------------------===// %import gyb -%TMirrorDecl = gyb.parseTemplate("../common/MirrorDecl.gyb") -%TMirrorConformance = gyb.parseTemplate("../common/MirrorConformance.gyb") -%TMirrorBoilerplate = gyb.parseTemplate("../common/MirrorBoilerplate.gyb") % for mutable in (True, False): % Self = 'UnsafeMutablePointer' if mutable else 'UnsafePointer' % a_Self = 'an `UnsafeMutablePointer`' if mutable else 'an `UnsafePointer`' -% MirrorConformance = gyb.executeTemplate(TMirrorConformance,introspecteeType=Self,genericArgs=['Memory'],disposition='Struct') -% MirrorDecl = gyb.executeTemplate(TMirrorDecl,introspecteeType=Self,genericArgs=['Memory'],disposition='Struct') -% MirrorBoilerplate = gyb.executeTemplate(TMirrorBoilerplate,introspecteeType=Self,genericArgs=['Memory'],disposition='Struct') /// A pointer to an object of type `Memory`. This type provides no automated /// memory management, and therefore the user must take care to allocate @@ -164,7 +158,7 @@ ${comment} /// /// - Precondition: The memory is not initialized. /// - /// - Postcondition: The memory is initalized; the value should eventually + /// - Postcondition: The memory is initialized; the value should eventually /// be destroyed or moved from to avoid leaks. public func initialize(newvalue: Memory) { Builtin.initialize(newvalue, _rawValue) @@ -210,8 +204,10 @@ ${comment} _debugPrecondition( source < self || source >= self + count, "${Self}.assignBackwardFrom non-preceding overlapping range; use assignFrom instead") - for var i = count; --i >= 0; { + var i = count-1 + while i >= 0 { self[i] = source[i] + i -= 1 } } @@ -421,34 +417,25 @@ extension ${Self} : CustomDebugStringConvertible { } } -${MirrorDecl} { - ${MirrorBoilerplate} - - var count: Int { return 1 } - - func _getPointerValue() -> UInt64 { - return UInt64(Int(Builtin.ptrtoint_Word(_value._rawValue))) - } - - subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: return ("pointerValue",_reflect(_getPointerValue())) - default: _preconditionFailure("cannot extract this child index") - } +extension ${Self} : CustomReflectable { + public func customMirror() -> Mirror { + let ptrValue = UInt64(bitPattern: Int64(Int(Builtin.ptrtoint_Word(_rawValue)))) + return Mirror(self, children: ["pointerValue": ptrValue]) } +} +extension ${Self} : CustomPlaygroundQuickLookable { var summary: String { let selfType = "${Self}" - let ptrValue = _getPointerValue() - if ptrValue == 0 { return "\(selfType)(nil)" } - return "\(selfType)(0x\(_uint64ToString(ptrValue, radix:16, uppercase:true)))" + let ptrValue = UInt64(bitPattern: Int64(Int(Builtin.ptrtoint_Word(_rawValue)))) + return ptrValue == 0 ? "\(selfType)(nil)" : "\(selfType)(0x\(_uint64ToString(ptrValue, radix:16, uppercase:true)))" } - var quickLookObject: PlaygroundQuickLook? { return .Text(summary) } + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + return .Text(summary) + } } -${MirrorConformance} - @_transparent @warn_unused_result public func == ( diff --git a/stdlib/public/core/VarArgs.swift b/stdlib/public/core/VarArgs.swift index 4b64ceef52f51..ce4ee0e916fb3 100644 --- a/stdlib/public/core/VarArgs.swift +++ b/stdlib/public/core/VarArgs.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -333,7 +333,8 @@ final public class VaListBuilder { } for word in words { - storage[count++] = word + storage[count] = word + count += 1 } } @@ -403,7 +404,8 @@ final public class VaListBuilder { sseRegistersUsed += 1 } else if encoded.count == 1 && gpRegistersUsed < _x86_64CountGPRegisters { - storage[gpRegistersUsed++] = encoded[0] + storage[gpRegistersUsed] = encoded[0] + gpRegistersUsed += 1 } else { for w in encoded { diff --git a/stdlib/public/core/Zip.swift b/stdlib/public/core/Zip.swift index f68ce9fe9a68f..ca0a6961a9144 100644 --- a/stdlib/public/core/Zip.swift +++ b/stdlib/public/core/Zip.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index c3fbdc7614359..cadbb44c84580 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -17,36 +17,19 @@ if(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER) set(swift_runtime_leaks_sources Leaks.mm) endif() -set(swift_runtime_dtrace_sources) -if (SWIFT_RUNTIME_ENABLE_DTRACE) - set(swift_runtime_dtrace_sources SwiftRuntimeDTraceProbes.d) - list(APPEND swift_runtime_compile_flags - "-DSWIFT_RUNTIME_ENABLE_DTRACE=1") -endif() - # Acknowledge that the following sources are known. set(LLVM_OPTIONAL_SOURCES Remangle.cpp) set(swift_runtime_objc_sources) set(swift_runtime_unicode_normalization_sources) -set(swift_runtime_link_libraries) if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") set(swift_runtime_objc_sources ErrorObject.mm SwiftObject.mm Remangle.cpp Reflection.mm) - set(LLVM_OPTIONAL_SOURCES - UnicodeNormalization.cpp) else() - find_package(ICU REQUIRED COMPONENTS uc i18n) - set(swift_runtime_unicode_normalization_sources - UnicodeNormalization.cpp) - set(swift_runtime_link_libraries - ${ICU_UC_LIBRARY} ${ICU_I18N_LIBRARY}) - include_directories( - ${ICU_UC_INCLUDE_DIR} ${ICU_I18N_INCLUDE_DIR}) endif() add_swift_library(swiftRuntime IS_STDLIB IS_STDLIB_CORE @@ -59,16 +42,14 @@ add_swift_library(swiftRuntime IS_STDLIB IS_STDLIB_CORE HeapObject.cpp KnownMetadata.cpp Metadata.cpp + MetadataLookup.cpp Once.cpp + ProtocolConformance.cpp Reflection.cpp SwiftObject.cpp - UnicodeExtendedGraphemeClusters.cpp.gyb ${swift_runtime_objc_sources} - ${swift_runtime_dtrace_sources} ${swift_runtime_leaks_sources} - ${swift_runtime_unicode_normalization_sources} C_COMPILE_FLAGS ${swift_runtime_compile_flags} - LINK_LIBRARIES ${swift_runtime_link_libraries} INSTALL_IN_COMPONENT stdlib) foreach(sdk ${SWIFT_CONFIGURED_SDKS}) diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index d7584a83e32b5..5becdd929d6dc 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,7 +18,6 @@ #include "swift/Basic/Demangle.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/Lazy.h" -#include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Enum.h" #include "swift/Runtime/HeapObject.h" @@ -32,18 +31,8 @@ #include "../SwiftShims/RuntimeShims.h" #include "stddef.h" -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#elif defined(__ELF__) -#include -#include -#endif - -#include #include #include -#include #include // FIXME: Clang defines max_align_t in stddef.h since 3.6. @@ -58,14 +47,13 @@ using namespace swift; using namespace metadataimpl; #if SWIFT_OBJC_INTEROP -//#include #include #include #include #include // Aliases for Objective-C runtime entry points. -const char *class_getName(const ClassMetadata* type) { +static const char *class_getName(const ClassMetadata* type) { return class_getName( reinterpret_cast(const_cast(type))); } @@ -469,9 +457,14 @@ static bool _dynamicCastClassToValueViaObjCBridgeable( /// A convenient method for failing out of a dynamic cast. static bool _fail(OpaqueValue *srcValue, const Metadata *srcType, - const Metadata *targetType, DynamicCastFlags flags) { - if (flags & DynamicCastFlags::Unconditional) - swift_dynamicCastFailure(srcType, targetType); + const Metadata *targetType, DynamicCastFlags flags, + const Metadata *srcDynamicType = nullptr) { + if (flags & DynamicCastFlags::Unconditional) { + const Metadata *srcTypeToReport = + srcDynamicType ? srcDynamicType + : srcType; + swift_dynamicCastFailure(srcTypeToReport, targetType); + } if (flags & DynamicCastFlags::DestroyOnFailure) srcType->vw_destroy(srcValue); return false; @@ -602,7 +595,7 @@ static bool _conformsToProtocol(const OpaqueValue *value, if (value) { return _unknownClassConformsToObjCProtocol(value, protocol); } else { - return _swift_classConformsToObjCProtocol(type, protocol); + return classConformsToObjCProtocol(type, protocol); } #endif return false; @@ -613,7 +606,7 @@ static bool _conformsToProtocol(const OpaqueValue *value, return _unknownClassConformsToObjCProtocol(value, protocol); } else { auto wrapper = cast(type); - return _swift_classConformsToObjCProtocol(wrapper->Class, protocol); + return classConformsToObjCProtocol(wrapper->Class, protocol); } #endif return false; @@ -986,7 +979,7 @@ static bool _dynamicCastToExistential(OpaqueValue *dest, if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, destExistential->getWitnessTables())) { - return _fail(srcDynamicValue, srcDynamicType, targetType, flags); + return _fail(src, srcType, targetType, flags, srcDynamicType); } auto object = *(reinterpret_cast(srcDynamicValue)); @@ -1005,7 +998,7 @@ static bool _dynamicCastToExistential(OpaqueValue *dest, if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, destExistential->getWitnessTables())) - return _fail(srcDynamicValue, srcDynamicType, targetType, flags); + return _fail(src, srcType, targetType, flags, srcDynamicType); // Fill in the type and value. destExistential->Type = srcDynamicType; @@ -1029,7 +1022,7 @@ static bool _dynamicCastToExistential(OpaqueValue *dest, if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, &errorWitness)) - return _fail(srcDynamicValue, srcDynamicType, targetType, flags); + return _fail(src, srcType, targetType, flags, srcDynamicType); BoxPair destBox = swift_allocError(srcDynamicType, errorWitness, srcDynamicValue, @@ -1058,7 +1051,7 @@ _dynamicCastUnknownClassToExistential(const void *object, if (protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject) break; - if (!_swift_objectConformsToObjCProtocol(object, protocol)) + if (!objectConformsToObjCProtocol(object, protocol)) return nullptr; break; #else @@ -1906,10 +1899,7 @@ static bool _dynamicCastToExistentialMetatype(OpaqueValue *dest, case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: - if (flags & DynamicCastFlags::Unconditional) { - swift_dynamicCastFailure(srcType, targetType); - } - return false; + return _fail(src, srcType, targetType, flags); } _failCorruptType(srcType); } @@ -1990,15 +1980,63 @@ static id dynamicCastValueToNSError(OpaqueValue *src, } #endif -static bool canCastToExistential(OpaqueValue *dest, OpaqueValue *src, - const Metadata *srcType, - const Metadata *targetType) { - if (targetType->getKind() != MetadataKind::Existential) - return false; +namespace { + +struct OptionalCastResult { + bool success; + const Metadata* payloadType; +}; - return _dynamicCastToExistential(dest, src, srcType, - cast(targetType), - DynamicCastFlags::Default); +} + +/// Handle optional unwrapping of the cast source. +/// \returns {true, nullptr} if the cast succeeds without unwrapping. +/// \returns {false, nullptr} if the cast fails before unwrapping. +/// \returns {false, payloadType} if the cast should be attempted using an +/// equivalent payloadType. +static OptionalCastResult +checkDynamicCastFromOptional(OpaqueValue *dest, + OpaqueValue *src, + const Metadata *srcType, + const Metadata *targetType, + DynamicCastFlags flags) { + if (srcType->getKind() != MetadataKind::Optional) + return {false, srcType}; + + // Check if the target is an existential that Optional always conforms to. + if (targetType->getKind() == MetadataKind::Existential) { + // Attempt a conditional cast without destroying on failure. + DynamicCastFlags checkCastFlags + = flags - (DynamicCastFlags::Unconditional + | DynamicCastFlags::DestroyOnFailure); + assert((checkCastFlags - DynamicCastFlags::TakeOnSuccess) + == DynamicCastFlags::Default && "Unhandled DynamicCastFlag"); + if (_dynamicCastToExistential(dest, src, srcType, + cast(targetType), + checkCastFlags)) { + return {true, nullptr}; + } + } + const Metadata *payloadType = + cast(srcType)->getGenericArgs()[0]; + int enumCase = + swift_getEnumCaseSinglePayload(src, payloadType, 1 /*emptyCases=*/); + if (enumCase != -1) { + // Allow Optional.None -> Optional.None + if (targetType->getKind() != MetadataKind::Optional) { + _fail(src, srcType, targetType, flags); + return {false, nullptr}; + } + // Inject the .None tag + swift_storeEnumTagSinglePayload(dest, payloadType, enumCase, + 1 /*emptyCases=*/); + _succeed(dest, src, srcType, flags); + return {true, nullptr}; + } + // .Some + // Single payload enums are guaranteed layout compatible with their + // payload. Only the source's payload needs to be taken or destroyed. + return {false, payloadType}; } /// Perform a dynamic cast to an arbitrary type. @@ -2007,28 +2045,11 @@ bool swift::swift_dynamicCast(OpaqueValue *dest, const Metadata *srcType, const Metadata *targetType, DynamicCastFlags flags) { - // Check if the cast source is Optional and the target is not an existential - // that Optional conforms to. Unwrap one level of Optional and continue. - if (srcType->getKind() == MetadataKind::Optional - && !canCastToExistential(dest, src, srcType, targetType)) { - const Metadata *payloadType = - cast(srcType)->getGenericArgs()[0]; - int enumCase = - swift_getEnumCaseSinglePayload(src, payloadType, 1 /*emptyCases=*/); - if (enumCase != -1) { - // Allow Optional.None -> Optional.None - if (targetType->getKind() != MetadataKind::Optional) - return _fail(src, srcType, targetType, flags); - // Inject the .None tag - swift_storeEnumTagSinglePayload(dest, payloadType, enumCase, - 1 /*emptyCases=*/); - return _succeed(dest, src, srcType, flags); - } - // .Some - // Single payload enums are guaranteed layout compatible with their - // payload. Only the source's payload needs to be taken or destroyed. - srcType = payloadType; - } + auto unwrapResult = checkDynamicCastFromOptional(dest, src, srcType, + targetType, flags); + srcType = unwrapResult.payloadType; + if (!srcType) + return unwrapResult.success; switch (targetType->getKind()) { // Handle wrapping an Optional target. @@ -2196,569 +2217,6 @@ bool swift::swift_dynamicCast(OpaqueValue *dest, _failCorruptType(srcType); } -#if defined(NDEBUG) && SWIFT_OBJC_INTEROP -void ProtocolConformanceRecord::dump() const { - auto symbolName = [&](const void *addr) -> const char * { - Dl_info info; - int ok = dladdr(addr, &info); - if (!ok) - return ""; - return info.dli_sname; - }; - - switch (auto kind = getTypeKind()) { - case ProtocolConformanceTypeKind::Universal: - printf("universal"); - break; - case ProtocolConformanceTypeKind::UniqueDirectType: - case ProtocolConformanceTypeKind::NonuniqueDirectType: - printf("%s direct type ", - kind == ProtocolConformanceTypeKind::UniqueDirectType - ? "unique" : "nonunique"); - if (auto ntd = getDirectType()->getNominalTypeDescriptor()) { - printf("%s", ntd->Name); - } else { - printf(""); - } - break; - case ProtocolConformanceTypeKind::UniqueDirectClass: - printf("unique direct class %s", - class_getName(getDirectClass())); - break; - case ProtocolConformanceTypeKind::UniqueIndirectClass: - printf("unique indirect class %s", - class_getName(*getIndirectClass())); - break; - - case ProtocolConformanceTypeKind::UniqueGenericPattern: - printf("unique generic type %s", symbolName(getGenericPattern())); - break; - } - - printf(" => "); - - switch (getConformanceKind()) { - case ProtocolConformanceReferenceKind::WitnessTable: - printf("witness table %s\n", symbolName(getStaticWitnessTable())); - break; - case ProtocolConformanceReferenceKind::WitnessTableAccessor: - printf("witness table accessor %s\n", - symbolName((const void *)(uintptr_t)getWitnessTableAccessor())); - break; - } -} -#endif - -/// Take the type reference inside a protocol conformance record and fetch the -/// canonical metadata pointer for the type it refers to. -/// Returns nil for universal or generic type references. -const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata() -const { - switch (getTypeKind()) { - case ProtocolConformanceTypeKind::UniqueDirectType: - // Already unique. - return getDirectType(); - case ProtocolConformanceTypeKind::NonuniqueDirectType: - // Ask the runtime for the unique metadata record we've canonized. - return swift_getForeignTypeMetadata((ForeignTypeMetadata*)getDirectType()); - case ProtocolConformanceTypeKind::UniqueIndirectClass: - // The class may be ObjC, in which case we need to instantiate its Swift - // metadata. The class additionally may be weak-linked, so we have to check - // for null. - if (auto *ClassMetadata = *getIndirectClass()) - return swift_getObjCClassMetadata(ClassMetadata); - return nullptr; - - case ProtocolConformanceTypeKind::UniqueDirectClass: - // The class may be ObjC, in which case we need to instantiate its Swift - // metadata. - if (auto *ClassMetadata = getDirectClass()) - return swift_getObjCClassMetadata(ClassMetadata); - return nullptr; - - case ProtocolConformanceTypeKind::UniqueGenericPattern: - case ProtocolConformanceTypeKind::Universal: - // The record does not apply to a single type. - return nullptr; - } -} - -const WitnessTable *ProtocolConformanceRecord::getWitnessTable(const Metadata *type) -const { - switch (getConformanceKind()) { - case ProtocolConformanceReferenceKind::WitnessTable: - return getStaticWitnessTable(); - - case ProtocolConformanceReferenceKind::WitnessTableAccessor: - return getWitnessTableAccessor()(type); - } -} - -#if defined(__APPLE__) && defined(__MACH__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" -#elif defined(__ELF__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" -#endif - -// std:once_flag token to install the dyld callback to enqueue images for -// protocol conformance lookup. -static std::once_flag InstallProtocolConformanceAddImageCallbackOnce; - -namespace { - struct ConformanceSection { - const ProtocolConformanceRecord *Begin, *End; - const ProtocolConformanceRecord *begin() const { - return Begin; - } - const ProtocolConformanceRecord *end() const { - return End; - } - }; - - struct ConformanceCacheEntry { - private: - const void *Type; - const ProtocolDescriptor *Proto; - uintptr_t Data; - // All Darwin 64-bit platforms reserve the low 2^32 of address space, which - // is more than enough invalid pointer values for any realistic generation - // number. It's a little easier to overflow on 32-bit, so we need an extra - // bit there. -#if !__LP64__ - bool Success; -#endif - - ConformanceCacheEntry(const void *type, - const ProtocolDescriptor *proto, - uintptr_t Data, bool Success) - : Type(type), Proto(proto), Data(Data) -#if !__LP64__ - , Success(Success) -#endif - { -#if __LP64__ -# if __APPLE__ - assert((!Success && Data <= 0xFFFFFFFFU) || - (Success && Data > 0xFFFFFFFFU)); -# elif __linux__ || __FreeBSD__ - assert((!Success && Data <= 0x0FFFU) || - (Success && Data > 0x0FFFU)); -# else -# error "port me" -# endif -#endif - } - - public: - ConformanceCacheEntry() = default; - - static ConformanceCacheEntry createSuccess( - const void *type, const ProtocolDescriptor *proto, - const swift::WitnessTable *witness) { - return ConformanceCacheEntry(type, proto, (uintptr_t) witness, true); - } - - static ConformanceCacheEntry createFailure( - const void *type, const ProtocolDescriptor *proto, - unsigned failureGeneration) { - return ConformanceCacheEntry(type, proto, (uintptr_t) failureGeneration, - false); - } - - /// \returns true if the entry represents an entry for the pair \p type - /// and \p proto. - bool matches(const void *type, const ProtocolDescriptor *proto) { - return type == Type && Proto == proto; - } - - bool isSuccessful() const { -#if __LP64__ -# if __APPLE__ - return Data > 0xFFFFFFFFU; -# elif __linux__ || __FreeBSD__ - return Data > 0x0FFFU; -# else -# error "port me" -# endif -#else - return Success; -#endif - } - - /// Get the cached witness table, if successful. - const WitnessTable *getWitnessTable() const { - assert(isSuccessful()); - return (const WitnessTable *)Data; - } - - /// Get the generation number under which this lookup failed. - unsigned getFailureGeneration() const { - assert(!isSuccessful()); - return Data; - } - }; -} - -// Conformance Cache. - -struct ConformanceState { - ConcurrentMap Cache; - std::vector SectionsToScan; - pthread_mutex_t SectionsToScanLock; - - ConformanceState() { - SectionsToScan.reserve(16); - pthread_mutex_init(&SectionsToScanLock, nullptr); - } -}; - -static Lazy Conformances; - -// This variable is used to signal when a cache was generated and -// it is correct to avoid a new scan. -static unsigned ConformanceCacheGeneration = 0; - -void -swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin, - const ProtocolConformanceRecord *end){ - auto &C = Conformances.get(); - - pthread_mutex_lock(&C.SectionsToScanLock); - - C.SectionsToScan.push_back(ConformanceSection{begin, end}); - - pthread_mutex_unlock(&C.SectionsToScanLock); -} - -static void _addImageProtocolConformancesBlock(const uint8_t *conformances, - size_t conformancesSize) { - assert(conformancesSize % sizeof(ProtocolConformanceRecord) == 0 - && "weird-sized conformances section?!"); - - // If we have a section, enqueue the conformances for lookup. - auto recordsBegin - = reinterpret_cast(conformances); - auto recordsEnd - = reinterpret_cast - (conformances + conformancesSize); - swift_registerProtocolConformances(recordsBegin, recordsEnd); -} - -#if defined(__APPLE__) && defined(__MACH__) -static void _addImageProtocolConformances(const mach_header *mh, - intptr_t vmaddr_slide) { -#ifdef __LP64__ - using mach_header_platform = mach_header_64; - assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); -#else - using mach_header_platform = mach_header; -#endif - - // Look for a __swift2_proto section. - unsigned long conformancesSize; - const uint8_t *conformances = - getsectiondata(reinterpret_cast(mh), - SEG_TEXT, SWIFT_PROTOCOL_CONFORMANCES_SECTION, - &conformancesSize); - - if (!conformances) - return; - - _addImageProtocolConformancesBlock(conformances, conformancesSize); -} -#elif defined(__ELF__) -static int _addImageProtocolConformances(struct dl_phdr_info *info, - size_t size, void * /*data*/) { - void *handle; - if (!info->dlpi_name || info->dlpi_name[0] == '\0') { - handle = dlopen(nullptr, RTLD_LAZY); - } else - handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); - auto conformances = reinterpret_cast( - dlsym(handle, SWIFT_PROTOCOL_CONFORMANCES_SECTION)); - - if (!conformances) { - // if there are no conformances, don't hold this handle open. - dlclose(handle); - return 0; - } - - // Extract the size of the conformances block from the head of the section - auto conformancesSize = *reinterpret_cast(conformances); - conformances += sizeof(conformancesSize); - - _addImageProtocolConformancesBlock(conformances, conformancesSize); - - dlclose(handle); - return 0; -} -#endif - -static void installCallbacksToInspectDylib() { - static OnceToken_t token; - auto callback = [](void*) { - #if defined(__APPLE__) && defined(__MACH__) - // Install our dyld callback if we haven't already. - // Dyld will invoke this on our behalf for all images that have already - // been loaded. - _dyld_register_func_for_add_image(_addImageProtocolConformances); - #elif defined(__ELF__) - // Search the loaded dls. Unlike the above, this only searches the already - // loaded ones. - // FIXME: Find a way to have this continue to happen after. - // rdar://problem/19045112 - dl_iterate_phdr(_addImageProtocolConformances, nullptr); - #else - # error No known mechanism to inspect dynamic libraries on this platform. - #endif - }; - - SWIFT_ONCE_F(token, callback, nullptr); -} - -static size_t hashTypeProtocolPair(const void *type, - const ProtocolDescriptor *protocol) { - // A simple hash function for the conformance pair. - return (size_t)type + ((size_t)protocol >> 2); -} - -/// Search the witness table in the ConformanceCache. \returns a pair of the -/// WitnessTable pointer and a boolean value True if a definitive value is -/// found. \returns false if the type or its superclasses were not found in -/// the cache. -static -std::pair -searchInConformanceCache(const Metadata *type, - const ProtocolDescriptor *protocol, - ConformanceCacheEntry *&foundEntry) { - auto &C = Conformances.get(); - auto origType = type; - - foundEntry = nullptr; - -recur_inside_cache_lock: - - // See if we have a cached conformance. Try the specific type first. - - // Hash and lookup the type-protocol pair in the cache. - size_t hash = hashTypeProtocolPair(type, protocol); - ConcurrentList &Bucket = - C.Cache.findOrAllocateNode(hash); - - // Check if the type-protocol entry exists in the cache entry that we found. - for (auto &Entry : Bucket) { - if (!Entry.matches(type, protocol)) continue; - - if (Entry.isSuccessful()) { - return std::make_pair(Entry.getWitnessTable(), true); - } - - if (type == origType) - foundEntry = &Entry; - - // If we got a cached negative response, check the generation number. - if (Entry.getFailureGeneration() == C.SectionsToScan.size()) { - // We found an entry with a negative value. - return std::make_pair(nullptr, true); - } - } - - // If the type is generic, see if there's a shared nondependent witness table - // for its instances. - if (auto generic = type->getGenericPattern()) { - // Hash and lookup the type-protocol pair in the cache. - size_t hash = hashTypeProtocolPair(generic, protocol); - ConcurrentList &Bucket = - C.Cache.findOrAllocateNode(hash); - - for (auto &Entry : Bucket) { - if (!Entry.matches(generic, protocol)) continue; - if (Entry.isSuccessful()) { - return std::make_pair(Entry.getWitnessTable(), true); - } - // We don't try to cache negative responses for generic - // patterns. - } - } - - // If the type is a class, try its superclass. - if (const ClassMetadata *classType = type->getClassObject()) { - if (auto super = classType->SuperClass) { - if (super != getRootSuperclass()) { - type = swift_getObjCClassMetadata(super); - goto recur_inside_cache_lock; - } - } - } - - // We did not find an entry. - return std::make_pair(nullptr, false); -} - -/// Checks if a given candidate is a type itself, one of its -/// superclasses or a related generic type. -/// This check is supposed to use the same logic that is used -/// by searchInConformanceCache. -static -bool isRelatedType(const Metadata *type, const void *candidate) { - - while (true) { - if (type == candidate) - return true; - - // If the type is generic, see if there's a shared nondependent witness table - // for its instances. - if (auto generic = type->getGenericPattern()) { - if (generic == candidate) - return true; - } - - // If the type is a class, try its superclass. - if (const ClassMetadata *classType = type->getClassObject()) { - if (auto super = classType->SuperClass) { - if (super != getRootSuperclass()) { - type = swift_getObjCClassMetadata(super); - if (type == candidate) - return true; - continue; - } - } - } - - break; - } - - return false; -} - -const WitnessTable * -swift::swift_conformsToProtocol(const Metadata *type, - const ProtocolDescriptor *protocol) { - auto &C = Conformances.get(); - - // Install callbacks for tracking when a new dylib is loaded so we can - // scan it. - installCallbacksToInspectDylib(); - auto origType = type; - - unsigned numSections = 0; - - ConformanceCacheEntry *foundEntry; - -recur: - // See if we have a cached conformance. The ConcurrentMap data structure - // allows us to insert and search the map concurrently without locking. - // We do lock the slow path because the SectionsToScan data structure is not - // concurrent. - auto FoundConformance = searchInConformanceCache(type, protocol, foundEntry); - // The negative answer does not always mean that there is no conformance, - // unless it is an exact match on the type. If it is not an exact match, - // it may mean that all of the superclasses do not have this conformance, - // but the actual type may still have this conformance. - if (FoundConformance.second) { - if (FoundConformance.first || foundEntry) - return FoundConformance.first; - } - - unsigned failedGeneration = ConformanceCacheGeneration; - - // If we didn't have an up-to-date cache entry, scan the conformance records. - pthread_mutex_lock(&C.SectionsToScanLock); - - // If we have no new information to pull in (and nobody else pulled in - // new information while we waited on the lock), we're done. - if (C.SectionsToScan.size() == numSections) { - if (failedGeneration != ConformanceCacheGeneration) { - // Someone else pulled in new conformances while we were waiting. - // Start over with our newly-populated cache. - pthread_mutex_unlock(&C.SectionsToScanLock); - type = origType; - goto recur; - } - - - // Hash and lookup the type-protocol pair in the cache. - size_t hash = hashTypeProtocolPair(type, protocol); - ConcurrentList &Bucket = - C.Cache.findOrAllocateNode(hash); - Bucket.push_front(ConformanceCacheEntry::createFailure( - type, protocol, C.SectionsToScan.size())); - pthread_mutex_unlock(&C.SectionsToScanLock); - return nullptr; - } - - // Update the last known number of sections to scan. - numSections = C.SectionsToScan.size(); - - // Scan only sections that were not scanned yet. - unsigned sectionIdx = foundEntry ? foundEntry->getFailureGeneration() : 0; - unsigned endSectionIdx = C.SectionsToScan.size(); - - for (; sectionIdx < endSectionIdx; ++sectionIdx) { - auto §ion = C.SectionsToScan[sectionIdx]; - // Eagerly pull records for nondependent witnesses into our cache. - for (const auto &record : section) { - // If the record applies to a specific type, cache it. - if (auto metadata = record.getCanonicalTypeMetadata()) { - auto P = record.getProtocol(); - - // Look for an exact match. - if (protocol != P) - continue; - - if (!isRelatedType(type, metadata)) - continue; - - // Hash and lookup the type-protocol pair in the cache. - size_t hash = hashTypeProtocolPair(metadata, P); - ConcurrentList &Bucket = - C.Cache.findOrAllocateNode(hash); - - auto witness = record.getWitnessTable(metadata); - if (witness) - Bucket.push_front( - ConformanceCacheEntry::createSuccess(metadata, P, witness)); - else - Bucket.push_front(ConformanceCacheEntry::createFailure( - metadata, P, C.SectionsToScan.size())); - - // If the record provides a nondependent witness table for all instances - // of a generic type, cache it for the generic pattern. - // TODO: "Nondependent witness table" probably deserves its own flag. - // An accessor function might still be necessary even if the witness table - // can be shared. - } else if (record.getTypeKind() - == ProtocolConformanceTypeKind::UniqueGenericPattern - && record.getConformanceKind() - == ProtocolConformanceReferenceKind::WitnessTable) { - - auto R = record.getGenericPattern(); - auto P = record.getProtocol(); - - // Look for an exact match. - if (protocol != P) - continue; - - if (!isRelatedType(type, R)) - continue; - - // Hash and lookup the type-protocol pair in the cache. - size_t hash = hashTypeProtocolPair(R, P); - ConcurrentList &Bucket = - C.Cache.findOrAllocateNode(hash); - Bucket.push_front(ConformanceCacheEntry::createSuccess( - R, P, record.getStaticWitnessTable())); - } - } - } - ++ConformanceCacheGeneration; - - pthread_mutex_unlock(&C.SectionsToScanLock); - // Start over with our newly-populated cache. - type = origType; - goto recur; -} - // The return type is incorrect. It is only important that it is // passed using 'sret'. extern "C" OpaqueExistentialContainer @@ -2769,7 +2227,7 @@ _TFs24_injectValueIntoOptionalU__FQ_GSqQ__(OpaqueValue *value, extern "C" OpaqueExistentialContainer _TFs26_injectNothingIntoOptionalU__FT_GSqQ__(const Metadata *T); -static inline bool swift_isClassOrObjCExistentialImpl(const Metadata *T) { +static inline bool swift_isClassOrObjCExistentialTypeImpl(const Metadata *T) { auto kind = T->getKind(); // Classes. if (Metadata::isAnyKindOfClass(kind)) @@ -3056,7 +2514,7 @@ findBridgeWitness(const Metadata *T) { extern "C" HeapObject *swift_bridgeNonVerbatimToObjectiveC( OpaqueValue *value, const Metadata *T ) { - assert(!swift_isClassOrObjCExistentialImpl(T)); + assert(!swift_isClassOrObjCExistentialTypeImpl(T)); if (const auto *bridgeWitness = findBridgeWitness(T)) { if (!bridgeWitness->isBridgedToObjectiveC(T, T)) { @@ -3079,7 +2537,7 @@ extern "C" const Metadata *swift_getBridgedNonVerbatimObjectiveCType( const Metadata *value, const Metadata *T ) { // Classes and Objective-C existentials bridge verbatim. - assert(!swift_isClassOrObjCExistentialImpl(T)); + assert(!swift_isClassOrObjCExistentialTypeImpl(T)); // Check if the type conforms to _BridgedToObjectiveC, in which case // we'll extract its associated type. @@ -3180,7 +2638,7 @@ swift_bridgeNonVerbatimFromObjectiveCConditional( extern "C" bool swift_isBridgedNonVerbatimToObjectiveC( const Metadata *value, const Metadata *T ) { - assert(!swift_isClassOrObjCExistentialImpl(T)); + assert(!swift_isClassOrObjCExistentialTypeImpl(T)); auto bridgeWitness = findBridgeWitness(T); return bridgeWitness && bridgeWitness->isBridgedToObjectiveC(value, T); @@ -3188,29 +2646,18 @@ extern "C" bool swift_isBridgedNonVerbatimToObjectiveC( #endif // func isClassOrObjCExistential(x: T.Type) -> Bool -extern "C" bool swift_isClassOrObjCExistential(const Metadata *value, +extern "C" bool swift_isClassOrObjCExistentialType(const Metadata *value, const Metadata *T) { - return swift_isClassOrObjCExistentialImpl(T); -} - -// func _swift_isClass(x: Any) -> Bool -extern "C" bool _swift_isClass(OpaqueExistentialContainer *value) { - bool Result = Metadata::isAnyKindOfClass(value->Type->getKind()); - - // Destroy value->Buffer since the Any is passed in at +1. - value->Type->vw_destroyBuffer(&value->Buffer); - - return Result; + return swift_isClassOrObjCExistentialTypeImpl(T); } -// func _swift_getSuperclass_nonNull(_: AnyClass) -> AnyClass? -extern "C" const Metadata *_swift_getSuperclass_nonNull( +// func swift_class_getSuperclass(_: AnyClass) -> AnyClass? +extern "C" const Metadata *swift_class_getSuperclass( const Metadata *theClass ) { if (const ClassMetadata *classType = theClass->getClassObject()) - if (auto super = classType->SuperClass) - if (super != getRootSuperclass()) - return swift_getObjCClassMetadata(super); + if (classHasSuperclass(classType)) + return swift_getObjCClassMetadata(classType->SuperClass); return nullptr; } diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp index c3554b87f60ae..857878783774b 100644 --- a/stdlib/public/runtime/Demangle.cpp +++ b/stdlib/public/runtime/Demangle.cpp @@ -1,2 +1,231 @@ #include "../../../lib/Basic/Demangle.cpp" #include "../../../lib/Basic/Punycode.cpp" +#include "swift/Runtime/Metadata.h" +#include "Private.h" + +#if SWIFT_OBJC_INTEROP + +#include + +// Build a demangled type tree for a nominal type. +static Demangle::NodePointer +_buildDemanglingForNominalType(Demangle::Node::Kind boundGenericKind, + const Metadata *type, + const NominalTypeDescriptor *description) { + using namespace Demangle; + + // Demangle the base name. + auto node = demangleTypeAsNode(description->Name, + strlen(description->Name)); + // If generic, demangle the type parameters. + if (description->GenericParams.NumPrimaryParams > 0) { + auto typeParams = NodeFactory::create(Node::Kind::TypeList); + auto typeBytes = reinterpret_cast(type); + auto genericParam = reinterpret_cast( + typeBytes + sizeof(void*) * description->GenericParams.Offset); + for (unsigned i = 0, e = description->GenericParams.NumPrimaryParams; + i < e; ++i, ++genericParam) { + auto demangling = _swift_buildDemanglingForMetadata(*genericParam); + if (demangling == nullptr) + return nullptr; + typeParams->addChild(demangling); + } + + auto genericNode = NodeFactory::create(boundGenericKind); + genericNode->addChild(node); + genericNode->addChild(typeParams); + return genericNode; + } + return node; +} + +// Build a demangled type tree for a type. +Demangle::NodePointer swift::_swift_buildDemanglingForMetadata(const Metadata *type) { + using namespace Demangle; + + switch (type->getKind()) { + case MetadataKind::Class: { + auto classType = static_cast(type); + return _buildDemanglingForNominalType(Node::Kind::BoundGenericClass, + type, classType->getDescription()); + } + case MetadataKind::Enum: + case MetadataKind::Optional: { + auto structType = static_cast(type); + return _buildDemanglingForNominalType(Node::Kind::BoundGenericEnum, + type, structType->Description); + } + case MetadataKind::Struct: { + auto structType = static_cast(type); + return _buildDemanglingForNominalType(Node::Kind::BoundGenericStructure, + type, structType->Description); + } + case MetadataKind::ObjCClassWrapper: { +#if SWIFT_OBJC_INTEROP + auto objcWrapper = static_cast(type); + const char *className = class_getName((Class)objcWrapper->Class); + + // ObjC classes mangle as being in the magic "__ObjC" module. + auto module = NodeFactory::create(Node::Kind::Module, "__ObjC"); + + auto node = NodeFactory::create(Node::Kind::Class); + node->addChild(module); + node->addChild(NodeFactory::create(Node::Kind::Identifier, + llvm::StringRef(className))); + + return node; +#else + assert(false && "no ObjC interop"); + return nullptr; +#endif + } + case MetadataKind::ForeignClass: { + auto foreign = static_cast(type); + return Demangle::demangleTypeAsNode(foreign->getName(), + strlen(foreign->getName())); + } + case MetadataKind::Existential: { + auto exis = static_cast(type); + NodePointer proto_list = NodeFactory::create(Node::Kind::ProtocolList); + NodePointer type_list = NodeFactory::create(Node::Kind::TypeList); + + proto_list->addChild(type_list); + + std::vector protocols; + protocols.reserve(exis->Protocols.NumProtocols); + for (unsigned i = 0, e = exis->Protocols.NumProtocols; i < e; ++i) + protocols.push_back(exis->Protocols[i]); + + // Sort the protocols by their mangled names. + // The ordering in the existential type metadata is by metadata pointer, + // which isn't necessarily stable across invocations. + std::sort(protocols.begin(), protocols.end(), + [](const ProtocolDescriptor *a, const ProtocolDescriptor *b) -> bool { + return strcmp(a->Name, b->Name) < 0; + }); + + for (auto *protocol : protocols) { + // The protocol name is mangled as a type symbol, with the _Tt prefix. + auto protocolNode = demangleSymbolAsNode(protocol->Name, + strlen(protocol->Name)); + + // ObjC protocol names aren't mangled. + if (!protocolNode) { + auto module = NodeFactory::create(Node::Kind::Module, + MANGLING_MODULE_OBJC); + auto node = NodeFactory::create(Node::Kind::Protocol); + node->addChild(module); + node->addChild(NodeFactory::create(Node::Kind::Identifier, + llvm::StringRef(protocol->Name))); + auto typeNode = NodeFactory::create(Node::Kind::Type); + typeNode->addChild(node); + type_list->addChild(typeNode); + continue; + } + + // FIXME: We have to dig through a ridiculous number of nodes to get + // to the Protocol node here. + protocolNode = protocolNode->getChild(0); // Global -> TypeMangling + protocolNode = protocolNode->getChild(0); // TypeMangling -> Type + protocolNode = protocolNode->getChild(0); // Type -> ProtocolList + protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList + protocolNode = protocolNode->getChild(0); // TypeList -> Type + + assert(protocolNode->getKind() == Node::Kind::Type); + assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol); + type_list->addChild(protocolNode); + } + + return proto_list; + } + case MetadataKind::ExistentialMetatype: { + auto metatype = static_cast(type); + auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType); + auto node = NodeFactory::create(Node::Kind::ExistentialMetatype); + node->addChild(instance); + return node; + } + case MetadataKind::Function: { + auto func = static_cast(type); + + Node::Kind kind; + switch (func->getConvention()) { + case FunctionMetadataConvention::Swift: + kind = Node::Kind::FunctionType; + break; + case FunctionMetadataConvention::Block: + kind = Node::Kind::ObjCBlock; + break; + case FunctionMetadataConvention::CFunctionPointer: + kind = Node::Kind::CFunctionPointer; + break; + case FunctionMetadataConvention::Thin: + kind = Node::Kind::ThinFunctionType; + break; + } + + std::vector inputs; + for (unsigned i = 0, e = func->getNumArguments(); i < e; ++i) { + auto arg = func->getArguments()[i]; + auto input = _swift_buildDemanglingForMetadata(arg.getPointer()); + if (arg.getFlag()) { + NodePointer inout = NodeFactory::create(Node::Kind::InOut); + inout->addChild(input); + input = inout; + } + inputs.push_back(input); + } + + NodePointer totalInput; + if (inputs.size() > 1) { + auto tuple = NodeFactory::create(Node::Kind::NonVariadicTuple); + for (auto &input : inputs) + tuple->addChild(input); + totalInput = tuple; + } else { + totalInput = inputs.front(); + } + + NodePointer args = NodeFactory::create(Node::Kind::ArgumentTuple); + args->addChild(totalInput); + + NodePointer resultTy = _swift_buildDemanglingForMetadata(func->ResultType); + NodePointer result = NodeFactory::create(Node::Kind::ReturnType); + result->addChild(resultTy); + + auto funcNode = NodeFactory::create(kind); + if (func->throws()) + funcNode->addChild(NodeFactory::create(Node::Kind::ThrowsAnnotation)); + funcNode->addChild(args); + funcNode->addChild(result); + return funcNode; + } + case MetadataKind::Metatype: { + auto metatype = static_cast(type); + auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType); + auto node = NodeFactory::create(Node::Kind::Metatype); + node->addChild(instance); + return node; + } + case MetadataKind::Tuple: { + auto tuple = static_cast(type); + auto tupleNode = NodeFactory::create(Node::Kind::NonVariadicTuple); + for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) { + auto elt = _swift_buildDemanglingForMetadata(tuple->getElement(i).Type); + tupleNode->addChild(elt); + } + return tupleNode; + } + case MetadataKind::Opaque: + // FIXME: Some opaque types do have manglings, but we don't have enough info + // to figure them out. + case MetadataKind::HeapLocalVariable: + case MetadataKind::HeapGenericLocalVariable: + case MetadataKind::ErrorObject: + break; + } + // Not a type. + return nullptr; +} + +#endif diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp index aa8e79654422e..43555b3e0cacf 100644 --- a/stdlib/public/runtime/Enum.cpp +++ b/stdlib/public/runtime/Enum.cpp @@ -1,8 +1,8 @@ -//===--- Enum.cpp - Runtime declarations for enums -----------*- C++ -*--===// +//===--- Enum.cpp - Runtime declarations for enums ------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/ErrorObject.cpp b/stdlib/public/runtime/ErrorObject.cpp index a12cbe075412b..20d3747aee84f 100644 --- a/stdlib/public/runtime/ErrorObject.cpp +++ b/stdlib/public/runtime/ErrorObject.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/ErrorObject.h b/stdlib/public/runtime/ErrorObject.h index 3ec36ed20c9df..62748b84eed51 100644 --- a/stdlib/public/runtime/ErrorObject.h +++ b/stdlib/public/runtime/ErrorObject.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -180,14 +180,6 @@ extern "C" void swift_unexpectedError(SwiftError *object) /// Initialize an ErrorType box to make it usable as an NSError instance. extern "C" id swift_bridgeErrorTypeToNSError(SwiftError *errorObject); -/// Convert an (optional) NSError instance to a (non-optional) -/// ErrorType box. -extern "C" SwiftError *swift_convertNSErrorToErrorType(id errorObject); - -/// Convert a (non-optional) ErrorType box to a (non-optional) -/// NSError instance. -extern "C" id swift_convertErrorTypeToNSError(SwiftError *errorObject); - /// Attempt to dynamically cast an NSError instance to a Swift ErrorType /// implementation using the _ObjectiveCBridgeableErrorType protocol. /// diff --git a/stdlib/public/runtime/ErrorObject.mm b/stdlib/public/runtime/ErrorObject.mm index 2902d0d96540b..851d194e908b7 100644 --- a/stdlib/public/runtime/ErrorObject.mm +++ b/stdlib/public/runtime/ErrorObject.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -313,23 +313,6 @@ static id _swift_bridgeErrorTypeToNSError_(SwiftError *errorObject) { return _swift_bridgeErrorTypeToNSError(errorObject); } -SwiftError * -swift::swift_convertNSErrorToErrorType(id errorObject) { - // The fast path is that we have a real error object. - if (errorObject) return reinterpret_cast(errorObject); - - // Unlike Objective-C, we can't just propagate nil errors around. - auto allocNilError = - (SwiftError*(*)()) dlsym(RTLD_DEFAULT, "swift_allocNilObjCError"); - assert(allocNilError && "didn't link Foundation overlay?"); - return allocNilError(); -} - -id swift::swift_convertErrorTypeToNSError(SwiftError *errorObject) { - assert(errorObject && "bridging a nil error!"); - return swift_bridgeErrorTypeToNSError(errorObject); -} - bool swift::tryDynamicCastNSErrorToValue(OpaqueValue *dest, OpaqueValue *src, diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 248bbcb2901d2..7b8aeb091929c 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -85,6 +85,12 @@ reportNow(const char *message) #endif } +/// Report a fatal error to system console, stderr, and crash logs. +/// Does not crash by itself. +void swift::swift_reportError(const char *message) { + reportNow(message); + reportOnCrash(message); +} // Report a fatal error to system console, stderr, and crash logs, then abort. LLVM_ATTRIBUTE_NORETURN @@ -97,89 +103,13 @@ swift::fatalError(const char *format, ...) char *log; vasprintf(&log, format, args); - reportNow(log); - reportOnCrash(log); - + swift_reportError(log); abort(); } - -// Report a fatal error to system console, stderr, and crash logs. -// : : file , line \n -// The message may be omitted by passing messageLength=0. -extern "C" void -swift_reportFatalErrorInFile(const char *prefix, intptr_t prefixLength, - const char *message, intptr_t messageLength, - const char *file, intptr_t fileLength, - uintptr_t line) { - char *log; - asprintf(&log, "%.*s: %.*s%sfile %.*s, line %zu\n", (int)prefixLength, prefix, - (int)messageLength, message, (messageLength ? ": " : ""), - (int)fileLength, file, (size_t)line); - - reportNow(log); - reportOnCrash(log); - - free(log); -} - -// Report a fatal error to system console, stderr, and crash logs. -// : : file , line \n -// The message may be omitted by passing messageLength=0. -extern "C" void swift_reportFatalError(const char *prefix, - intptr_t prefixLength, - const char *message, - intptr_t messageLength) { - char *log; - asprintf(&log, "%.*s: %.*s\n", (int)prefixLength, prefix, - (int)messageLength, message); - - reportNow(log); - reportOnCrash(log); - - free(log); -} - -// Report a call to an unimplemented initializer. -// : : : fatal error: use of unimplemented -// initializer '' for class 'className' -extern "C" void swift_reportUnimplementedInitializerInFile( - const char *className, intptr_t classNameLength, const char *initName, - intptr_t initNameLength, const char *file, intptr_t fileLength, - uintptr_t line, uintptr_t column) { - char *log; - asprintf(&log, "%.*s: %zu: %zu: fatal error: use of unimplemented " - "initializer '%.*s' for class '%.*s'\n", - (int)fileLength, file, (size_t)line, (size_t)column, - (int)initNameLength, initName, (int)classNameLength, className); - - reportNow(log); - reportOnCrash(log); - - free(log); -} - -// Report a call to an unimplemented initializer. -// fatal error: use of unimplemented initializer '' for class -// 'className' -extern "C" void swift_reportUnimplementedInitializer(const char *className, - intptr_t classNameLength, - const char *initName, - intptr_t initNameLength) { - char *log; - asprintf(&log, "fatal error: use of unimplemented " - "initializer '%.*s' for class '%.*s'\n", - (int)initNameLength, initName, (int)classNameLength, className); - - reportNow(log); - reportOnCrash(log); - - free(log); -} - -// Report a call to a removed method. +// Crash when a deleted method is called by accident. LLVM_ATTRIBUTE_NORETURN extern "C" void -swift_reportMissingMethod() { - swift::fatalError("fatal error: call of removed method\n"); +swift_deletedMethodError() { + swift::fatalError("fatal error: call of deleted method\n"); } diff --git a/stdlib/public/runtime/ExistentialMetadataImpl.h b/stdlib/public/runtime/ExistentialMetadataImpl.h index afa3c8e842a39..f91810bc834be 100644 --- a/stdlib/public/runtime/ExistentialMetadataImpl.h +++ b/stdlib/public/runtime/ExistentialMetadataImpl.h @@ -1,8 +1,8 @@ -//===--- ExistentialMetadataImpl.h - Existential metadata ------*- C++ -*--===// +//===--- ExistentialMetadataImpl.h - Existential metadata -------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -325,7 +325,7 @@ struct LLVM_LIBRARY_VISIBILITY ClassExistentialBox static constexpr size_t isBitwiseTakable = true; }; -/// A non-fixed box implementation class for an class existential +/// A non-fixed box implementation class for a class existential /// type with a dynamic number of witness tables. struct LLVM_LIBRARY_VISIBILITY NonFixedClassExistentialBox : ClassExistentialBoxBase { diff --git a/stdlib/public/runtime/Heap.cpp b/stdlib/public/runtime/Heap.cpp index 5480c02107c36..d82bbffdac8cf 100644 --- a/stdlib/public/runtime/Heap.cpp +++ b/stdlib/public/runtime/Heap.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 64c2d70b1c6dd..15f122b10d8b9 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -1,8 +1,8 @@ -//===--- Alloc.cpp - Swift Language ABI Allocation Support ----------------===// +//===--- HeapObject.cpp - Swift Language ABI Allocation Support -----------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -38,14 +38,6 @@ # include #include "swift/Runtime/ObjCBridge.h" #endif -#if SWIFT_RUNTIME_ENABLE_DTRACE -# include "SwiftRuntimeDTraceProbes.h" -#else -# define SWIFT_ALLOCATEOBJECT() -# define SWIFT_DEALLOCATEOBJECT() -# define SWIFT_RELEASE() -# define SWIFT_RETAIN() -#endif #include "Leaks.h" using namespace swift; @@ -54,7 +46,6 @@ HeapObject * swift::swift_allocObject(HeapMetadata const *metadata, size_t requiredSize, size_t requiredAlignmentMask) { - SWIFT_ALLOCATEOBJECT(); return _swift_allocObject(metadata, requiredSize, requiredAlignmentMask); } static HeapObject * @@ -105,8 +96,8 @@ extern "C" HeapObject* swift_bufferAllocate( } /// \brief Another entrypoint for swift_bufferAllocate. -/// It is generated by the compiler in some corner cases, e.g. if an serialized -/// optimzed module is imported into a non-optimized main module. +/// It is generated by the compiler in some corner cases, e.g. if a serialized +/// optimized module is imported into a non-optimized main module. /// TODO: This is only a workaround. Remove this function as soon as we can /// get rid of the llvm SwiftStackPromotion pass. extern "C" HeapObject* swift_bufferAllocateOnStack( @@ -116,8 +107,8 @@ extern "C" HeapObject* swift_bufferAllocateOnStack( /// \brief Called at the end of the lifetime of an object returned by /// swift_bufferAllocateOnStack. -/// It is generated by the compiler in some corner cases, e.g. if an serialized -/// optimzed module is imported into a non-optimized main module. +/// It is generated by the compiler in some corner cases, e.g. if a serialized +/// optimized module is imported into a non-optimized main module. /// TODO: This is only a workaround. Remove this function as soon as we can /// get rid of the llvm SwiftStackPromotion pass. extern "C" void swift_bufferDeallocateFromStack(HeapObject *) { @@ -125,55 +116,6 @@ extern "C" void swift_bufferDeallocateFromStack(HeapObject *) { extern "C" intptr_t swift_bufferHeaderSize() { return sizeof(HeapObject); } -/// A do-nothing destructor for POD metadata. -static void destroyPOD(HeapObject *o); - -/// Heap metadata for POD allocations. -static const FullMetadata PODHeapMetadata{ - HeapMetadataHeader{{destroyPOD}, {nullptr}}, - HeapMetadata{Metadata{MetadataKind::HeapLocalVariable}} -}; - -namespace { - /// Header for a POD allocation created by swift_allocPOD. - struct PODBox : HeapObject { - /// The size of the complete allocation. - size_t allocatedSize; - - /// The required alignment of the complete allocation. - size_t allocatedAlignMask; - - /// Returns the offset in bytes from the address of the header of a POD - /// allocation with the given size and alignment. - static size_t getValueOffset(size_t size, size_t alignMask) { - // llvm::RoundUpToAlignment(size, mask + 1) generates terrible code - return (sizeof(PODBox) + alignMask) & ~alignMask; - } - }; -} - -static void destroyPOD(HeapObject *o) { - auto box = static_cast(o); - // Deallocate the buffer. - return swift_deallocObject(box, box->allocatedSize, box->allocatedAlignMask); -} - -BoxPair::Return -swift::swift_allocPOD(size_t dataSize, size_t dataAlignmentMask) { - assert(isAlignmentMask(dataAlignmentMask)); - // Allocate the heap object. - size_t valueOffset = PODBox::getValueOffset(dataSize, dataAlignmentMask); - size_t size = valueOffset + dataSize; - size_t alignMask = std::max(dataAlignmentMask, alignof(HeapObject) - 1); - auto *obj = swift_allocObject(&PODHeapMetadata, size, alignMask); - // Initialize the header for the box. - static_cast(obj)->allocatedSize = size; - static_cast(obj)->allocatedAlignMask = alignMask; - // Get the address of the value inside. - auto *data = reinterpret_cast(obj) + valueOffset; - return BoxPair{obj, reinterpret_cast(data)}; -} - namespace { /// Heap metadata for a box, which may have been generated statically by the /// compiler or by the runtime. @@ -317,7 +259,6 @@ void _swift_release_dealloc(HeapObject *object) __attribute__((noinline,used)); void swift::swift_retain(HeapObject *object) { - SWIFT_RETAIN(); _swift_retain(object); } static void _swift_retain_(HeapObject *object) { @@ -326,7 +267,6 @@ static void _swift_retain_(HeapObject *object) { auto swift::_swift_retain = _swift_retain_; void swift::swift_retain_n(HeapObject *object, uint32_t n) { - SWIFT_RETAIN(); _swift_retain_n(object, n); } static void _swift_retain_n_(HeapObject *object, uint32_t n) { @@ -337,7 +277,6 @@ static void _swift_retain_n_(HeapObject *object, uint32_t n) { auto swift::_swift_retain_n = _swift_retain_n_; void swift::swift_release(HeapObject *object) { - SWIFT_RELEASE(); return _swift_release(object); } static void _swift_release_(HeapObject *object) { @@ -348,7 +287,6 @@ static void _swift_release_(HeapObject *object) { auto swift::_swift_release = _swift_release_; void swift::swift_release_n(HeapObject *object, uint32_t n) { - SWIFT_RELEASE(); return _swift_release_n(object, n); } static void _swift_release_n_(HeapObject *object, uint32_t n) { @@ -358,14 +296,6 @@ static void _swift_release_n_(HeapObject *object, uint32_t n) { } auto swift::_swift_release_n = _swift_release_n_; -size_t swift::swift_retainCount(HeapObject *object) { - return object->refCount.getCount(); -} - -size_t swift::swift_unownedRetainCount(HeapObject *object) { - return object->weakRefCount.getCount(); -} - void swift::swift_unownedRetain(HeapObject *object) { if (!object) return; @@ -546,7 +476,6 @@ static inline void memset_pattern8(void *b, const void *pattern8, size_t len) { void swift::swift_deallocObject(HeapObject *object, size_t allocatedSize, size_t allocatedAlignMask) { - SWIFT_DEALLOCATEOBJECT(); assert(isAlignmentMask(allocatedAlignMask)); assert(object->refCount.isDeallocating()); #ifdef SWIFT_RUNTIME_CLOBBER_FREED_OBJECTS @@ -630,11 +559,6 @@ void swift::swift_deallocObject(HeapObject *object, size_t allocatedSize, } } -/// This is a function that is opaque to the optimizer. It is called to ensure -/// that an object is alive at least until that time. -extern "C" void swift_fixLifetime(OpaqueValue *value) { -} - void swift::swift_weakInit(WeakReference *ref, HeapObject *value) { ref->Value = value; swift_unownedRetain(value); diff --git a/stdlib/public/runtime/KnownMetadata.cpp b/stdlib/public/runtime/KnownMetadata.cpp index 55eee7d38991b..c4fc1371a1d58 100644 --- a/stdlib/public/runtime/KnownMetadata.cpp +++ b/stdlib/public/runtime/KnownMetadata.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/Leaks.h b/stdlib/public/runtime/Leaks.h index a0685c3633558..868f2c26e8b07 100644 --- a/stdlib/public/runtime/Leaks.h +++ b/stdlib/public/runtime/Leaks.h @@ -1,8 +1,8 @@ -//===--- Leaks.h ----------------------------------------------------------===// +//===--- Leaks.h ------------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/Leaks.mm b/stdlib/public/runtime/Leaks.mm index 6cd80b1a12c04..de28d801c287a 100644 --- a/stdlib/public/runtime/Leaks.mm +++ b/stdlib/public/runtime/Leaks.mm @@ -1,8 +1,8 @@ -//===--- Leaks.mm ----------------------------------------*- C++ -*--------===// +//===--- Leaks.mm -----------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -140,7 +140,7 @@ static void dumpSwiftHeapObjects() { "\"name\": \"%s\", " "\"kind\": \"%s\"" "}", - NTD->Name, kindDescriptor); + NTD->Name.get(), kindDescriptor); continue; } diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index e4c358cdd1c4f..c0632436874bd 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -1,8 +1,8 @@ -//===--- Metadata.cpp - Swift Language ABI Metdata Support ----------------===// +//===--- Metadata.cpp - Swift Language ABI Metadata Support ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -264,42 +264,6 @@ swift::swift_getGenericMetadata(GenericMetadata *pattern, return entry->Value; } -/// Fast entry points. -const Metadata * -swift::swift_getGenericMetadata1(GenericMetadata *pattern, const void*argument){ - assert(pattern->NumKeyArguments == 1); - return swift_getGenericMetadata(pattern, &argument); -} - -const Metadata * -swift::swift_getGenericMetadata2(GenericMetadata *pattern, - const void *arg0, const void *arg1) { - const void *args[] = {arg0, arg1}; - assert(pattern->NumKeyArguments == 2); - return swift_getGenericMetadata(pattern, args); -} - -const Metadata * -swift::swift_getGenericMetadata3(GenericMetadata *pattern, - const void *arg0, - const void *arg1, - const void *arg2) { - const void *args[] = {arg0, arg1, arg2}; - assert(pattern->NumKeyArguments == 3); - return swift_getGenericMetadata(pattern, args); -} - -const Metadata * -swift::swift_getGenericMetadata4(GenericMetadata *pattern, - const void *arg0, - const void *arg1, - const void *arg2, - const void *arg3) { - const void *args[] = {arg0, arg1, arg2, arg3}; - assert(pattern->NumKeyArguments == 4); - return swift_getGenericMetadata(pattern, args); -} - namespace { class ObjCClassCacheEntry : public CacheEntry { FullMetadata Metadata; @@ -1457,24 +1421,105 @@ static uint32_t getLog2AlignmentFromMask(size_t alignMask) { log2++; return log2; } + +static inline ClassROData *getROData(ClassMetadata *theClass) { + return (ClassROData*) (theClass->Data & ~uintptr_t(1)); +} + +static void _swift_initGenericClassObjCName(ClassMetadata *theClass) { + // Use the remangler to generate a mangled name from the type metadata. + auto demangling = _swift_buildDemanglingForMetadata(theClass); + + // Remangle that into a new type mangling string. + auto typeNode + = Demangle::NodeFactory::create(Demangle::Node::Kind::TypeMangling); + typeNode->addChild(demangling); + auto globalNode + = Demangle::NodeFactory::create(Demangle::Node::Kind::Global); + globalNode->addChild(typeNode); + + auto string = Demangle::mangleNode(globalNode); + + auto fullNameBuf = (char*)swift_slowAlloc(string.size() + 1, 0); + memcpy(fullNameBuf, string.c_str(), string.size() + 1); + + auto theMetaclass = (ClassMetadata *)object_getClass((id)theClass); + + getROData(theClass)->Name = fullNameBuf; + getROData(theMetaclass)->Name = fullNameBuf; +} #endif +static void _swift_initializeSuperclass(ClassMetadata *theClass, + bool copyFieldOffsetVectors) { +#if SWIFT_OBJC_INTEROP + // If the class is generic, we need to give it a name for Objective-C. + if (theClass->getDescription()->GenericParams.NumParams > 0) + _swift_initGenericClassObjCName(theClass); +#endif + + const ClassMetadata *theSuperclass = theClass->SuperClass; + if (theSuperclass == nullptr) + return; + + // If any ancestors had generic parameters or field offset vectors, + // inherit them. + auto ancestor = theSuperclass; + auto *classWords = reinterpret_cast(theClass); + auto *superWords = reinterpret_cast(theSuperclass); + while (ancestor && ancestor->isTypeMetadata()) { + auto description = ancestor->getDescription(); + auto &genericParams = description->GenericParams; + if (genericParams.hasGenericParams()) { + unsigned numParamWords = 0; + for (unsigned i = 0; i < genericParams.NumParams; ++i) { + // 1 word for the type metadata, and 1 for every protocol witness + numParamWords += + 1 + genericParams.Parameters[i].NumWitnessTables; + } + memcpy(classWords + genericParams.Offset, + superWords + genericParams.Offset, + numParamWords * sizeof(uintptr_t)); + } + if (copyFieldOffsetVectors && + description->Class.hasFieldOffsetVector()) { + unsigned fieldOffsetVector = description->Class.FieldOffsetVectorOffset; + memcpy(classWords + fieldOffsetVector, + superWords + fieldOffsetVector, + description->Class.NumFields * sizeof(uintptr_t)); + } + ancestor = ancestor->SuperClass; + } + +#if SWIFT_OBJC_INTEROP + // Set up the superclass of the metaclass, which is the metaclass of the + // superclass. + auto theMetaclass = (ClassMetadata *)object_getClass((id)theClass); + auto theSuperMetaclass + = (const ClassMetadata *)object_getClass((id)theSuperclass); + theMetaclass->SuperClass = theSuperMetaclass; +#endif +} + /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, - const ClassMetadata *super, size_t numFields, const ClassFieldLayout *fieldLayouts, size_t *fieldOffsets) { + _swift_initializeSuperclass(self, /*copyFieldOffsetVectors=*/true); + // Start layout by appending to a standard heap object header. size_t size, alignMask; #if SWIFT_OBJC_INTEROP - ClassROData *rodata = (ClassROData*) (self->Data & ~uintptr_t(1)); + ClassROData *rodata = getROData(self); #endif // If we have a superclass, start from its size and alignment instead. - if (super) { + if (classHasSuperclass(self)) { + const ClassMetadata *super = self->SuperClass; + // This is straightforward if the superclass is Swift. #if SWIFT_OBJC_INTEROP if (super->isTypeMetadata()) { @@ -1552,7 +1597,7 @@ void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, rodata->InstanceStart = size; auto &allocator = unsafeGetInitializedCache( - self->getDescription()->GenericMetadataPattern) + self->getDescription()->getGenericMetadataPattern()) .getAllocator(); // Always clone the ivar descriptors. @@ -2140,7 +2185,7 @@ ExistentialTypeMetadata::getWitnessTable(const OpaqueValue *container, } // The return type here describes extra structure for the protocol - // witness table for some reason. We should probaby have a nominal + // witness table for some reason. We should probably have a nominal // type for these, just for type safety reasons. return witnessTables[i]; } @@ -2345,7 +2390,7 @@ Metadata::getGenericPattern() const { auto ntd = getNominalTypeDescriptor(); if (!ntd) return nullptr; - return ntd->GenericMetadataPattern; + return ntd->getGenericMetadataPattern(); } const ClassMetadata * @@ -2378,88 +2423,6 @@ Metadata::getClassObject() const { } } -/// Scan and return a single run-length encoded identifier. -/// Returns a malloc-allocated string, or nullptr on failure. -/// mangled is advanced past the end of the scanned token. -static char *scanIdentifier(const char *&mangled) -{ - const char *original = mangled; - - { - if (*mangled == '0') goto fail; // length may not be zero - - size_t length = 0; - while (Demangle::isDigit(*mangled)) { - size_t oldlength = length; - length *= 10; - length += *mangled++ - '0'; - if (length <= oldlength) goto fail; // integer overflow - } - - if (length == 0) goto fail; - if (length > strlen(mangled)) goto fail; - - char *result = strndup(mangled, length); - assert(result); - mangled += length; - return result; - } - -fail: - mangled = original; // rewind - return nullptr; -} - - -/// \brief Demangle a mangled class name into module+class. -/// Returns true if the name was successfully decoded. -/// On success, *outModule and *outClass must be freed with free(). -/// FIXME: this should be replaced by a real demangler -bool swift::swift_demangleSimpleClass(const char *mangledName, - char **outModule, char **outClass) { - char *moduleName = nullptr; - char *className = nullptr; - - { - // Prefix for a mangled class - const char *m = mangledName; - if (0 != strncmp(m, "_TtC", 4)) - goto fail; - m += 4; - - // Module name - if (strncmp(m, "Ss", 2) == 0) { - moduleName = strdup(swift::STDLIB_NAME); - assert(moduleName); - m += 2; - } else { - moduleName = scanIdentifier(m); - if (!moduleName) - goto fail; - } - - // Class name - className = scanIdentifier(m); - if (!className) - goto fail; - - // Nothing else - if (strlen(m)) - goto fail; - - *outModule = moduleName; - *outClass = className; - return true; - } - -fail: - if (moduleName) free(moduleName); - if (className) free(className); - *outModule = nullptr; - *outClass = nullptr; - return false; -} - #ifndef NDEBUG extern "C" void _swift_debug_verifyTypeLayoutAttribute(Metadata *type, @@ -2495,61 +2458,14 @@ void _swift_debug_verifyTypeLayoutAttribute(Metadata *type, extern "C" void swift_initializeSuperclass(ClassMetadata *theClass, - const ClassMetadata *theSuperclass) { - // We need a lock in order to ensure the class initialization and ObjC - // registration are atomic. - // TODO: A global lock for this is lame. - // TODO: A lock is also totally unnecessary for the non-objc runtime. - // Without ObjC registration, a release store of the superclass - // reference should be enough to dependency-order the other - // initialization steps. - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - - pthread_mutex_lock(&mutex); - - // Bail out if this already happened while we were waiting. - if (theClass->SuperClass) { - pthread_mutex_unlock(&mutex); - return; - } - - // Put the superclass reference in the base class. - theClass->SuperClass = theSuperclass; - - // If any ancestors had generic parameters, inherit them. - auto ancestor = theSuperclass; - auto *classWords = reinterpret_cast(theClass); - auto *superWords = reinterpret_cast(theSuperclass); - while (ancestor && ancestor->isTypeMetadata()) { - auto description = ancestor->getDescription(); - auto &genericParams = description->GenericParams; - if (genericParams.hasGenericParams()) { - unsigned numParamWords = 0; - for (unsigned i = 0; i < genericParams.NumParams; ++i) { - // 1 word for the type metadata, and 1 for every protocol witness - numParamWords += - 1 + genericParams.Parameters[i].NumWitnessTables; - } - memcpy(classWords + genericParams.Offset, - superWords + genericParams.Offset, - numParamWords * sizeof(uintptr_t)); - } - ancestor = ancestor->SuperClass; - } - + bool copyFieldOffsetVectors) { + // Copy generic parameters and field offset vectors from the superclass. + _swift_initializeSuperclass(theClass, copyFieldOffsetVectors); + #if SWIFT_OBJC_INTEROP - // Set up the superclass of the metaclass, which is the metaclass of the - // superclass. - auto theMetaclass = (ClassMetadata *)object_getClass((id)theClass); - auto theSuperMetaclass - = (const ClassMetadata *)object_getClass((id)theSuperclass); - theMetaclass->SuperClass = theSuperMetaclass; - // Register the class pair with the ObjC runtime. swift_instantiateObjCClass(theClass); #endif - - pthread_mutex_unlock(&mutex); } namespace llvm { namespace hashing { namespace detail { @@ -2558,3 +2474,65 @@ namespace llvm { namespace hashing { namespace detail { size_t fixed_seed_override = 0; } } } +/*** Protocol witness tables *************************************************/ + +namespace { + class WitnessTableCacheEntry : public CacheEntry { + public: + static const char *getName() { return "WitnessTableCache"; } + + WitnessTableCacheEntry(size_t numArguments) {} + + static constexpr size_t getNumArguments() { + return 1; + } + }; +} + +using GenericWitnessTableCache = MetadataCache; +using LazyGenericWitnessTableCache = Lazy; + +/// Fetch the cache for a generic witness-table structure. +static GenericWitnessTableCache &getCache(GenericWitnessTable *gen) { + // Keep this assert even if you change the representation above. + static_assert(sizeof(LazyGenericWitnessTableCache) <= + sizeof(GenericWitnessTable::PrivateData), + "metadata cache is larger than the allowed space"); + + auto lazyCache = + reinterpret_cast(gen->PrivateData); + return lazyCache->get(); +} + +extern "C" const WitnessTable * +swift::swift_getGenericWitnessTable(GenericWitnessTable *genericTable, + const Metadata *type, + void * const *instantiationArgs) { + // Search the cache. + constexpr const size_t numGenericArgs = 1; + const void *args[] = { type }; + auto &cache = getCache(genericTable); + auto entry = cache.findOrAdd(args, numGenericArgs, + [&]() -> WitnessTableCacheEntry* { + // Create a new entry for the cache. + auto entry = WitnessTableCacheEntry::allocate(cache.getAllocator(), + args, numGenericArgs, + genericTable->WitnessTableSizeInWords * sizeof(void*)); + + auto *table = entry->getData(); + memcpy((void**) table, (void* const *) &*genericTable->Pattern, + genericTable->WitnessTableSizeInWordsToCopy * sizeof(void*)); + bzero((void**) table + genericTable->WitnessTableSizeInWordsToCopy, + (genericTable->WitnessTableSizeInWords + - genericTable->WitnessTableSizeInWordsToCopy) * sizeof(void*)); + + // Call the instantiation function. + if (!genericTable->Instantiator.isNull()) { + genericTable->Instantiator(table, type, instantiationArgs); + } + + return entry; + }); + + return entry->getData(); +} diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 38049f0a56ec8..b83277ccc9e69 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -1,8 +1,8 @@ -//===--- MetadataCache.h - Implements the metadata cache -------*- C++ -*--===// +//===--- MetadataCache.h - Implements the metadata cache --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/MetadataImpl.h b/stdlib/public/runtime/MetadataImpl.h index e743e1416f824..f75f57d36f981 100644 --- a/stdlib/public/runtime/MetadataImpl.h +++ b/stdlib/public/runtime/MetadataImpl.h @@ -1,8 +1,8 @@ -//===--- MetadataImpl.h - Metadata implementation routines -----*- C++ -*--===// +//===--- MetadataImpl.h - Metadata implementation routines ------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp new file mode 100644 index 0000000000000..61981375e245b --- /dev/null +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -0,0 +1,320 @@ +//===--- MetadataLookup.cpp - Swift Language Type Name Lookup -------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Implementations of runtime functions for looking up a type by name. +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/LLVM.h" +#include "swift/Basic/Lazy.h" +#include "swift/Runtime/Concurrent.h" +#include "swift/Runtime/HeapObject.h" +#include "swift/Runtime/Metadata.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/StringExtras.h" +#include "Private.h" + +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#elif defined(__ELF__) +#include +#include +#endif + +#include +#include + +using namespace swift; +using namespace Demangle; + +#if SWIFT_OBJC_INTEROP +#include +#include +#include +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#define SWIFT_TYPE_METADATA_SECTION "__swift2_types" +#elif defined(__ELF__) +#define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" +#endif + +// Type Metadata Cache. + +namespace { + struct TypeMetadataSection { + const TypeMetadataRecord *Begin, *End; + const TypeMetadataRecord *begin() const { + return Begin; + } + const TypeMetadataRecord *end() const { + return End; + } + }; + + struct TypeMetadataCacheEntry { + private: + std::string Name; + const Metadata *Metadata; + + public: + TypeMetadataCacheEntry(const llvm::StringRef name, + const struct Metadata *metadata) { + Name = name.str(); + Metadata = metadata; + } + + bool matches(llvm::StringRef aName) { + return aName.equals(Name); + } + + const struct Metadata *getMetadata(void) { + return Metadata; + } + }; +} + +static void _initializeCallbacksToInspectDylib(); + +struct TypeMetadataState { + ConcurrentMap Cache; + std::vector SectionsToScan; + pthread_mutex_t SectionsToScanLock; + + TypeMetadataState() { + SectionsToScan.reserve(16); + pthread_mutex_init(&SectionsToScanLock, nullptr); + _initializeCallbacksToInspectDylib(); + } +}; + +static Lazy TypeMetadataRecords; + +static void +_registerTypeMetadataRecords(TypeMetadataState &T, + const TypeMetadataRecord *begin, + const TypeMetadataRecord *end) { + pthread_mutex_lock(&T.SectionsToScanLock); + T.SectionsToScan.push_back(TypeMetadataSection{begin, end}); + pthread_mutex_unlock(&T.SectionsToScanLock); +} + +static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, + size_t recordsSize) { + assert(recordsSize % sizeof(TypeMetadataRecord) == 0 + && "weird-sized type metadata section?!"); + + // If we have a section, enqueue the type metadata for lookup. + auto recordsBegin + = reinterpret_cast(records); + auto recordsEnd + = reinterpret_cast + (records + recordsSize); + + // type metadata cache should always be sufficiently initialized by this point. + _registerTypeMetadataRecords(TypeMetadataRecords.unsafeGetAlreadyInitialized(), + recordsBegin, recordsEnd); +} + +#if defined(__APPLE__) && defined(__MACH__) +static void _addImageTypeMetadataRecords(const mach_header *mh, + intptr_t vmaddr_slide) { +#ifdef __LP64__ + using mach_header_platform = mach_header_64; + assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); +#else + using mach_header_platform = mach_header; +#endif + + // Look for a __swift2_types section. + unsigned long recordsSize; + const uint8_t *records = + getsectiondata(reinterpret_cast(mh), + SEG_TEXT, SWIFT_TYPE_METADATA_SECTION, + &recordsSize); + + if (!records) + return; + + _addImageTypeMetadataRecordsBlock(records, recordsSize); +} +#elif defined(__ELF__) +static int _addImageTypeMetadataRecords(struct dl_phdr_info *info, + size_t size, void * /*data*/) { + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') { + handle = dlopen(nullptr, RTLD_LAZY); + } else + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); + auto records = reinterpret_cast( + dlsym(handle, SWIFT_TYPE_METADATA_SECTION)); + + if (!records) { + // if there are no type metadata records, don't hold this handle open. + dlclose(handle); + return 0; + } + + // Extract the size of the type metadata block from the head of the section + auto recordsSize = *reinterpret_cast(records); + records += sizeof(recordsSize); + + _addImageTypeMetadataRecordsBlock(records, recordsSize); + + dlclose(handle); + return 0; +} +#endif + +static void _initializeCallbacksToInspectDylib() { +#if defined(__APPLE__) && defined(__MACH__) + // Install our dyld callback. + // Dyld will invoke this on our behalf for all images that have already + // been loaded. + _dyld_register_func_for_add_image(_addImageTypeMetadataRecords); +#elif defined(__ELF__) + // Search the loaded dls. Unlike the above, this only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen after. + // rdar://problem/19045112 + dl_iterate_phdr(_addImageTypeMetadataRecords, nullptr); +#else +# error No known mechanism to inspect dynamic libraries on this platform. +#endif +} + +void +swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, + const TypeMetadataRecord *end) { + auto &T = TypeMetadataRecords.get(); + _registerTypeMetadataRecords(T, begin, end); +} + +// copied from ProtocolConformanceRecord::getCanonicalTypeMetadata() +const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const { + switch (getTypeKind()) { + case TypeMetadataRecordKind::UniqueDirectType: + return getDirectType(); + case TypeMetadataRecordKind::NonuniqueDirectType: + return swift_getForeignTypeMetadata((ForeignTypeMetadata *)getDirectType()); + case TypeMetadataRecordKind::UniqueDirectClass: + if (auto *ClassMetadata = + static_cast(getDirectType())) + return swift_getObjCClassMetadata(ClassMetadata); + else + return nullptr; + default: + return nullptr; + } +} + +// returns the type metadata for the type named by typeNode +const Metadata * +swift::_matchMetadataByMangledTypeName(const llvm::StringRef typeName, + const Metadata *metadata, + const NominalTypeDescriptor *ntd) { + if (metadata != nullptr) { + assert(ntd == nullptr); + ntd = metadata->getNominalTypeDescriptor(); + } + + if (ntd == nullptr || ntd->Name.get() != typeName) + return nullptr; + + // Instantiate resilient types. + if (metadata == nullptr && + ntd->getGenericMetadataPattern() && + !ntd->GenericParams.hasGenericParams()) { + return swift_getResilientMetadata(ntd->getGenericMetadataPattern()); + } + + return metadata; +} + +// returns the type metadata for the type named by typeName +static const Metadata * +_searchTypeMetadataRecords(const TypeMetadataState &T, + const llvm::StringRef typeName) { + unsigned sectionIdx = 0; + unsigned endSectionIdx = T.SectionsToScan.size(); + const Metadata *foundMetadata = nullptr; + + for (; sectionIdx < endSectionIdx; ++sectionIdx) { + auto §ion = T.SectionsToScan[sectionIdx]; + for (const auto &record : section) { + if (auto metadata = record.getCanonicalTypeMetadata()) + foundMetadata = _matchMetadataByMangledTypeName(typeName, metadata, nullptr); + else if (auto ntd = record.getNominalTypeDescriptor()) + foundMetadata = _matchMetadataByMangledTypeName(typeName, nullptr, ntd); + + if (foundMetadata != nullptr) + return foundMetadata; + } + } + + return nullptr; +} + +static const Metadata * +_typeByMangledName(const llvm::StringRef typeName) { + const Metadata *foundMetadata = nullptr; + auto &T = TypeMetadataRecords.get(); + size_t hash = llvm::HashString(typeName); + + ConcurrentList &Bucket = T.Cache.findOrAllocateNode(hash); + + // Check name to type metadata cache + for (auto &Entry : Bucket) { + if (Entry.matches(typeName)) + return Entry.getMetadata(); + } + + // Check type metadata records + pthread_mutex_lock(&T.SectionsToScanLock); + foundMetadata = _searchTypeMetadataRecords(T, typeName); + pthread_mutex_unlock(&T.SectionsToScanLock); + + // Check protocol conformances table. Note that this has no support for + // resolving generic types yet. + if (foundMetadata == nullptr) + foundMetadata = _searchConformancesByMangledTypeName(typeName); + + if (foundMetadata != nullptr) + Bucket.push_front(TypeMetadataCacheEntry(typeName, foundMetadata)); + +#if SWIFT_OBJC_INTEROP + // Check for ObjC class + // FIXME does this have any value? any ObjC class with a Swift name + // should already be registered as a Swift type. + if (foundMetadata == nullptr) { + std::string prefixedName("_Tt" + typeName.str()); + foundMetadata = reinterpret_cast + (objc_lookUpClass(prefixedName.c_str())); + } +#endif + + return foundMetadata; +} + +/// Return the type metadata for a given mangled name, used in the +/// implementation of _typeByName(). The human readable name returned +/// by swift_getTypeName() is non-unique, so we used mangled names +/// internally. +extern "C" +const Metadata * +swift_getTypeByMangledName(const char *typeName, size_t typeNameLength) { + llvm::StringRef name(typeName, typeNameLength); + return _typeByMangledName(name); +} diff --git a/stdlib/public/runtime/Once.cpp b/stdlib/public/runtime/Once.cpp index ee8f691156ba2..5fea28dd1ab66 100644 --- a/stdlib/public/runtime/Once.cpp +++ b/stdlib/public/runtime/Once.cpp @@ -1,8 +1,8 @@ -//===--- Once.cpp - Runtime support for lazy initialization ----------------==// +//===--- Once.cpp - Runtime support for lazy initialization ---------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,7 @@ using namespace swift; #ifdef __APPLE__ -// On OS X and and iOS, swift_once is implemented using GCD. +// On OS X and iOS, swift_once is implemented using GCD. #include static_assert(std::is_same::value, diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 0a66df2e16843..cdb7887d3b220 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -1,8 +1,8 @@ -//===--- Private.h - Private runtime declarations --------------*- C++ -*--===// +//===--- Private.h - Private runtime declarations ---------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -17,6 +17,7 @@ #ifndef SWIFT_RUNTIME_PRIVATE_H #define SWIFT_RUNTIME_PRIVATE_H +#include "swift/Basic/Demangle.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Metadata.h" #include "llvm/Support/Compiler.h" @@ -29,12 +30,10 @@ namespace swift { #endif #if SWIFT_OBJC_INTEROP - extern "C" LLVM_LIBRARY_VISIBILITY - bool _swift_objectConformsToObjCProtocol(const void *theObject, + bool objectConformsToObjCProtocol(const void *theObject, const ProtocolDescriptor *theProtocol); - extern "C" LLVM_LIBRARY_VISIBILITY - bool _swift_classConformsToObjCProtocol(const void *theClass, + bool classConformsToObjCProtocol(const void *theClass, const ProtocolDescriptor *theProtocol); #endif @@ -95,7 +94,13 @@ namespace swift { /// Note that this function may return a nullptr on non-objc platforms, /// where there is no common root class. rdar://problem/18987058 const ClassMetadata *getRootSuperclass(); - + + /// Check if a class has a formal superclass in the AST. + static inline + bool classHasSuperclass(const ClassMetadata *c) { + return (c->SuperClass && c->SuperClass != getRootSuperclass()); + } + /// Replace entries of a freshly-instantiated value witness table with more /// efficient common implementations where applicable. /// @@ -106,6 +111,17 @@ namespace swift { /// Returns true if common value witnesses were used, false otherwise. void installCommonValueWitnesses(ValueWitnessTable *vwtable); + const Metadata * + _matchMetadataByMangledTypeName(const llvm::StringRef metadataNameRef, + const Metadata *metadata, + const NominalTypeDescriptor *ntd); + + const Metadata * + _searchConformancesByMangledTypeName(const llvm::StringRef typeName); + +#if SWIFT_OBJC_INTEROP + Demangle::NodePointer _swift_buildDemanglingForMetadata(const Metadata *type); +#endif } // end namespace swift diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp new file mode 100644 index 0000000000000..fc08f83e0aa3f --- /dev/null +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -0,0 +1,633 @@ +//===--- ProtocolConformance.cpp - Swift protocol conformance checking ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Checking and caching of Swift protocol conformances. +// +//===----------------------------------------------------------------------===// + +#include "swift/Basic/LLVM.h" +#include "swift/Basic/Lazy.h" +#include "swift/Runtime/Concurrent.h" +#include "swift/Runtime/Metadata.h" +#include "Private.h" + +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#elif defined(__ELF__) +#include +#include +#endif + +#include +#include + +using namespace swift; + + +#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP +#include + +static const char *class_getName(const ClassMetadata* type) { + return class_getName( + reinterpret_cast(const_cast(type))); +} + +void ProtocolConformanceRecord::dump() const { + auto symbolName = [&](const void *addr) -> const char * { + Dl_info info; + int ok = dladdr(addr, &info); + if (!ok) + return ""; + return info.dli_sname; + }; + + switch (auto kind = getTypeKind()) { + case TypeMetadataRecordKind::Universal: + printf("universal"); + break; + case TypeMetadataRecordKind::UniqueDirectType: + case TypeMetadataRecordKind::NonuniqueDirectType: + printf("%s direct type ", + kind == TypeMetadataRecordKind::UniqueDirectType + ? "unique" : "nonunique"); + if (auto ntd = getDirectType()->getNominalTypeDescriptor()) { + printf("%s", ntd->Name.get()); + } else { + printf(""); + } + break; + case TypeMetadataRecordKind::UniqueDirectClass: + printf("unique direct class %s", + class_getName(getDirectClass())); + break; + case TypeMetadataRecordKind::UniqueIndirectClass: + printf("unique indirect class %s", + class_getName(*getIndirectClass())); + break; + + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: + printf("unique nominal type descriptor %s", symbolName(getNominalTypeDescriptor())); + break; + } + + printf(" => "); + + switch (getConformanceKind()) { + case ProtocolConformanceReferenceKind::WitnessTable: + printf("witness table %s\n", symbolName(getStaticWitnessTable())); + break; + case ProtocolConformanceReferenceKind::WitnessTableAccessor: + printf("witness table accessor %s\n", + symbolName((const void *)(uintptr_t)getWitnessTableAccessor())); + break; + } +} +#endif + +/// Take the type reference inside a protocol conformance record and fetch the +/// canonical metadata pointer for the type it refers to. +/// Returns nil for universal or generic type references. +const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata() +const { + switch (getTypeKind()) { + case TypeMetadataRecordKind::UniqueDirectType: + // Already unique. + return getDirectType(); + case TypeMetadataRecordKind::NonuniqueDirectType: + // Ask the runtime for the unique metadata record we've canonized. + return swift_getForeignTypeMetadata((ForeignTypeMetadata*)getDirectType()); + case TypeMetadataRecordKind::UniqueIndirectClass: + // The class may be ObjC, in which case we need to instantiate its Swift + // metadata. The class additionally may be weak-linked, so we have to check + // for null. + if (auto *ClassMetadata = *getIndirectClass()) + return swift_getObjCClassMetadata(ClassMetadata); + return nullptr; + + case TypeMetadataRecordKind::UniqueDirectClass: + // The class may be ObjC, in which case we need to instantiate its Swift + // metadata. + if (auto *ClassMetadata = getDirectClass()) + return swift_getObjCClassMetadata(ClassMetadata); + return nullptr; + + case TypeMetadataRecordKind::UniqueNominalTypeDescriptor: + case TypeMetadataRecordKind::Universal: + // The record does not apply to a single type. + return nullptr; + } +} + +const WitnessTable *ProtocolConformanceRecord::getWitnessTable(const Metadata *type) +const { + switch (getConformanceKind()) { + case ProtocolConformanceReferenceKind::WitnessTable: + return getStaticWitnessTable(); + + case ProtocolConformanceReferenceKind::WitnessTableAccessor: + return getWitnessTableAccessor()(type); + } +} + +#if defined(__APPLE__) && defined(__MACH__) +#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" +#elif defined(__ELF__) +#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" +#endif + +namespace { + struct ConformanceSection { + const ProtocolConformanceRecord *Begin, *End; + const ProtocolConformanceRecord *begin() const { + return Begin; + } + const ProtocolConformanceRecord *end() const { + return End; + } + }; + + struct ConformanceCacheEntry { + private: + const void *Type; + const ProtocolDescriptor *Proto; + uintptr_t Data; + // All Darwin 64-bit platforms reserve the low 2^32 of address space, which + // is more than enough invalid pointer values for any realistic generation + // number. It's a little easier to overflow on 32-bit, so we need an extra + // bit there. +#if !__LP64__ + bool Success; +#endif + + ConformanceCacheEntry(const void *type, + const ProtocolDescriptor *proto, + uintptr_t Data, bool Success) + : Type(type), Proto(proto), Data(Data) +#if !__LP64__ + , Success(Success) +#endif + { +#if __LP64__ +# if __APPLE__ + assert((!Success && Data <= 0xFFFFFFFFU) || + (Success && Data > 0xFFFFFFFFU)); +# elif __linux__ || __FreeBSD__ + assert((!Success && Data <= 0x0FFFU) || + (Success && Data > 0x0FFFU)); +# else +# error "port me" +# endif +#endif + } + + public: + ConformanceCacheEntry() = default; + + static ConformanceCacheEntry createSuccess( + const void *type, const ProtocolDescriptor *proto, + const swift::WitnessTable *witness) { + return ConformanceCacheEntry(type, proto, (uintptr_t) witness, true); + } + + static ConformanceCacheEntry createFailure( + const void *type, const ProtocolDescriptor *proto, + unsigned failureGeneration) { + return ConformanceCacheEntry(type, proto, (uintptr_t) failureGeneration, + false); + } + + /// \returns true if the entry represents an entry for the pair \p type + /// and \p proto. + bool matches(const void *type, const ProtocolDescriptor *proto) { + return type == Type && Proto == proto; + } + + bool isSuccessful() const { +#if __LP64__ +# if __APPLE__ + return Data > 0xFFFFFFFFU; +# elif __linux__ || __FreeBSD__ + return Data > 0x0FFFU; +# else +# error "port me" +# endif +#else + return Success; +#endif + } + + /// Get the cached witness table, if successful. + const WitnessTable *getWitnessTable() const { + assert(isSuccessful()); + return (const WitnessTable *)Data; + } + + /// Get the generation number under which this lookup failed. + unsigned getFailureGeneration() const { + assert(!isSuccessful()); + return Data; + } + }; +} + +// Conformance Cache. + +static void _initializeCallbacksToInspectDylib(); + +struct ConformanceState { + ConcurrentMap Cache; + std::vector SectionsToScan; + pthread_mutex_t SectionsToScanLock; + + ConformanceState() { + SectionsToScan.reserve(16); + pthread_mutex_init(&SectionsToScanLock, nullptr); + _initializeCallbacksToInspectDylib(); + } +}; + +static Lazy Conformances; + +static void +_registerProtocolConformances(ConformanceState &C, + const ProtocolConformanceRecord *begin, + const ProtocolConformanceRecord *end) { + pthread_mutex_lock(&C.SectionsToScanLock); + C.SectionsToScan.push_back(ConformanceSection{begin, end}); + pthread_mutex_unlock(&C.SectionsToScanLock); +} + +static void _addImageProtocolConformancesBlock(const uint8_t *conformances, + size_t conformancesSize) { + assert(conformancesSize % sizeof(ProtocolConformanceRecord) == 0 + && "weird-sized conformances section?!"); + + // If we have a section, enqueue the conformances for lookup. + auto recordsBegin + = reinterpret_cast(conformances); + auto recordsEnd + = reinterpret_cast + (conformances + conformancesSize); + + // Conformance cache should always be sufficiently initialized by this point. + _registerProtocolConformances(Conformances.unsafeGetAlreadyInitialized(), + recordsBegin, recordsEnd); +} + +#if defined(__APPLE__) && defined(__MACH__) +static void _addImageProtocolConformances(const mach_header *mh, + intptr_t vmaddr_slide) { +#ifdef __LP64__ + using mach_header_platform = mach_header_64; + assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); +#else + using mach_header_platform = mach_header; +#endif + + // Look for a __swift2_proto section. + unsigned long conformancesSize; + const uint8_t *conformances = + getsectiondata(reinterpret_cast(mh), + SEG_TEXT, SWIFT_PROTOCOL_CONFORMANCES_SECTION, + &conformancesSize); + + if (!conformances) + return; + + _addImageProtocolConformancesBlock(conformances, conformancesSize); +} +#elif defined(__ELF__) +static int _addImageProtocolConformances(struct dl_phdr_info *info, + size_t size, void * /*data*/) { + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') { + handle = dlopen(nullptr, RTLD_LAZY); + } else + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); + auto conformances = reinterpret_cast( + dlsym(handle, SWIFT_PROTOCOL_CONFORMANCES_SECTION)); + + if (!conformances) { + // if there are no conformances, don't hold this handle open. + dlclose(handle); + return 0; + } + + // Extract the size of the conformances block from the head of the section + auto conformancesSize = *reinterpret_cast(conformances); + conformances += sizeof(conformancesSize); + + _addImageProtocolConformancesBlock(conformances, conformancesSize); + + dlclose(handle); + return 0; +} +#endif + +static void _initializeCallbacksToInspectDylib() { +#if defined(__APPLE__) && defined(__MACH__) + // Install our dyld callback. + // Dyld will invoke this on our behalf for all images that have already + // been loaded. + _dyld_register_func_for_add_image(_addImageProtocolConformances); +#elif defined(__ELF__) + // Search the loaded dls. Unlike the above, this only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen after. + // rdar://problem/19045112 + dl_iterate_phdr(_addImageProtocolConformances, nullptr); +#else +# error No known mechanism to inspect dynamic libraries on this platform. +#endif +} + +// This variable is used to signal when a cache was generated and +// it is correct to avoid a new scan. +static unsigned ConformanceCacheGeneration = 0; + +void +swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin, + const ProtocolConformanceRecord *end){ + auto &C = Conformances.get(); + _registerProtocolConformances(C, begin, end); +} + +static size_t hashTypeProtocolPair(const void *type, + const ProtocolDescriptor *protocol) { + // A simple hash function for the conformance pair. + return (size_t)type + ((size_t)protocol >> 2); +} + +/// Search the witness table in the ConformanceCache. \returns a pair of the +/// WitnessTable pointer and a boolean value True if a definitive value is +/// found. \returns false if the type or its superclasses were not found in +/// the cache. +static +std::pair +searchInConformanceCache(const Metadata *type, + const ProtocolDescriptor *protocol, + ConformanceCacheEntry *&foundEntry) { + auto &C = Conformances.get(); + auto origType = type; + + foundEntry = nullptr; + +recur_inside_cache_lock: + + // See if we have a cached conformance. Try the specific type first. + + { + // Hash and lookup the type-protocol pair in the cache. + size_t hash = hashTypeProtocolPair(type, protocol); + ConcurrentList &Bucket = + C.Cache.findOrAllocateNode(hash); + + // Check if the type-protocol entry exists in the cache entry that we found. + for (auto &Entry : Bucket) { + if (!Entry.matches(type, protocol)) continue; + + if (Entry.isSuccessful()) { + return std::make_pair(Entry.getWitnessTable(), true); + } + + if (type == origType) + foundEntry = &Entry; + + // If we got a cached negative response, check the generation number. + if (Entry.getFailureGeneration() == C.SectionsToScan.size()) { + // We found an entry with a negative value. + return std::make_pair(nullptr, true); + } + } + } + + { + // For generic and resilient types, nondependent conformances + // are keyed by the nominal type descriptor rather than the + // metadata, so try that. + auto *description = type->getNominalTypeDescriptor(); + + // Hash and lookup the type-protocol pair in the cache. + size_t hash = hashTypeProtocolPair(description, protocol); + ConcurrentList &Bucket = + C.Cache.findOrAllocateNode(hash); + + for (auto &Entry : Bucket) { + if (!Entry.matches(description, protocol)) continue; + if (Entry.isSuccessful()) { + return std::make_pair(Entry.getWitnessTable(), true); + } + // We don't try to cache negative responses for generic + // patterns. + } + } + + // If the type is a class, try its superclass. + if (const ClassMetadata *classType = type->getClassObject()) { + if (classHasSuperclass(classType)) { + type = swift_getObjCClassMetadata(classType->SuperClass); + goto recur_inside_cache_lock; + } + } + + // We did not find an entry. + return std::make_pair(nullptr, false); +} + +/// Checks if a given candidate is a type itself, one of its +/// superclasses or a related generic type. +/// +/// This check is supposed to use the same logic that is used +/// by searchInConformanceCache. +/// +/// \param candidate Pointer to a Metadata or a NominalTypeDescriptor. +/// +static +bool isRelatedType(const Metadata *type, const void *candidate, + bool candidateIsMetadata) { + + while (true) { + if (type == candidate && candidateIsMetadata) + return true; + + // If the type is resilient or generic, see if there's a witness table + // keyed off the nominal type descriptor. + auto *description = type->getNominalTypeDescriptor(); + if (description == candidate && !candidateIsMetadata) + return true; + + // If the type is a class, try its superclass. + if (const ClassMetadata *classType = type->getClassObject()) { + if (classHasSuperclass(classType)) { + type = swift_getObjCClassMetadata(classType->SuperClass); + continue; + } + } + + break; + } + + return false; +} + +const WitnessTable * +swift::swift_conformsToProtocol(const Metadata *type, + const ProtocolDescriptor *protocol) { + auto &C = Conformances.get(); + auto origType = type; + unsigned numSections = 0; + ConformanceCacheEntry *foundEntry; + +recur: + // See if we have a cached conformance. The ConcurrentMap data structure + // allows us to insert and search the map concurrently without locking. + // We do lock the slow path because the SectionsToScan data structure is not + // concurrent. + auto FoundConformance = searchInConformanceCache(type, protocol, foundEntry); + // The negative answer does not always mean that there is no conformance, + // unless it is an exact match on the type. If it is not an exact match, + // it may mean that all of the superclasses do not have this conformance, + // but the actual type may still have this conformance. + if (FoundConformance.second) { + if (FoundConformance.first || foundEntry) + return FoundConformance.first; + } + + unsigned failedGeneration = ConformanceCacheGeneration; + + // If we didn't have an up-to-date cache entry, scan the conformance records. + pthread_mutex_lock(&C.SectionsToScanLock); + + // If we have no new information to pull in (and nobody else pulled in + // new information while we waited on the lock), we're done. + if (C.SectionsToScan.size() == numSections) { + if (failedGeneration != ConformanceCacheGeneration) { + // Someone else pulled in new conformances while we were waiting. + // Start over with our newly-populated cache. + pthread_mutex_unlock(&C.SectionsToScanLock); + type = origType; + goto recur; + } + + + // Hash and lookup the type-protocol pair in the cache. + size_t hash = hashTypeProtocolPair(type, protocol); + ConcurrentList &Bucket = + C.Cache.findOrAllocateNode(hash); + Bucket.push_front(ConformanceCacheEntry::createFailure( + type, protocol, C.SectionsToScan.size())); + pthread_mutex_unlock(&C.SectionsToScanLock); + return nullptr; + } + + // Update the last known number of sections to scan. + numSections = C.SectionsToScan.size(); + + // Scan only sections that were not scanned yet. + unsigned sectionIdx = foundEntry ? foundEntry->getFailureGeneration() : 0; + unsigned endSectionIdx = C.SectionsToScan.size(); + + for (; sectionIdx < endSectionIdx; ++sectionIdx) { + auto §ion = C.SectionsToScan[sectionIdx]; + // Eagerly pull records for nondependent witnesses into our cache. + for (const auto &record : section) { + // If the record applies to a specific type, cache it. + if (auto metadata = record.getCanonicalTypeMetadata()) { + auto P = record.getProtocol(); + + // Look for an exact match. + if (protocol != P) + continue; + + if (!isRelatedType(type, metadata, /*isMetadata=*/true)) + continue; + + // Hash and lookup the type-protocol pair in the cache. + size_t hash = hashTypeProtocolPair(metadata, P); + ConcurrentList &Bucket = + C.Cache.findOrAllocateNode(hash); + + auto witness = record.getWitnessTable(metadata); + if (witness) + Bucket.push_front( + ConformanceCacheEntry::createSuccess(metadata, P, witness)); + else + Bucket.push_front(ConformanceCacheEntry::createFailure( + metadata, P, C.SectionsToScan.size())); + + // If the record provides a nondependent witness table for all instances + // of a generic type, cache it for the generic pattern. + // TODO: "Nondependent witness table" probably deserves its own flag. + // An accessor function might still be necessary even if the witness table + // can be shared. + } else if (record.getTypeKind() + == TypeMetadataRecordKind::UniqueNominalTypeDescriptor + && record.getConformanceKind() + == ProtocolConformanceReferenceKind::WitnessTable) { + + auto R = record.getNominalTypeDescriptor(); + auto P = record.getProtocol(); + + // Look for an exact match. + if (protocol != P) + continue; + + if (!isRelatedType(type, R, /*isMetadata=*/false)) + continue; + + // Hash and lookup the type-protocol pair in the cache. + size_t hash = hashTypeProtocolPair(R, P); + ConcurrentList &Bucket = + C.Cache.findOrAllocateNode(hash); + Bucket.push_front(ConformanceCacheEntry::createSuccess( + R, P, record.getStaticWitnessTable())); + } + } + } + ++ConformanceCacheGeneration; + + pthread_mutex_unlock(&C.SectionsToScanLock); + // Start over with our newly-populated cache. + type = origType; + goto recur; +} + +const Metadata * +swift::_searchConformancesByMangledTypeName(const llvm::StringRef typeName) { + auto &C = Conformances.get(); + const Metadata *foundMetadata = nullptr; + + pthread_mutex_lock(&C.SectionsToScanLock); + + unsigned sectionIdx = 0; + unsigned endSectionIdx = C.SectionsToScan.size(); + + for (; sectionIdx < endSectionIdx; ++sectionIdx) { + auto §ion = C.SectionsToScan[sectionIdx]; + for (const auto &record : section) { + if (auto metadata = record.getCanonicalTypeMetadata()) + foundMetadata = _matchMetadataByMangledTypeName(typeName, metadata, nullptr); + else if (auto ntd = record.getNominalTypeDescriptor()) + foundMetadata = _matchMetadataByMangledTypeName(typeName, nullptr, ntd); + + if (foundMetadata != nullptr) + break; + } + if (foundMetadata != nullptr) + break; + } + + pthread_mutex_unlock(&C.SectionsToScanLock); + + return foundMetadata; +} diff --git a/stdlib/public/runtime/Reflection.mm b/stdlib/public/runtime/Reflection.mm index c0019d586d76b..bbf03460c0237 100644 --- a/stdlib/public/runtime/Reflection.mm +++ b/stdlib/public/runtime/Reflection.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -22,7 +22,6 @@ #include #include #include -#include #include #if SWIFT_OBJC_INTEROP @@ -299,6 +298,38 @@ AnyReturn swift_MagicMirrorData_objcValue(HeapObject *owner, #pragma clang diagnostic pop +extern "C" +const char *swift_OpaqueSummary(const Metadata *T) { + switch (T->getKind()) { + case MetadataKind::Class: + case MetadataKind::Struct: + case MetadataKind::Enum: + case MetadataKind::Optional: + case MetadataKind::Metatype: + return nullptr; + case MetadataKind::Opaque: + return "(Opaque Value)"; + case MetadataKind::Tuple: + return "(Tuple)"; + case MetadataKind::Function: + return "(Function)"; + case MetadataKind::Existential: + return "(Existential)"; + case MetadataKind::ObjCClassWrapper: + return "(Objective-C Class Wrapper)"; + case MetadataKind::ExistentialMetatype: + return "(Existential Metatype)"; + case MetadataKind::ForeignClass: + return "(Foreign Class)"; + case MetadataKind::HeapLocalVariable: + return "(Heap Local Variable)"; + case MetadataKind::HeapGenericLocalVariable: + return "(Heap Generic Local Variable)"; + case MetadataKind::ErrorObject: + return "(ErrorType Object)"; + } +} + extern "C" void swift_MagicMirrorData_summary(const Metadata *T, String *result) { switch (T->getKind()) { @@ -575,7 +606,12 @@ static void getEnumMirrorInfo(const OpaqueValue *value, unsigned payloadCases = Description.getNumPayloadCases(); - unsigned tag = type->vw_getEnumTag(value); + // 'tag' is in the range [-ElementsWithPayload..ElementsWithNoPayload-1]. + int tag = type->vw_getEnumTag(value); + + // Convert resilient tag index to fragile tag index. + tag += payloadCases; + const Metadata *payloadType = nullptr; bool indirect = false; @@ -598,7 +634,7 @@ static void getEnumMirrorInfo(const OpaqueValue *value, const OpaqueValue *value, const Metadata *type) { if (!isEnumReflectable(type)) - return NULL; + return nullptr; const auto Enum = static_cast(type); const auto &Description = Enum->Description->Enum; @@ -608,6 +644,31 @@ static void getEnumMirrorInfo(const OpaqueValue *value, return getFieldName(Description.CaseNames, tag); } +extern "C" +const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *type) { + // Build a magic mirror. Unconditionally destroy the value at the end. + const _ReflectableWitnessTable *witness; + const Metadata *mirrorType; + const OpaqueValue *cMirrorValue; + std::tie(witness, mirrorType, cMirrorValue) = getReflectableConformance(type, value); + + OpaqueValue *mirrorValue = const_cast(cMirrorValue); + Mirror mirror; + + if (witness) { + mirror = witness->getMirror(mirrorValue, mirrorType); + } else { + bool take = mirrorValue == value; + ::new (&mirror) MagicMirror(mirrorValue, mirrorType, take); + } + + MagicMirror *theMirror = reinterpret_cast(&mirror); + MagicMirrorData data = theMirror->Data; + const char *result = swift_EnumMirror_caseName(data.Owner, data.Value, data.Type); + type->vw_destroy(value); + return result; +} + extern "C" intptr_t swift_EnumMirror_count(HeapObject *owner, const OpaqueValue *value, @@ -660,18 +721,6 @@ StringMirrorTuple swift_EnumMirror_subscript(intptr_t i, } // -- Class destructuring. -static bool classHasSuperclass(const ClassMetadata *c) { -#if SWIFT_OBJC_INTEROP - // A class does not have a superclass if its ObjC superclass is the - // "SwiftObject" root class. - return c->SuperClass - && (Class)c->SuperClass != NSClassFromString(@"SwiftObject"); -#else - // In non-objc mode, the test is just if it has a non-null superclass. - return c->SuperClass != nullptr; -#endif -} - static Mirror getMirrorForSuperclass(const ClassMetadata *sup, HeapObject *owner, const OpaqueValue *value, diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index 6f6a4e6dce203..4179d164ec88b 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -44,12 +44,6 @@ # include # include #endif -#if SWIFT_RUNTIME_ENABLE_DTRACE -# include "SwiftRuntimeDTraceProbes.h" -#else -#define SWIFT_ISUNIQUELYREFERENCED() -#define SWIFT_ISUNIQUELYREFERENCEDORPINNED() -#endif using namespace swift; @@ -238,8 +232,8 @@ - (BOOL)isProxy { } - (struct _NSZone *)zone { - return (struct _NSZone *) - (malloc_zone_from_ptr(self) ?: malloc_default_zone()); + auto zone = malloc_zone_from_ptr(self); + return (struct _NSZone *)(zone ? zone : malloc_default_zone()); } - (void)doesNotRecognizeSelector: (SEL) sel { @@ -262,7 +256,7 @@ - (id)autorelease { return _objc_rootAutorelease(self); } - (NSUInteger)retainCount { - return swift::swift_retainCount(reinterpret_cast(self)); + return reinterpret_cast(self)->refCount.getCount(); } - (BOOL)_isDeallocating { return swift_isDeallocating(reinterpret_cast(self)); @@ -451,7 +445,7 @@ - (BOOL)isNSValue__ { return NO; } // version for SwiftShims bool -swift::_swift_usesNativeSwiftReferenceCounting_class(const void *theClass) { +swift::swift_objc_class_usesNativeSwiftReferenceCounting(const void *theClass) { #if SWIFT_OBJC_INTEROP return usesNativeSwiftReferenceCounting((const ClassMetadata *)theClass); #else @@ -978,6 +972,7 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { /*****************************************************************************/ /******************************* DYNAMIC CASTS *******************************/ /*****************************************************************************/ + #if SWIFT_OBJC_INTEROP const void * swift::swift_dynamicCastObjCClass(const void *object, @@ -1024,18 +1019,14 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { return object; } -extern "C" bool swift_objcRespondsToSelector(id object, SEL selector) { - return [object respondsToSelector:selector]; -} - -extern "C" bool swift::_swift_objectConformsToObjCProtocol(const void *theObject, - const ProtocolDescriptor *protocol) { +bool swift::objectConformsToObjCProtocol(const void *theObject, + const ProtocolDescriptor *protocol) { return [((id) theObject) conformsToProtocol: (Protocol*) protocol]; } -extern "C" bool swift::_swift_classConformsToObjCProtocol(const void *theClass, - const ProtocolDescriptor *protocol) { +bool swift::classConformsToObjCProtocol(const void *theClass, + const ProtocolDescriptor *protocol) { return [((Class) theClass) conformsToProtocol: (Protocol*) protocol]; } @@ -1197,246 +1188,6 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { swift_dynamicCastFailure(source, dest); } - -static Demangle::NodePointer _buildDemanglingForMetadata(const Metadata *type); - -// Build a demangled type tree for a nominal type. -static Demangle::NodePointer -_buildDemanglingForNominalType(Demangle::Node::Kind boundGenericKind, - const Metadata *type, - const NominalTypeDescriptor *description) { - using namespace Demangle; - - // Demangle the base name. - auto node = demangleTypeAsNode(description->Name, - strlen(description->Name)); - // If generic, demangle the type parameters. - if (description->GenericParams.NumPrimaryParams > 0) { - auto typeParams = NodeFactory::create(Node::Kind::TypeList); - auto typeBytes = reinterpret_cast(type); - auto genericParam = reinterpret_cast( - typeBytes + sizeof(void*) * description->GenericParams.Offset); - for (unsigned i = 0, e = description->GenericParams.NumPrimaryParams; - i < e; ++i, ++genericParam) { - typeParams->addChild(_buildDemanglingForMetadata(*genericParam)); - } - - auto genericNode = NodeFactory::create(boundGenericKind); - genericNode->addChild(node); - genericNode->addChild(typeParams); - return genericNode; - } - return node; -} - -// Build a demangled type tree for a type. -static Demangle::NodePointer _buildDemanglingForMetadata(const Metadata *type) { - using namespace Demangle; - - switch (type->getKind()) { - case MetadataKind::Class: { - auto classType = static_cast(type); - return _buildDemanglingForNominalType(Node::Kind::BoundGenericClass, - type, classType->getDescription()); - } - case MetadataKind::Enum: - case MetadataKind::Optional: { - auto structType = static_cast(type); - return _buildDemanglingForNominalType(Node::Kind::BoundGenericEnum, - type, structType->Description); - } - case MetadataKind::Struct: { - auto structType = static_cast(type); - return _buildDemanglingForNominalType(Node::Kind::BoundGenericStructure, - type, structType->Description); - } - case MetadataKind::ObjCClassWrapper: { -#if SWIFT_OBJC_INTEROP - auto objcWrapper = static_cast(type); - const char *className = class_getName((Class)objcWrapper->Class); - - // ObjC classes mangle as being in the magic "__ObjC" module. - auto module = NodeFactory::create(Node::Kind::Module, "__ObjC"); - - auto node = NodeFactory::create(Node::Kind::Class); - node->addChild(module); - node->addChild(NodeFactory::create(Node::Kind::Identifier, - llvm::StringRef(className))); - - return node; -#else - assert(false && "no ObjC interop"); - return nullptr; -#endif - } - case MetadataKind::ForeignClass: { - auto foreign = static_cast(type); - return Demangle::demangleTypeAsNode(foreign->getName(), - strlen(foreign->getName())); - } - case MetadataKind::Existential: { - auto exis = static_cast(type); - NodePointer proto_list = NodeFactory::create(Node::Kind::ProtocolList); - NodePointer type_list = NodeFactory::create(Node::Kind::TypeList); - - proto_list->addChild(type_list); - - std::vector protocols; - protocols.reserve(exis->Protocols.NumProtocols); - for (unsigned i = 0, e = exis->Protocols.NumProtocols; i < e; ++i) - protocols.push_back(exis->Protocols[i]); - - // Sort the protocols by their mangled names. - // The ordering in the existential type metadata is by metadata pointer, - // which isn't necessarily stable across invocations. - std::sort(protocols.begin(), protocols.end(), - [](const ProtocolDescriptor *a, const ProtocolDescriptor *b) -> bool { - return strcmp(a->Name, b->Name) < 0; - }); - - for (auto *protocol : protocols) { - // The protocol name is mangled as a type symbol, with the _Tt prefix. - auto protocolNode = demangleSymbolAsNode(protocol->Name, - strlen(protocol->Name)); - - // ObjC protocol names aren't mangled. - if (!protocolNode) { - auto module = NodeFactory::create(Node::Kind::Module, - MANGLING_MODULE_OBJC); - auto node = NodeFactory::create(Node::Kind::Protocol); - node->addChild(module); - node->addChild(NodeFactory::create(Node::Kind::Identifier, - llvm::StringRef(protocol->Name))); - auto typeNode = NodeFactory::create(Node::Kind::Type); - typeNode->addChild(node); - type_list->addChild(typeNode); - continue; - } - - // FIXME: We have to dig through a ridiculous number of nodes to get - // to the Protocol node here. - protocolNode = protocolNode->getChild(0); // Global -> TypeMangling - protocolNode = protocolNode->getChild(0); // TypeMangling -> Type - protocolNode = protocolNode->getChild(0); // Type -> ProtocolList - protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList - protocolNode = protocolNode->getChild(0); // TypeList -> Type - - assert(protocolNode->getKind() == Node::Kind::Type); - assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol); - type_list->addChild(protocolNode); - } - - return proto_list; - } - case MetadataKind::ExistentialMetatype: { - auto metatype = static_cast(type); - auto instance = _buildDemanglingForMetadata(metatype->InstanceType); - auto node = NodeFactory::create(Node::Kind::ExistentialMetatype); - node->addChild(instance); - return node; - } - case MetadataKind::Function: { - auto func = static_cast(type); - - Node::Kind kind; - switch (func->getConvention()) { - case FunctionMetadataConvention::Swift: - kind = Node::Kind::FunctionType; - break; - case FunctionMetadataConvention::Block: - kind = Node::Kind::ObjCBlock; - break; - case FunctionMetadataConvention::CFunctionPointer: - kind = Node::Kind::CFunctionPointer; - break; - case FunctionMetadataConvention::Thin: - kind = Node::Kind::ThinFunctionType; - break; - } - - std::vector inputs; - for (unsigned i = 0, e = func->getNumArguments(); i < e; ++i) { - auto arg = func->getArguments()[i]; - auto input = _buildDemanglingForMetadata(arg.getPointer()); - if (arg.getFlag()) { - NodePointer inout = NodeFactory::create(Node::Kind::InOut); - inout->addChild(input); - input = inout; - } - inputs.push_back(input); - } - - NodePointer totalInput; - if (inputs.size() > 1) { - auto tuple = NodeFactory::create(Node::Kind::NonVariadicTuple); - for (auto &input : inputs) - tuple->addChild(input); - totalInput = tuple; - } else { - totalInput = inputs.front(); - } - - NodePointer args = NodeFactory::create(Node::Kind::ArgumentTuple); - args->addChild(totalInput); - - NodePointer resultTy = _buildDemanglingForMetadata(func->ResultType); - NodePointer result = NodeFactory::create(Node::Kind::ReturnType); - result->addChild(resultTy); - - auto funcNode = NodeFactory::create(kind); - if (func->throws()) - funcNode->addChild(NodeFactory::create(Node::Kind::ThrowsAnnotation)); - funcNode->addChild(args); - funcNode->addChild(result); - return funcNode; - } - case MetadataKind::Metatype: { - auto metatype = static_cast(type); - auto instance = _buildDemanglingForMetadata(metatype->InstanceType); - auto node = NodeFactory::create(Node::Kind::Metatype); - node->addChild(instance); - return node; - } - case MetadataKind::Tuple: { - auto tuple = static_cast(type); - auto tupleNode = NodeFactory::create(Node::Kind::NonVariadicTuple); - for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) { - auto elt = _buildDemanglingForMetadata(tuple->getElement(i).Type); - tupleNode->addChild(elt); - } - return tupleNode; - } - case MetadataKind::Opaque: - // FIXME: Some opaque types do have manglings, but we don't have enough info - // to figure them out. - case MetadataKind::HeapLocalVariable: - case MetadataKind::HeapGenericLocalVariable: - case MetadataKind::ErrorObject: - break; - } - // Not a type. - return nullptr; -} - -extern "C" const char * -swift_getGenericClassObjCName(const ClassMetadata *clas) { - // Use the remangler to generate a mangled name from the type metadata. - auto demangling = _buildDemanglingForMetadata(clas); - - // Remangle that into a new type mangling string. - auto typeNode - = Demangle::NodeFactory::create(Demangle::Node::Kind::TypeMangling); - typeNode->addChild(demangling); - auto globalNode - = Demangle::NodeFactory::create(Demangle::Node::Kind::Global); - globalNode->addChild(typeNode); - - auto string = Demangle::mangleNode(globalNode); - - auto fullNameBuf = (char*)swift_slowAlloc(string.size() + 1, 0); - memcpy(fullNameBuf, string.c_str(), string.size() + 1); - return fullNameBuf; -} #endif const ClassMetadata * @@ -1457,26 +1208,23 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { return sourceType; } +#if SWIFT_OBJC_INTEROP // Given a non-nil object reference, return true iff the object uses // native swift reference counting. -bool swift::_swift_usesNativeSwiftReferenceCounting_nonNull( +static bool usesNativeSwiftReferenceCounting_nonNull( const void* object ) { - assert(object != nullptr); -#if SWIFT_OBJC_INTEROP - return !isObjCTaggedPointer(object) && - usesNativeSwiftReferenceCounting_allocated(object); -#else - return true; -#endif + assert(object != nullptr); + return !isObjCTaggedPointer(object) && + usesNativeSwiftReferenceCounting_allocated(object); } +#endif bool swift::swift_isUniquelyReferenced_nonNull_native( const HeapObject* object ) { assert(object != nullptr); assert(!object->refCount.isDeallocating()); - SWIFT_ISUNIQUELYREFERENCED(); return object->refCount.isUniquelyReferenced(); } @@ -1489,7 +1237,7 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { assert(object != nullptr); return #if SWIFT_OBJC_INTEROP - _swift_usesNativeSwiftReferenceCounting_nonNull(object) && + usesNativeSwiftReferenceCounting_nonNull(object) && #endif swift_isUniquelyReferenced_nonNull_native((HeapObject*)object); } @@ -1559,7 +1307,7 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { assert(object != nullptr); return #if SWIFT_OBJC_INTEROP - _swift_usesNativeSwiftReferenceCounting_nonNull(object) && + usesNativeSwiftReferenceCounting_nonNull(object) && #endif swift_isUniquelyReferencedOrPinned_nonNull_native( (const HeapObject*)object); @@ -1580,31 +1328,44 @@ static void doWeakDestroy(WeakReference *addr, bool valueIsNative) { /// pinned flag is set. bool swift::swift_isUniquelyReferencedOrPinned_nonNull_native( const HeapObject* object) { - SWIFT_ISUNIQUELYREFERENCEDORPINNED(); assert(object != nullptr); assert(!object->refCount.isDeallocating()); return object->refCount.isUniquelyReferencedOrPinned(); } -#if SWIFT_OBJC_INTEROP -/// Returns class_getInstanceSize(c) -/// -/// That function is otherwise unavailable to the core stdlib. -size_t swift::_swift_class_getInstancePositiveExtentSize(const void* c) { - return class_getInstanceSize((Class)c); -} -#endif +using ClassExtents = TwoWordPair; -extern "C" size_t _swift_class_getInstancePositiveExtentSize_native( - const Metadata *c) { +extern "C" +ClassExtents::Return +swift_class_getInstanceExtents(const Metadata *c) { assert(c && c->isClassObject()); auto metaData = c->getClassObject(); - return metaData->getInstanceSize() - metaData->getInstanceAddressPoint(); + return ClassExtents{ + metaData->getInstanceAddressPoint(), + metaData->getInstanceSize() - metaData->getInstanceAddressPoint() + }; } +#if SWIFT_OBJC_INTEROP +extern "C" +ClassExtents::Return +swift_objc_class_unknownGetInstanceExtents(const ClassMetadata* c) { + // Pure ObjC classes never have negative extents. + if (c->isPureObjC()) + return ClassExtents{0, class_getInstanceSize((Class)c)}; + + return swift_class_getInstanceExtents(c); +} +#endif + const ClassMetadata *swift::getRootSuperclass() { #if SWIFT_OBJC_INTEROP - return (const ClassMetadata *)[SwiftObject class]; + static Lazy SwiftObjectClass; + + return SwiftObjectClass.get([](void *ptr) { + *((const ClassMetadata **) ptr) = + (const ClassMetadata *)[SwiftObject class]; + }); #else return nullptr; #endif diff --git a/stdlib/public/runtime/SwiftRuntimeDTraceProbes.d b/stdlib/public/runtime/SwiftRuntimeDTraceProbes.d deleted file mode 100644 index cfe5236d4963c..0000000000000 --- a/stdlib/public/runtime/SwiftRuntimeDTraceProbes.d +++ /dev/null @@ -1,9 +0,0 @@ - -provider swift { - probe retain(); - probe release(); - probe allocateObject(); - probe deallocateObject(); - probe isUniquelyReferenced(); - probe isUniquelyReferencedOrPinned(); -}; diff --git a/stdlib/public/runtime/swift.ld b/stdlib/public/runtime/swift.ld index f5b5c44be4d5f..193c089120fd6 100644 --- a/stdlib/public/runtime/swift.ld +++ b/stdlib/public/runtime/swift.ld @@ -5,6 +5,12 @@ SECTIONS .swift2_protocol_conformances_start = . ; QUAD(SIZEOF(.swift2_protocol_conformances) - 8) ; *(.swift2_protocol_conformances) ; + }, + .swift2_type_metadata : + { + .swift2_type_metadata_start = . ; + QUAD(SIZEOF(.swift2_type_metadata) - 8) ; + *(.swift2_type_metadata) ; } } INSERT AFTER .dtors diff --git a/stdlib/public/stubs/Assert.cpp b/stdlib/public/stubs/Assert.cpp new file mode 100644 index 0000000000000..c80ff44b97a8f --- /dev/null +++ b/stdlib/public/stubs/Assert.cpp @@ -0,0 +1,91 @@ +//===--- Assert.cpp - Assertion failure reporting -------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Implementation of +// +//===----------------------------------------------------------------------===// + +#include "swift/Runtime/Debug.h" +#include +#include +#include + +using namespace swift; + +// Report a fatal error to system console, stderr, and crash logs. +// : : file , line \n +// The message may be omitted by passing messageLength=0. +extern "C" void +_swift_stdlib_reportFatalErrorInFile(const char *prefix, intptr_t prefixLength, + const char *message, intptr_t messageLength, + const char *file, intptr_t fileLength, + uintptr_t line) { + char *log; + asprintf(&log, "%.*s: %.*s%sfile %.*s, line %zu\n", (int)prefixLength, prefix, + (int)messageLength, message, (messageLength ? ": " : ""), + (int)fileLength, file, (size_t)line); + + swift_reportError(log); + free(log); +} + +// Report a fatal error to system console, stderr, and crash logs. +// : : file , line \n +// The message may be omitted by passing messageLength=0. +extern "C" void +_swift_stdlib_reportFatalError(const char *prefix, + intptr_t prefixLength, + const char *message, + intptr_t messageLength) { + char *log; + asprintf(&log, "%.*s: %.*s\n", (int)prefixLength, prefix, + (int)messageLength, message); + + swift_reportError(log); + free(log); +} + +// Report a call to an unimplemented initializer. +// : : : fatal error: use of unimplemented +// initializer '' for class 'className' +extern "C" void +_swift_stdlib_reportUnimplementedInitializerInFile( + const char *className, intptr_t classNameLength, const char *initName, + intptr_t initNameLength, const char *file, intptr_t fileLength, + uintptr_t line, uintptr_t column) { + char *log; + asprintf(&log, "%.*s: %zu: %zu: fatal error: use of unimplemented " + "initializer '%.*s' for class '%.*s'\n", + (int)fileLength, file, (size_t)line, (size_t)column, + (int)initNameLength, initName, (int)classNameLength, className); + + swift_reportError(log); + free(log); +} + +// Report a call to an unimplemented initializer. +// fatal error: use of unimplemented initializer '' for class +// 'className' +extern "C" void +_swift_stdlib_reportUnimplementedInitializer(const char *className, + intptr_t classNameLength, + const char *initName, + intptr_t initNameLength) { + char *log; + asprintf(&log, "fatal error: use of unimplemented " + "initializer '%.*s' for class '%.*s'\n", + (int)initNameLength, initName, (int)classNameLength, className); + + swift_reportError(log); + free(log); +} + diff --git a/stdlib/public/stubs/Availability.mm b/stdlib/public/stubs/Availability.mm index d76d0b1a4ac91..3d13741bde8c4 100644 --- a/stdlib/public/stubs/Availability.mm +++ b/stdlib/public/stubs/Availability.mm @@ -1,8 +1,8 @@ -//===--- Availability.mm - Swift Language API Availability Support---------===// +//===--- Availability.mm - Swift Language API Availability Support --------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/stubs/CMakeLists.txt b/stdlib/public/stubs/CMakeLists.txt index f7e2c3e829d60..4bc5c74342161 100644 --- a/stdlib/public/stubs/CMakeLists.txt +++ b/stdlib/public/stubs/CMakeLists.txt @@ -1,17 +1,33 @@ set(swift_stubs_objc_sources) +set(swift_stubs_unicode_normalization_sources) +set(swift_stubs_link_libraries) if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}") set(swift_stubs_objc_sources Availability.mm FoundationHelpers.mm SwiftNativeNSXXXBase.mm.gyb) + set(LLVM_OPTIONAL_SOURCES + UnicodeNormalization.cpp) +else() + find_package(ICU REQUIRED COMPONENTS uc i18n) + set(swift_stubs_unicode_normalization_sources + UnicodeNormalization.cpp) + set(swift_stubs_link_libraries + ${ICU_UC_LIBRARY} ${ICU_I18N_LIBRARY}) + include_directories( + ${ICU_UC_INCLUDE_DIR} ${ICU_I18N_INCLUDE_DIR}) endif() add_swift_library(swiftStdlibStubs IS_STDLIB IS_STDLIB_CORE + Assert.cpp GlobalObjects.cpp LibcShims.cpp Stubs.cpp + UnicodeExtendedGraphemeClusters.cpp.gyb ${swift_stubs_objc_sources} + ${swift_stubs_unicode_normalization_sources} C_COMPILE_FLAGS ${SWIFT_CORE_CXX_FLAGS} + LINK_LIBRARIES ${swift_stubs_link_libraries} INSTALL_IN_COMPONENT stdlib) diff --git a/stdlib/public/stubs/FoundationHelpers.mm b/stdlib/public/stubs/FoundationHelpers.mm index 4974b9a308740..be4b18ef102c8 100644 --- a/stdlib/public/stubs/FoundationHelpers.mm +++ b/stdlib/public/stubs/FoundationHelpers.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/stubs/GlobalObjects.cpp b/stdlib/public/stubs/GlobalObjects.cpp index 2ff75573d878c..02e04cd63c51d 100644 --- a/stdlib/public/stubs/GlobalObjects.cpp +++ b/stdlib/public/stubs/GlobalObjects.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 13d9d74a9f9fc..ea83c3ec7b98d 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 7526ab830d105..71c87739fcf78 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -222,7 +222,8 @@ extern "C" long double _swift_fmodl(long double lhs, long double rhs) { // FIXME: rdar://14883575 Libcompiler_rt omits muloti4 #if (defined(__APPLE__) && defined(__arm64__)) || \ (defined(__linux__) && defined(__x86_64__)) || \ - (defined(__linux__) && defined(__aarch64__)) + (defined(__linux__) && defined(__aarch64__)) || \ + (defined(__linux__) && defined(__powerpc64__)) typedef int ti_int __attribute__ ((mode (TI))); extern "C" @@ -328,7 +329,7 @@ static const char *_swift_stdlib_strtoX_clocale_impl( *outResult = result; if (result == huge || result == -huge || result == 0.0 || result == -0.0) { if (errno == ERANGE) - EndPtr = NULL; + EndPtr = nullptr; } return EndPtr; } diff --git a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb index d4c0ec2ffe7e4..43611e9925517 100644 --- a/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb +++ b/stdlib/public/stubs/SwiftNativeNSXXXBase.mm.gyb @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -74,6 +74,15 @@ using namespace swift; auto SELF = reinterpret_cast(self); return (bool)swift_tryRetain(SELF); } +- (BOOL)_isDeallocating { + return swift_isDeallocating(reinterpret_cast(self)); +} +- (BOOL)allowsWeakReference { + return !swift_isDeallocating(reinterpret_cast(self)); +} +- (BOOL)retainWeakReference { + return swift_tryRetain(reinterpret_cast(self)) != nullptr; +} #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-missing-super-calls" diff --git a/stdlib/public/runtime/UnicodeExtendedGraphemeClusters.cpp.gyb b/stdlib/public/stubs/UnicodeExtendedGraphemeClusters.cpp.gyb similarity index 93% rename from stdlib/public/runtime/UnicodeExtendedGraphemeClusters.cpp.gyb rename to stdlib/public/stubs/UnicodeExtendedGraphemeClusters.cpp.gyb index 75f6d5384355e..503a4da4cd3cd 100644 --- a/stdlib/public/runtime/UnicodeExtendedGraphemeClusters.cpp.gyb +++ b/stdlib/public/stubs/UnicodeExtendedGraphemeClusters.cpp.gyb @@ -1,8 +1,8 @@ -//===- UnicodeExtendedGraphemeClusters.cpp.gyb ------------------*- c++ -*-===// +//===--- UnicodeExtendedGraphemeClusters.cpp.gyb ----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,7 +15,7 @@ # FIXME: this table should be moved to a Swift file in stdlib. Unfortunately, # in Swift we don't have a way to statically initialize arrays. -from GYBUnicodeDataUtils import * +from GYBUnicodeDataUtils import GraphemeClusterBreakPropertyTable, UnicodeTrieGenerator, get_extended_grapheme_cluster_rules_matrix grapheme_cluster_break_property_table = \ GraphemeClusterBreakPropertyTable(unicodeGraphemeBreakPropertyFile) diff --git a/stdlib/public/runtime/UnicodeNormalization.cpp b/stdlib/public/stubs/UnicodeNormalization.cpp similarity index 98% rename from stdlib/public/runtime/UnicodeNormalization.cpp rename to stdlib/public/stubs/UnicodeNormalization.cpp index 0d921c9691f13..74caec310fa3f 100644 --- a/stdlib/public/runtime/UnicodeNormalization.cpp +++ b/stdlib/public/stubs/UnicodeNormalization.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -78,7 +78,7 @@ class ASCIICollation { return &collation; } - /// Maps an ASCII character to an collation element priority as would be + /// Maps an ASCII character to a collation element priority as would be /// returned by a call to ucol_next(). int32_t map(unsigned char c) const { return CollationTable[c]; @@ -287,7 +287,7 @@ int32_t _swift_stdlib_unicode_strToUpper(uint16_t *Destination, /// Convert the unicode string to lowercase. This function will return the /// required buffer length as a result. If this length does not match the /// 'DestinationCapacity' this function must be called again with a buffer of -/// the required length to get an lowercase version of the string. +/// the required length to get a lowercase version of the string. extern "C" int32_t _swift_stdlib_unicode_strToLower(uint16_t *Destination, int32_t DestinationCapacity, diff --git a/test/1_stdlib/ArrayBridge.swift b/test/1_stdlib/ArrayBridge.swift index 7a0255a6047ad..402b63c9ba2d3 100644 --- a/test/1_stdlib/ArrayBridge.swift +++ b/test/1_stdlib/ArrayBridge.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -47,14 +47,15 @@ class Tracked : NSObject, Fooable { func foo() { } required init(_ value: Int) { - ++trackedCount - serialNumber = ++nextTrackedSerialNumber + trackedCount += 1 + nextTrackedSerialNumber += 1 + serialNumber = nextTrackedSerialNumber self.value = value } deinit { assert(serialNumber > 0, "double destruction!") - --trackedCount + trackedCount -= 1 serialNumber = -serialNumber } @@ -102,7 +103,7 @@ struct BridgedSwift : CustomStringConvertible, _ObjectiveCBridgeable { } func _bridgeToObjectiveC() -> BridgedObjC { - ++bridgeToOperationCount + bridgeToOperationCount += 1 return BridgedObjC(trak.value) } @@ -115,7 +116,7 @@ struct BridgedSwift : CustomStringConvertible, _ObjectiveCBridgeable { inout result: BridgedSwift? ) { assert(x.value >= 0, "not bridged") - ++bridgeFromOperationCount + bridgeFromOperationCount += 1 result = BridgedSwift(x.value) } @@ -527,7 +528,7 @@ func testRoundTrip() { } } - var test = Test() + let test = Test() let array = [ BridgedSwift(10), BridgedSwift(20), BridgedSwift(30), @@ -555,7 +556,7 @@ print(x.objectAtIndex(0) as Base) */ func testMutableArray() { - var m = NSMutableArray(array: ["fu", "bar", "buzz"]) + let m = NSMutableArray(array: ["fu", "bar", "buzz"]) let a = m as NSArray as! [NSString] print(a) // CHECK-NEXT: [fu, bar, buzz] m.addObject("goop") diff --git a/test/1_stdlib/ArrayCore.swift b/test/1_stdlib/ArrayCore.swift index ae8759cce0cd8..0a15b62f5ccda 100644 --- a/test/1_stdlib/ArrayCore.swift +++ b/test/1_stdlib/ArrayCore.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -23,14 +23,15 @@ var nextTrackedSerialNumber = 0 final class Tracked : ForwardIndexType, CustomStringConvertible { required init(_ value: Int) { - ++trackedCount - serialNumber = ++nextTrackedSerialNumber + trackedCount += 1 + nextTrackedSerialNumber += 1 + serialNumber = nextTrackedSerialNumber self.value = value } deinit { assert(serialNumber > 0, "double destruction!") - --trackedCount + trackedCount -= 1 serialNumber = -serialNumber } diff --git a/test/1_stdlib/ArrayTraps.swift.gyb b/test/1_stdlib/ArrayTraps.swift.gyb index be4422644c6ff..a40a02121406a 100644 --- a/test/1_stdlib/ArrayTraps.swift.gyb +++ b/test/1_stdlib/ArrayTraps.swift.gyb @@ -8,8 +8,6 @@ // RUN: %S/../../utils/line-directive %t/ArrayTraps.swift -- %target-run %t/a.out_Release // REQUIRES: executable_test -// XFAIL: linux - import StdlibUnittest // Also import modules which are used by StdlibUnittest internally. This @@ -136,67 +134,6 @@ ${ArrayTy}Traps.test("${'removeAtIndex(_:)/%s' % index}") % end % end -class Base { } -class Derived : Base { } -class Derived2 : Derived { } - -ArrayTraps.test("downcast1") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let ba: [Base] = [ Derived(), Base() ] - let da = ba as! [Derived] - let d0 = da[0] - expectCrashLater() - da[1] -} - -import Foundation - -ArrayTraps.test("downcast2") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let a: [AnyObject] = [ "String", 1 ] - let sa = a as! [NSString] - let s0 = sa[0] - expectCrashLater() - sa[1] -} - -ArrayTraps.test("downcast3") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let ba: [Base] = [ Derived2(), Derived(), Base() ] - let d2a = ba as! [Derived2] - let d2a0 = d2a[0] - let d1a = d2a as [Derived] - let d1a0 = d1a[0] - let d1a1 = d1a[1] - expectCrashLater() - d1a[2] -} - -@objc protocol ObjCProto { } -class ObjCBase : NSObject, ObjCProto { } -class ObjCDerived : ObjCBase { } - -ArrayTraps.test("downcast4") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let ba: [ObjCProto] = [ ObjCDerived(), ObjCBase() ] - let da = ba as! [ObjCDerived] - let d0 = da[0] - expectCrashLater() - da[1] -} - ArrayTraps.test("unsafeLength") .skip(.Custom( { _isFastAssertConfiguration() }, @@ -213,117 +150,5 @@ ArrayTraps.test("unsafeLength") } } -ArrayTraps.test("bounds_with_downcast") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .crashOutputMatches(_isDebugAssertConfiguration() ? - "fatal error: Index out of range" : "") - .code { - let ba: [Base] = [ Derived(), Base() ] - let da = ba as! [Derived] - expectCrashLater() - let x = da[2] -} - -var ArraySemanticOptzns = TestSuite("ArraySemanticOptzns") - -class BaseClass { -} - -class ElementClass : BaseClass { - var val: String - init(_ x: String) { - val = x - } -} - -class ViolateInoutSafeySwitchToObjcBuffer { - final var anArray: [ElementClass] = [] - - let nsArray = NSArray( - objects: ElementClass("a"), ElementClass("b"), ElementClass("c")) - - @inline(never) - func accessArrayViaInoutVolation() { - anArray = _convertNSArrayToArray(nsArray) - } - - @inline(never) - func runLoop(inout A: [ElementClass]) { - // Simulate what happens if we hoist array properties out of a loop and the - // loop calls a function that violates inout safety and overrides the array. - let isNativeTypeChecked = A._hoistableIsNativeTypeChecked() - for i in 0.. 0, "double destruction!") - --trackedCount + trackedCount -= 1 serialNumber = -serialNumber } @@ -111,12 +112,12 @@ func testScope() { // We can get a single element out // CHECK-NEXT: nsx[0]: 1 . - var one = nsx.objectAtIndex(0) as! Tracked + let one = nsx.objectAtIndex(0) as! Tracked print("nsx[0]: \(one.value) .") // We can get the element again, but it may not have the same identity // CHECK-NEXT: object identity matches? - var anotherOne = nsx.objectAtIndex(0) as! Tracked + let anotherOne = nsx.objectAtIndex(0) as! Tracked print("object identity matches? \(one === anotherOne)") // Because the elements come back at +0, we really don't want to @@ -125,7 +126,7 @@ func testScope() { objects.withUnsafeMutableBufferPointer { // FIXME: Can't elide signature and use $0 here - (inout buf: UnsafeMutableBufferPointer)->() in + (inout buf: UnsafeMutableBufferPointer) -> () in nsx.getObjects( UnsafeMutablePointer(buf.baseAddress), range: _SwiftNSRange(location: 1, length: 2)) diff --git a/test/1_stdlib/BridgeStorage.swift.gyb b/test/1_stdlib/BridgeStorage.swift.gyb index 26fd3890d86bf..bc46a575b77cc 100644 --- a/test/1_stdlib/BridgeStorage.swift.gyb +++ b/test/1_stdlib/BridgeStorage.swift.gyb @@ -1,8 +1,8 @@ -//===--- BridgeStorage.swift.gyb ------------------------------------------===// +//===--- BridgeStorage.swift.gyb ------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -48,79 +48,6 @@ protocol BridgeStorage { extension _BridgeStorage : BridgeStorage {} -struct BridgeObject - : BridgeStorage { - - typealias Native = NativeType - typealias ObjC = ObjCType - - init(native: Native, bits: Int) { - _sanityCheck( - bits >= 0 && bits < 2, - "BridgeObject can't store bits outside the range 0-1") - - self.object = native - self.bits = UInt8(truncatingBitPattern: bits) - } - - init(native: Native) { - self.object = native - self.bits = 0 - } - - init(objC: ObjC) { - self.object = objC - self.bits = 0 - } - - mutating func isUniquelyReferencedNative() -> Bool { - return _getBool(Builtin.isUnique(&object)) - } - - var isNative: Bool { - return _swift_usesNativeSwiftReferenceCounting_nonNull( - UnsafePointer(rawObject)) - } - - var isObjC: Bool { - return !isNative - } - - var nativeInstance: Native { - precondition(isNative) - return Builtin.bridgeFromRawPointer(rawObject) - } - - var nativeInstance_noSpareBits: Native { - precondition(isNative) - precondition(spareBits == 0) - return Builtin.bridgeFromRawPointer(rawObject) - } - - mutating func isUniquelyReferenced_native_noSpareBits() -> Bool { - precondition(isNative) - precondition(spareBits == 0) - return _isUnique_native(&object) - } - - var objCInstance: ObjC { - precondition(isObjC) - return Builtin.bridgeFromRawPointer(rawObject) - } - - var spareBits: Int { - return Int(bits) - } - - var rawObject: Builtin.RawPointer { - return Builtin.bridgeToRawPointer(object) - } - - // object declared mutable to be passed to isUnique. - var object: AnyObject - let bits: UInt8 -} - //===----------------------------------------------------------------------===// //===--- Testing code -----------------------------------------------------===// //===----------------------------------------------------------------------===// @@ -192,7 +119,7 @@ var unTaggedNSString : NSString { return expectTagged("fûtbōl" as NSString, false) } -% for Self in '_BridgeStorage', 'BridgeObject': +% for Self in ['_BridgeStorage']: allTests.test("${Self}") { typealias B = ${Self} diff --git a/test/1_stdlib/Builtins.swift b/test/1_stdlib/Builtins.swift index 8446814421732..93a4036a051a2 100644 --- a/test/1_stdlib/Builtins.swift +++ b/test/1_stdlib/Builtins.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -21,6 +21,14 @@ import Swift import SwiftShims import StdlibUnittest +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + #if _runtime(_ObjC) import Foundation #endif @@ -119,8 +127,8 @@ var NoisyDeathCount = 0 protocol P {} class Noisy : P { - init() { ++NoisyLifeCount } - deinit { ++NoisyDeathCount } + init() { NoisyLifeCount += 1 } + deinit { NoisyDeathCount += 1} } struct Large : P { diff --git a/test/1_stdlib/Casts.swift b/test/1_stdlib/Casts.swift new file mode 100644 index 0000000000000..72a0f9d9546b4 --- /dev/null +++ b/test/1_stdlib/Casts.swift @@ -0,0 +1,76 @@ +// Casts.swift - Tests for conversion between types. +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +// ----------------------------------------------------------------------------- +/// +/// Contains tests for conversions between types which shouldn't trap. +/// +// ----------------------------------------------------------------------------- +// RUN: %target-run-stdlib-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let CastsTests = TestSuite("Casts") + +// Test for SR-426: missing release for some types after failed conversion +class DeinitTester { + private let onDeinit: () -> () + + init(onDeinit: () -> ()) { + self.onDeinit = onDeinit + } + deinit { + onDeinit() + } +} + +func testFailedTupleCast(onDeinit: () -> ()) { + // This function is to establish a scope for t to + // be deallocated at the end of. + let t: Any = (1, DeinitTester(onDeinit: onDeinit)) + _ = t is Any.Type +} + +CastsTests.test("No leak for failed tuple casts") { + var deinitRan = false + testFailedTupleCast { + deinitRan = true + } + expectTrue(deinitRan) +} + +protocol P {} +class ErrClass : ErrorType { } + +CastsTests.test("No overrelease of existential boxes in failed casts") { + // Test for crash from SR-392 + // We fail casts of an existential box repeatedly + // to ensure it does not get over-released. + func bar(t: T) { + for i in 0..<10 { + if case let a as P = t { + _ = a + } + } + } + + let err: ErrorType = ErrClass() + bar(err) +} + +runAllTests() diff --git a/test/1_stdlib/Collection.swift b/test/1_stdlib/Collection.swift index ef08005a6a540..171f1186884aa 100644 --- a/test/1_stdlib/Collection.swift +++ b/test/1_stdlib/Collection.swift @@ -1,6 +1,20 @@ -// RUN: %target-run-simple-swift | FileCheck %s +// RUN: %target-run-simple-swift --stdlib-unittest-in-process | tee %t.txt +// RUN: FileCheck %s < %t.txt +// note: remove the --stdlib-unittest-in-process once all the FileCheck tests +// have been converted to StdlibUnittest // REQUIRES: executable_test +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +var CollectionTests = TestSuite("CollectionTests") + struct X : CollectionType { typealias Element = String.CharacterView.Generator.Element typealias Index = String.Index @@ -45,7 +59,7 @@ func isPalindrome0< >(seq: S) -> Bool { typealias Index = S.Index - var a = seq.indices + let a = seq.indices var i = seq.indices var ir = i.lazy.reverse() var b = ir.generate() @@ -111,12 +125,14 @@ func isPalindrome2< var b = seq.startIndex, e = seq.endIndex while (b != e) { - if (b == --e) { + e = e.predecessor() + if (b == e) { break } - if seq[b++] != seq[e] { + if seq[b] != seq[e] { return false } + b = b.successor() } return true } @@ -200,5 +216,38 @@ func testIsEmptyFirstLast() { } testIsEmptyFirstLast() +/// A `CollectionType` that vends just the default implementations for +/// `CollectionType` methods. +struct CollectionOnly : CollectionType { + var base: T + + var startIndex: T.Index { + return base.startIndex + } + + var endIndex: T.Index { + return base.endIndex + } + + func generate() -> T.Generator { + return base.generate() + } + + subscript(position: T.Index) -> T.Generator.Element { + return base[position] + } +} + // CHECK: all done. print("all done.") + +CollectionTests.test("first/performance") { + // accessing `first` should not perform duplicate work on lazy collections + var log: [Int] = [] + let col_ = (0..<10).lazy.filter({ log.append($0); return (2..<8).contains($0) }) + let col = CollectionOnly(base: col_) + expectEqual(2, col.first) + expectEqual([0, 1, 2], log) +} + +runAllTests() diff --git a/test/1_stdlib/CollectionOfOne.swift b/test/1_stdlib/CollectionOfOne.swift index 7786ada0a212d..e003cf5f91554 100644 --- a/test/1_stdlib/CollectionOfOne.swift +++ b/test/1_stdlib/CollectionOfOne.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/DarwinAPI.swift b/test/1_stdlib/DarwinAPI.swift index a782e8eb4abd2..ff097c01d6828 100644 --- a/test/1_stdlib/DarwinAPI.swift +++ b/test/1_stdlib/DarwinAPI.swift @@ -4,6 +4,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var DarwinBooleanAPI = TestSuite("DarwinBooleanAPI") diff --git a/test/1_stdlib/DictionaryLiteral.swift b/test/1_stdlib/DictionaryLiteral.swift index ef8705c63a534..7a0ccea03112a 100644 --- a/test/1_stdlib/DictionaryLiteral.swift +++ b/test/1_stdlib/DictionaryLiteral.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -18,6 +18,14 @@ import SwiftExperimental import Foundation import StdlibUnittest +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + // Check that the generic parameters are called 'Key' and 'Value'. protocol TestProtocol1 {} diff --git a/test/1_stdlib/Dispatch.swift b/test/1_stdlib/Dispatch.swift index e7756fa4729e8..624081b1ea81b 100644 --- a/test/1_stdlib/Dispatch.swift +++ b/test/1_stdlib/Dispatch.swift @@ -7,6 +7,14 @@ import Dispatch import Foundation import StdlibUnittest +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + defer { runAllTests() } var DispatchAPI = TestSuite("DispatchAPI") diff --git a/test/1_stdlib/DispatchTypes.swift b/test/1_stdlib/DispatchTypes.swift index 1074976d39801..0378f3fe81d20 100644 --- a/test/1_stdlib/DispatchTypes.swift +++ b/test/1_stdlib/DispatchTypes.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -verify -parse %s +// RUN: %target-swift-frontend -parse %s // REQUIRES: objc_interop diff --git a/test/1_stdlib/ErrorHandling.swift b/test/1_stdlib/ErrorHandling.swift index f92b5b41800ad..baf4acea82964 100644 --- a/test/1_stdlib/ErrorHandling.swift +++ b/test/1_stdlib/ErrorHandling.swift @@ -18,8 +18,8 @@ import ObjectiveC var NoisyCount = 0 class Noisy { - init() { NoisyCount++ } - deinit { NoisyCount-- } + init() { NoisyCount += 1 } + deinit { NoisyCount -= 1 } } enum SillyError: ErrorType { case JazzHands } diff --git a/test/1_stdlib/ErrorType.swift b/test/1_stdlib/ErrorType.swift index 043630b79f299..155f9ca43c52e 100644 --- a/test/1_stdlib/ErrorType.swift +++ b/test/1_stdlib/ErrorType.swift @@ -25,8 +25,8 @@ protocol OtherClassProtocol : class { } class NoisyError : ErrorType, OtherProtocol, OtherClassProtocol { - init() { ++NoisyErrorLifeCount } - deinit { ++NoisyErrorDeathCount } + init() { NoisyErrorLifeCount += 1 } + deinit { NoisyErrorDeathCount += 1 } let _domain = "NoisyError" let _code = 123 diff --git a/test/1_stdlib/ErrorTypeBridging.swift b/test/1_stdlib/ErrorTypeBridging.swift index 1355bfe993de0..ee4f9b0578142 100644 --- a/test/1_stdlib/ErrorTypeBridging.swift +++ b/test/1_stdlib/ErrorTypeBridging.swift @@ -3,6 +3,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation import CoreLocation import Darwin @@ -22,8 +31,8 @@ protocol OtherClassProtocol : class { } class NoisyError : ErrorType, OtherProtocol, OtherClassProtocol { - init() { ++NoisyErrorLifeCount } - deinit { ++NoisyErrorDeathCount } + init() { NoisyErrorLifeCount += 1 } + deinit { NoisyErrorDeathCount += 1 } let _domain = "NoisyError" let _code = 123 diff --git a/test/1_stdlib/Experimental.swift b/test/1_stdlib/Experimental.swift index 5ffc6e0f04a45..9d717fe076172 100644 --- a/test/1_stdlib/Experimental.swift +++ b/test/1_stdlib/Experimental.swift @@ -46,8 +46,8 @@ ExperimentalTestSuite.test("ComposeOperator/CountCalls") { var aCalled = 0 var bCalled = 0 - func a(_: A) -> B { ++aCalled; return B() } - func b(_: B) -> C { ++bCalled; return C() } + func a(_: A) -> B { aCalled += 1; return B() } + func b(_: B) -> C { bCalled += 1; return C() } var result = b ∘ a expectEqual(0, aCalled) @@ -64,8 +64,8 @@ struct C {} var aCalled = 0 var bCalled = 0 -func a(_: A) -> B { ++aCalled; return B() } -func b(_: B) -> C { ++bCalled; return C() } +func a(_: A) -> B { aCalled += 1; return B() } +func b(_: B) -> C { bCalled += 1; return C() } ExperimentalTestSuite.test("ComposeOperator/CountCalls/Workaround") { var result = b ∘ a diff --git a/test/1_stdlib/Filter.swift b/test/1_stdlib/Filter.swift index fd04b627dc567..74ee1225e2196 100644 --- a/test/1_stdlib/Filter.swift +++ b/test/1_stdlib/Filter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Float.swift b/test/1_stdlib/Float.swift index 8cf37ecceb821..b96a700adc03b 100644 --- a/test/1_stdlib/Float.swift +++ b/test/1_stdlib/Float.swift @@ -37,12 +37,12 @@ func checkNormal(normal: TestFloat) { } func testNormal() { - var positiveNormal: TestFloat = 42.0 + let positiveNormal: TestFloat = 42.0 checkNormal(positiveNormal) _precondition(!positiveNormal.isSignMinus) _precondition(positiveNormal.floatingPointClass == .PositiveNormal) - var negativeNormal: TestFloat = -42.0 + let negativeNormal: TestFloat = -42.0 checkNormal(negativeNormal) _precondition(negativeNormal.isSignMinus) _precondition(negativeNormal.floatingPointClass == .NegativeNormal) @@ -74,12 +74,12 @@ func checkZero(zero: TestFloat) { } func testZero() { - var plusZero = noinlinePlusZero() + let plusZero = noinlinePlusZero() checkZero(plusZero) _precondition(!plusZero.isSignMinus) _precondition(plusZero.floatingPointClass == .PositiveZero) - var minusZero = noinlineMinusZero() + let minusZero = noinlineMinusZero() checkZero(minusZero) _precondition(minusZero.isSignMinus) _precondition(minusZero.floatingPointClass == .NegativeZero) @@ -129,7 +129,7 @@ func testSubnormal() { _preconditionFailure("unhandled float kind") } var positiveSubnormal: TestFloat = 1.0 - for var i = 0; i < iterations; i++ { + for var i = 0; i < iterations; i += 1 { positiveSubnormal /= 2.0 as TestFloat } checkSubnormal(positiveSubnormal) @@ -138,7 +138,7 @@ func testSubnormal() { _precondition(positiveSubnormal != 0.0) var negativeSubnormal: TestFloat = -1.0 - for var i = 0; i < iterations; i++ { + for var i = 0; i < iterations; i += 1{ negativeSubnormal /= 2.0 as TestFloat } checkSubnormal(negativeSubnormal) diff --git a/test/1_stdlib/FloatingPoint.swift.gyb b/test/1_stdlib/FloatingPoint.swift.gyb index 238119ecb6351..ac9ce39e56a79 100644 --- a/test/1_stdlib/FloatingPoint.swift.gyb +++ b/test/1_stdlib/FloatingPoint.swift.gyb @@ -223,7 +223,7 @@ func checkFloatingPointComparison_${FloatSelf}( expected: ExpectedComparisonResult, _ lhs: ${FloatSelf}, _ rhs: ${FloatSelf}, //===--- TRACE boilerplate ----------------------------------------------===// - // @autoclosure _ message: ()->String = "", + // @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ @@ -647,5 +647,24 @@ FloatingPoint.test("Float80/Literals") { #endif +var FloatingPointClassification = TestSuite("NumericParsing") + +FloatingPointClassification.test("FloatingPointClassification/Equatable") { + let values: [FloatingPointClassification] = [ + .SignalingNaN, + .QuietNaN, + .NegativeInfinity, + .NegativeNormal, + .NegativeSubnormal, + .NegativeZero, + .PositiveZero, + .PositiveSubnormal, + .PositiveNormal, + .PositiveInfinity + ] + // Values should be equal iff indices equal + checkEquatable(values, oracle: { $0 == $1 }) +} + runAllTests() diff --git a/test/1_stdlib/FloatingPointIR.swift b/test/1_stdlib/FloatingPointIR.swift index 1ed02747dd043..908efe0d37cb3 100644 --- a/test/1_stdlib/FloatingPointIR.swift +++ b/test/1_stdlib/FloatingPointIR.swift @@ -48,3 +48,8 @@ func testConstantFoldFloatLiterals() { // arm64: call void @{{.*}}_TF15FloatingPointIR13acceptFloat32FSfT_(float 1.000000e+00) // arm64: call void @{{.*}}_TF15FloatingPointIR13acceptFloat64FSdT_(double 1.000000e+00) +// powerpc64: call void @{{.*}}_TF15FloatingPointIR13acceptFloat32FSfT_(float 1.000000e+00) +// powerpc64: call void @{{.*}}_TF15FloatingPointIR13acceptFloat64FSdT_(double 1.000000e+00) + +// powerpc64le: call void @{{.*}}_TF15FloatingPointIR13acceptFloat32FSfT_(float 1.000000e+00) +// powerpc64le: call void @{{.*}}_TF15FloatingPointIR13acceptFloat64FSdT_(double 1.000000e+00) diff --git a/test/1_stdlib/InputStream.swift.gyb b/test/1_stdlib/InputStream.swift.gyb index 59fb559f7e449..6ac28310ff9fd 100644 --- a/test/1_stdlib/InputStream.swift.gyb +++ b/test/1_stdlib/InputStream.swift.gyb @@ -1,8 +1,8 @@ -//===--- InputStream.swift.gyb --------------------------------------------===// +//===--- InputStream.swift.gyb --------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.h b/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.h index c9f0d83c54524..1ef937c083a8c 100644 --- a/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.h +++ b/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.h @@ -1,8 +1,8 @@ -//===--- ArrayBridge.h ----------------------------------------------------===// +//===--- ArrayBridge.h ------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.m b/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.m index 68104f62e3746..781610757ce6a 100644 --- a/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.m +++ b/test/1_stdlib/Inputs/ArrayBridge/ArrayBridge.m @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/ArrayBridge/module.map b/test/1_stdlib/Inputs/ArrayBridge/module.map index 91941205411dc..511987f8227d1 100644 --- a/test/1_stdlib/Inputs/ArrayBridge/module.map +++ b/test/1_stdlib/Inputs/ArrayBridge/module.map @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/DictionaryKeyValueTypes.swift b/test/1_stdlib/Inputs/DictionaryKeyValueTypes.swift index f9f0c72c642b8..8ce4d2e8b5c61 100644 --- a/test/1_stdlib/Inputs/DictionaryKeyValueTypes.swift +++ b/test/1_stdlib/Inputs/DictionaryKeyValueTypes.swift @@ -791,7 +791,7 @@ func _checkArrayFastEnumerationImpl( expected: [Int], _ a: NSArray, _ makeEnumerator: () -> NSFastEnumeration, - _ useEnumerator: (NSArray, NSFastEnumeration, (AnyObject)->()) -> Void, + _ useEnumerator: (NSArray, NSFastEnumeration, (AnyObject) -> ()) -> Void, _ convertValue: (AnyObject) -> Int ) { let expectedContentsWithoutIdentity = @@ -924,7 +924,7 @@ func _checkSetFastEnumerationImpl( expected: [Int], _ s: NSSet, _ makeEnumerator: () -> NSFastEnumeration, - _ useEnumerator: (NSSet, NSFastEnumeration, (AnyObject)->()) -> Void, + _ useEnumerator: (NSSet, NSFastEnumeration, (AnyObject) -> ()) -> Void, _ convertMember: (AnyObject) -> Int ) { let expectedContentsWithoutIdentity = @@ -1142,7 +1142,7 @@ func _checkDictionaryFastEnumerationImpl( expected: [(Int, Int)], _ d: NSDictionary, _ makeEnumerator: () -> NSFastEnumeration, - _ useEnumerator: (NSDictionary, NSFastEnumeration, (AnyObjectTuple2)->()) -> Void, + _ useEnumerator: (NSDictionary, NSFastEnumeration, (AnyObjectTuple2) -> ()) -> Void, _ convertKey: (AnyObject) -> Int, _ convertValue: (AnyObject) -> Int ) { diff --git a/test/1_stdlib/Inputs/Mirror/Mirror.h b/test/1_stdlib/Inputs/Mirror/Mirror.h index 5acab1b170d0b..ef2112a217ebe 100644 --- a/test/1_stdlib/Inputs/Mirror/Mirror.h +++ b/test/1_stdlib/Inputs/Mirror/Mirror.h @@ -1,8 +1,8 @@ -//===--- Mirror.h ---------------------------------------------------------===// +//===--- Mirror.h -----------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/Mirror/Mirror.mm b/test/1_stdlib/Inputs/Mirror/Mirror.mm index 2b3be7a0fd021..9d053502d3557 100644 --- a/test/1_stdlib/Inputs/Mirror/Mirror.mm +++ b/test/1_stdlib/Inputs/Mirror/Mirror.mm @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/Mirror/module.map b/test/1_stdlib/Inputs/Mirror/module.map index ceacc55b29191..5042e7e0bfd1b 100644 --- a/test/1_stdlib/Inputs/Mirror/module.map +++ b/test/1_stdlib/Inputs/Mirror/module.map @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/PrintTestTypes.swift b/test/1_stdlib/Inputs/PrintTestTypes.swift new file mode 100644 index 0000000000000..d89a0bdbda3a2 --- /dev/null +++ b/test/1_stdlib/Inputs/PrintTestTypes.swift @@ -0,0 +1,157 @@ +public protocol ProtocolUnrelatedToPrinting {} + +public struct StructPrintable : CustomStringConvertible, + ProtocolUnrelatedToPrinting { + + let x: Int + + public init(_ x: Int) { + self.x = x + } + + public var description: String { + return "►\(x)◀︎" + } +} + +public struct LargeStructPrintable : CustomStringConvertible, + ProtocolUnrelatedToPrinting { + + let a: Int + let b: Int + let c: Int + let d: Int + + public init(_ a: Int, _ b: Int, _ c: Int, _ d: Int) { + self.a = a + self.b = b + self.c = c + self.d = d + } + + public var description: String { + return "<\(a) \(b) \(c) \(d)>" + } +} + +public struct StructDebugPrintable : CustomDebugStringConvertible { + let x: Int + + public init(_ x: Int) { + self.x = x + } + + public var debugDescription: String { + return "►\(x)◀︎" + } +} + +public struct StructVeryPrintable : CustomStringConvertible, + CustomDebugStringConvertible, ProtocolUnrelatedToPrinting { + + let x: Int + + public init(_ x: Int) { + self.x = x + } + + public var description: String { + return "" + } + + public var debugDescription: String { + return "" + } +} + +public struct EmptyStructWithoutDescription { + public init() {} +} + +public struct WithoutDescription { + let x: Int + + public init(_ x: Int) { + self.x = x + } +} + +public struct ValuesWithoutDescription { + let t: T + let u: U + let v: V + + public init(_ t: T, _ u: U, _ v: V) { + self.t = t + self.u = u + self.v = v + } +} + + +public class ClassPrintable : CustomStringConvertible, + ProtocolUnrelatedToPrinting { + + let x: Int + + public init(_ x: Int) { + self.x = x + } + + public var description: String { + return "►\(x)◀︎" + } +} + +public class ClassVeryPrintable : CustomStringConvertible, + CustomDebugStringConvertible, ProtocolUnrelatedToPrinting { + + let x: Int + + public init(_ x: Int) { + self.x = x + } + + public var description: String { + return "" + } + + public var debugDescription: String { + return "" + } +} + +public struct MyString : StringLiteralConvertible, + StringInterpolationConvertible { + + public init(str: String) { + value = str + } + + public var value: String + + public init(unicodeScalarLiteral value: String) { + self.init(str: value) + } + + public init(extendedGraphemeClusterLiteral value: String) { + self.init(str: value) + } + + public init(stringLiteral value: String) { + self.init(str: value) + } + + public init(stringInterpolation strings: MyString...) { + var result = "" + for s in strings { + result += s.value + } + self.init(str: result) + } + + public init(stringInterpolationSegment expr: T) { + self.init(str: "") + } +} + diff --git a/test/1_stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m b/test/1_stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m index 97225317b2401..d8eca5aff0e07 100644 --- a/test/1_stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m +++ b/test/1_stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Inputs/flatMap.gyb b/test/1_stdlib/Inputs/flatMap.gyb index e8e32a1f85e17..c1a8ad569cd89 100644 --- a/test/1_stdlib/Inputs/flatMap.gyb +++ b/test/1_stdlib/Inputs/flatMap.gyb @@ -1,4 +1,6 @@ -%import inspect,os.path,sys +%import inspect +%import os.path +%import sys %sys.path = [os.path.split(inspect.getframeinfo(inspect.currentframe()).filename)[0] or '.'] + sys.path % for Kind in Kinds: diff --git a/test/1_stdlib/Interval.swift b/test/1_stdlib/Interval.swift index 892d6000764b4..38679fc2be2e3 100644 --- a/test/1_stdlib/Interval.swift +++ b/test/1_stdlib/Interval.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/IntervalTraps.swift b/test/1_stdlib/IntervalTraps.swift index d2a28034cb039..707e0e3616d23 100644 --- a/test/1_stdlib/IntervalTraps.swift +++ b/test/1_stdlib/IntervalTraps.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/KVO.swift b/test/1_stdlib/KVO.swift index ecb95409632a1..21130b3c49823 100644 --- a/test/1_stdlib/KVO.swift +++ b/test/1_stdlib/KVO.swift @@ -75,9 +75,9 @@ t.objcValue = "three" t.objcValue = "four" // CHECK-NEXT: swiftValue 42, objcValue four -//===========================================================================// +//===----------------------------------------------------------------------===// // Test using a proper global context reference. -//===========================================================================// +//===----------------------------------------------------------------------===// var kvoContext = Int() diff --git a/test/1_stdlib/ManagedBuffer.swift b/test/1_stdlib/ManagedBuffer.swift index ab2febf4bd688..f3e3603523b56 100644 --- a/test/1_stdlib/ManagedBuffer.swift +++ b/test/1_stdlib/ManagedBuffer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,6 +16,15 @@ // XFAIL: linux import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation // Check that `NonObjectiveCBase` can be subclassed and the subclass can be @@ -95,7 +104,7 @@ final class TestManagedBuffer : ManagedBuffer { let count = self.count withUnsafeMutablePointerToElements { - (x: UnsafeMutablePointer)->() in + (x: UnsafeMutablePointer) -> () in for i in 0.stride(to: count, by: 2) { (x + i).destroy() } @@ -107,7 +116,7 @@ final class TestManagedBuffer : ManagedBuffer { precondition(count + 2 <= capacity) withUnsafeMutablePointerToElements { - (p: UnsafeMutablePointer)->() in + (p: UnsafeMutablePointer) -> () in (p + count).initialize(x) } self.count = count + 2 @@ -118,7 +127,7 @@ class MyBuffer { typealias Manager = ManagedBufferPointer deinit { Manager(unsafeBufferObject: self).withUnsafeMutablePointers { - (pointerToValue, pointerToElements)->Void in + (pointerToValue, pointerToElements) -> Void in pointerToElements.destroy(self.count) pointerToValue.destroy() } diff --git a/test/1_stdlib/Map.swift b/test/1_stdlib/Map.swift index 1a3e1bb4e6dd5..f09062105c7b0 100644 --- a/test/1_stdlib/Map.swift +++ b/test/1_stdlib/Map.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -52,7 +52,7 @@ for x in s { } print(">") -//===--- Avoid creating gratuitously self-destructive sequences ----------===// +//===--- Avoid creating gratuitously self-destructive sequences -----------===// // In a naive implementation, mapping over a non-self-destructive // SequenceType having a reference-semantics GeneratorType produces a @@ -65,7 +65,9 @@ print(">") // A GeneratorType with reference semantics class Counter : GeneratorType { func next() -> Int? { - return n < end ? n++ : nil + if n >= end { return nil } + n += 1 + return n-1 } init(_ n: Int, _ end: Int) { diff --git a/test/1_stdlib/Mirror.swift b/test/1_stdlib/Mirror.swift index ca288338d2de5..6296e552318f8 100644 --- a/test/1_stdlib/Mirror.swift +++ b/test/1_stdlib/Mirror.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -63,13 +63,15 @@ func find(substring: String, within domain: String) -> String.Index? { if (domainCount < substringCount) { return nil } var sliceStart = domain.startIndex var sliceEnd = domain.startIndex.advancedBy(substringCount) - for var i = 0;; ++i { + var i = 0 + while true { if domain[sliceStart.. Mirror { diff --git a/test/1_stdlib/NSArrayAPI.swift b/test/1_stdlib/NSArrayAPI.swift index fbe01609d57de..4c00ff2425c13 100644 --- a/test/1_stdlib/NSArrayAPI.swift +++ b/test/1_stdlib/NSArrayAPI.swift @@ -4,6 +4,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var NSArrayAPI = TestSuite("NSArrayAPI") diff --git a/test/1_stdlib/NSDictionary.swift b/test/1_stdlib/NSDictionary.swift index 9d186e9f96cac..67f8239508b7b 100644 --- a/test/1_stdlib/NSDictionary.swift +++ b/test/1_stdlib/NSDictionary.swift @@ -4,6 +4,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var tests = TestSuite("NSDictionary") diff --git a/test/1_stdlib/NSEnumeratorAPI.swift b/test/1_stdlib/NSEnumeratorAPI.swift index c9056b07b7ba6..2acf0c04f2dd9 100644 --- a/test/1_stdlib/NSEnumeratorAPI.swift +++ b/test/1_stdlib/NSEnumeratorAPI.swift @@ -4,6 +4,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var NSEnumeratorAPI = TestSuite("NSEnumeratorAPI") diff --git a/test/1_stdlib/NSSetAPI.swift b/test/1_stdlib/NSSetAPI.swift index ec7f6fa1e9923..6ca2775802831 100644 --- a/test/1_stdlib/NSSetAPI.swift +++ b/test/1_stdlib/NSSetAPI.swift @@ -4,6 +4,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var NSSetAPI = TestSuite("NSSetAPI") diff --git a/test/1_stdlib/NSStringAPI.swift b/test/1_stdlib/NSStringAPI.swift index 2c150899a346c..c67945b34c938 100644 --- a/test/1_stdlib/NSStringAPI.swift +++ b/test/1_stdlib/NSStringAPI.swift @@ -11,6 +11,15 @@ // import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation import StdlibUnittestFoundationExtras @@ -259,9 +268,9 @@ NSStringAPIs.test("localizedCapitalizedString") { /// executed in the given localeID func expectLocalizedEquality( expected: String, - _ op: (_: NSLocale?)->String, + _ op: (_: NSLocale?) -> String, _ localeID: String? = nil, - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ @@ -679,7 +688,7 @@ NSStringAPIs.test("getBytes(_:maxLength:usedLength:encoding:options:range:remain NSStringAPIs.test("getCString(_:maxLength:encoding:)") { var s = "abc あかさた" do { - // The largest buffer that can not accommodate the string plus null terminator. + // The largest buffer that cannot accommodate the string plus null terminator. let bufferLength = 16 var buffer = Array( count: bufferLength, repeatedValue: CChar(bitPattern: 0xff)) @@ -1187,7 +1196,7 @@ NSStringAPIs.test("rangeOfString(_:options:range:locale:)") { expectEmpty(s.rangeOfString("す")) // Note: here `rangeOfString` API produces indexes that don't point between - // grapheme cluster boundaries -- these can not be created with public + // grapheme cluster boundaries -- these cannot be created with public // String interface. // // FIXME: why does this search succeed and the above queries fail? There is @@ -1395,8 +1404,8 @@ NSStringAPIs.test("stringByFoldingWithOptions(_:locale:)") { func fwo( s: String, _ options: NSStringCompareOptions - )(loc: NSLocale?) -> String { - return s.stringByFoldingWithOptions(options, locale: loc) + ) -> (NSLocale?) -> String { + return { loc in s.stringByFoldingWithOptions(options, locale: loc) } } expectLocalizedEquality("abcd", fwo("abCD", .CaseInsensitiveSearch), "en") @@ -2143,7 +2152,7 @@ func getNullCString() -> UnsafeMutablePointer { return nil } -func getASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { +func getASCIICString() -> (UnsafeMutablePointer, dealloc: () -> ()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x61 up[1] = 0x62 @@ -2151,7 +2160,7 @@ func getASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { return (up, { up.dealloc(100) }) } -func getNonASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { +func getNonASCIICString() -> (UnsafeMutablePointer, dealloc: () -> ()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0xd0 up[1] = 0xb0 @@ -2162,7 +2171,7 @@ func getNonASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { } func getIllFormedUTF8String1( -) -> (UnsafeMutablePointer, dealloc: ()->()) { +) -> (UnsafeMutablePointer, dealloc: () -> ()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x41 up[1] = 0xed @@ -2174,7 +2183,7 @@ func getIllFormedUTF8String1( } func getIllFormedUTF8String2( -) -> (UnsafeMutablePointer, dealloc: ()->()) { +) -> (UnsafeMutablePointer, dealloc: () -> ()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x41 up[1] = 0xed diff --git a/test/1_stdlib/NSValueBridging.swift b/test/1_stdlib/NSValueBridging.swift index fe7642d473b41..9b98cffcce3a7 100644 --- a/test/1_stdlib/NSValueBridging.swift +++ b/test/1_stdlib/NSValueBridging.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,6 +16,15 @@ // REQUIRES: objc_interop import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import Foundation var nsValueBridging = TestSuite("NSValueBridging") diff --git a/test/1_stdlib/NewArray.swift.gyb b/test/1_stdlib/NewArray.swift.gyb index d1bdb7e88ff40..2f37d96900533 100644 --- a/test/1_stdlib/NewArray.swift.gyb +++ b/test/1_stdlib/NewArray.swift.gyb @@ -1,9 +1,9 @@ %# -*- mode: swift -*- -//===--- Array.swift ------------------------------------------------------===// +//===--- NewArray.swift.gyb -----------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -30,14 +30,15 @@ final class X : ForwardIndexType, Comparable, CustomStringConvertible, IntegerLiteralConvertible { required init(_ value: Int) { - ++xCount - serial = ++xSerial + xCount += 1 + xSerial += 1 + serial = xSerial self.value = value } deinit { assert(serial > 0, "double destruction!") - --xCount + xCount -= 1 serial = -serial } @@ -142,7 +143,7 @@ where T.Generator.Element == T._Buffer.Element, checkEqual(x, y, false) func checkReallocations( - a: T, _ growthDescription: String, _ growBy1: (inout _: T)->() + a: T, _ growthDescription: String, _ growBy1: (inout _: T) -> () ) { var a = a var reallocations = 0 @@ -155,7 +156,7 @@ where T.Generator.Element == T._Buffer.Element, let oldId = bufferID(a) growBy1(&a) if oldId != bufferID(a) { - ++reallocations + reallocations += 1 } } @@ -166,8 +167,8 @@ where T.Generator.Element == T._Buffer.Element, } } - checkReallocations(x, "append") { (inout x: T)->() in x.append(42) } - checkReallocations(x, "+=") { (inout x: T)->() in x.append(42) } + checkReallocations(x, "append") { (inout x: T) -> () in x.append(42) } + checkReallocations(x, "+=") { (inout x: T) -> () in x.append(42) } print("done.") } @@ -269,7 +270,7 @@ func testCocoa() { // Prove that we create contiguous storage for an opaque NSArray a.withUnsafeBufferPointer { - (p)->() in + (p) -> () in print(p[0]) // CHECK-NEXT: foo } @@ -347,13 +348,13 @@ let testWidth = 11 %arrayTypes = ['ContiguousArray', 'Array', 'ArraySlice'] %for A in arrayTypes: -func testReplace(make: ()->${A}) { +func testReplace(make: () -> ${A}) { checkRangeReplaceable(make, { X(100)..${A} = { + makeOne: () -> ${A} = { var x = ${A}() // make sure some - but not all - replacements will have to grow the buffer x.reserveCapacity(testWidth * 3 / 2) diff --git a/test/1_stdlib/NewStringAppending.swift b/test/1_stdlib/NewStringAppending.swift index b703c30fd2d7f..d260e720ea85a 100644 --- a/test/1_stdlib/NewStringAppending.swift +++ b/test/1_stdlib/NewStringAppending.swift @@ -6,7 +6,7 @@ // like OpaqueString anyway, so we can just disable the failing // configuration // -// Memory allocator specifics also vary across platorms. +// Memory allocator specifics also vary across platforms. // REQUIRES: CPU=x86_64, OS=macosx import Foundation diff --git a/test/1_stdlib/NoFoundation.swift b/test/1_stdlib/NoFoundation.swift index c2128e551ca23..51daed0ddfcdf 100644 --- a/test/1_stdlib/NoFoundation.swift +++ b/test/1_stdlib/NoFoundation.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/NumericParsing.swift.gyb b/test/1_stdlib/NumericParsing.swift.gyb index 35a45f8f2ecd7..bad50e6f0e981 100644 --- a/test/1_stdlib/NumericParsing.swift.gyb +++ b/test/1_stdlib/NumericParsing.swift.gyb @@ -1,8 +1,8 @@ -//===--- NumericParsing.swift.gyb ----------------------------------------===// +//===--- NumericParsing.swift.gyb -----------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -16,20 +16,22 @@ // RUN: %S/../../utils/line-directive %t/NumericParsing.swift -- %target-run %t/a.out // REQUIRES: executable_test %{ -from SwiftIntTypes import * +from SwiftIntTypes import all_integer_types word_bits = int(CMAKE_SIZEOF_VOID_P) def maskOfWidth(n): return (1 << n) - 1 -def inRadix(radix, n, zero = '0'): +def inRadix(radix, n, zero='0'): """ Represent the int n in the given radix. Note: the third parameter, zero, is not for user consumption. """ - if n < 0: return '-' + inRadix(radix, -n, '') - elif n == 0: return zero + if n < 0: + return '-' + inRadix(radix, -n, '') + elif n == 0: + return zero else: r = n % radix digit = chr((ord('0') + r) if r < 10 else (ord('a') + r - 10)) @@ -43,7 +45,7 @@ radices_to_test = [2, 8, 10, 16, max_radix] # How many values to test in each radix? A nice prime number of course. number_of_values = 23 -}% +}% import StdlibUnittest @@ -92,6 +94,10 @@ tests.test("${Self}/success") { expectEqual(nil, ${Self}("${minValue - 1}")) expectEqual(nil, ${Self}("\u{1D7FF}")) // MATHEMATICAL MONOSPACE DIGIT NINE + // Cases that should fail to parse + expectEqual(nil, ${Self}("--0")) // Zero w/ repeated plus + expectEqual(nil, ${Self}("-+5")) // Non-zero with -+ + // Do more exhaustive testing % for radix in radices_to_test: % for n in required_values + range( diff --git a/test/1_stdlib/OptionSetTest.swift b/test/1_stdlib/OptionSetTest.swift index 9436f4b27cafe..dd1feb66b9cf9 100644 --- a/test/1_stdlib/OptionSetTest.swift +++ b/test/1_stdlib/OptionSetTest.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Optional.swift b/test/1_stdlib/Optional.swift index 34c69560a2f6f..7476c42914ba7 100644 --- a/test/1_stdlib/Optional.swift +++ b/test/1_stdlib/Optional.swift @@ -12,6 +12,17 @@ import SwiftPrivate import ObjectiveC #endif +class DeinitTester { + private let onDeinit: () -> () + + init(onDeinit: () -> ()) { + self.onDeinit = onDeinit + } + deinit { + onDeinit() + } +} + let OptionalTests = TestSuite("Optional") protocol TestProtocol1 {} @@ -140,7 +151,7 @@ OptionalTests.test("nil comparison") { OptionalTests.test("??") { var counter = 0 - func nextCounter() -> Int { return counter++ } + func nextCounter() -> Int { counter += 1; return counter-1 } func nextCounter2() -> Int? { return nextCounter() } let a: Int? = 123 @@ -216,6 +227,14 @@ OptionalTests.test("Casting Optional") { expectTrue(anyToAny(ssx, Optional.self)! === x) expectTrue(anyToAny(x, Optional>.self)!! === x) expectTrue(anyToAnyOrNil(ni, Int.self) == nil) + + // Test for SR-459: Weakened optionals don't zero. + var deinitRan = false + do { + var t = DeinitTester { deinitRan = true } + _ = anyToAny(Optional(t), CustomDebugStringConvertible.self) + } + expectTrue(deinitRan) } OptionalTests.test("Casting Optional Traps") { diff --git a/test/1_stdlib/Print.swift b/test/1_stdlib/Print.swift index 9ee1e5f964070..c5ad5e373e99b 100644 --- a/test/1_stdlib/Print.swift +++ b/test/1_stdlib/Print.swift @@ -1,1045 +1,80 @@ -// RUN: mkdir -p %t -// RUN: %target-build-swift %s -parse-stdlib -Xfrontend -disable-access-control -o %t/a.out -Xlinker -dead_strip -// RUN: %target-run %t/a.out env | FileCheck %s -// RUN: %target-run %t/a.out ru_RU.UTF-8 | FileCheck %s +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main // REQUIRES: executable_test -// XFAIL: linux +import StdlibUnittest +import PrintTestTypes -import Swift -import Darwin - -// Interpret the command line arguments. -var arg = Process.arguments[1] - -if arg == "env" { - setlocale(LC_ALL, "") -} else { - setlocale(LC_ALL, arg) -} - -func stdlibTypesHaveDescription() { - func hasDescription(_: CustomStringConvertible) {} - - hasDescription(Int(42)) - hasDescription(UInt(42)) - - hasDescription(Int8(-42)) - hasDescription(Int16(-42)) - hasDescription(Int32(-42)) - hasDescription(Int64(-42)) - hasDescription(UInt8(42)) - hasDescription(UInt16(42)) - hasDescription(UInt32(42)) - hasDescription(UInt64(42)) - - hasDescription(Bool(true)) - - hasDescription(CChar(42)) - hasDescription(CUnsignedChar(42)) - hasDescription(CUnsignedShort(42)) - hasDescription(CUnsignedInt(42)) - hasDescription(CUnsignedLong(42)) - hasDescription(CUnsignedLongLong(42)) - hasDescription(CSignedChar(42)) - hasDescription(CShort(42)) - hasDescription(CInt(42)) - hasDescription(CLong(42)) - hasDescription(CLongLong(42)) - hasDescription(CFloat(1.0)) - hasDescription(CDouble(1.0)) - - hasDescription(CWideChar(42)) - hasDescription(CChar16(42)) - hasDescription(CChar32(42)) - hasDescription(CBool(true)) -} - -var failed = false - -func printedIs( - object: T, _ expected1: String, expected2: String? = nil, - file: StaticString = __FILE__, line: UInt = __LINE__ -) { - let actual = String(object) - var match = expected1 == actual - if !match && expected2 != nil { - match = expected2! == actual - } - if !match { - print( - "check failed at \(file), line \(line)", - "expected: \"\(expected1)\" or \"\(expected2)\"", - "actual: \"\(actual)\"", - "", - separator: "\n") - failed = true - } -} - -func debugPrintedIs( - object: T, _ expected1: String, expected2: String? = nil, - file: StaticString = __FILE__, line: UInt = __LINE__ -) { - var actual = "" - debugPrint(object, terminator: "", toStream: &actual) - if expected1 != actual && (expected2 == nil || expected2! != actual) { - print( - "check failed at \(file), line \(line)", - "expected: \"\(expected1)\" or \"\(expected2)\"", - "actual: \"\(actual)\"", - "", - separator: "\n") - failed = true - } -} - -func assertEquals( - expected: String, _ actual: String, - file: StaticString = __FILE__, line: UInt = __LINE__ -) { - if expected != actual { - print( - "check failed at \(file), line \(line)", - "expected: \"\(expected)\"", - "actual: \"\(actual)\"", - "", - separator: "\n") - failed = true - } -} - -func test_StdlibTypesPrinted() { - printedIs(Float(1.0), "1.0") - printedIs(Float(-1.0), "-1.0") - printedIs(Double(1.0), "1.0") - printedIs(Double(-1.0), "-1.0") - - printedIs(CChar(42), "42") - printedIs(CUnsignedChar(42), "42") - printedIs(CUnsignedShort(42), "42") - printedIs(CUnsignedInt(42), "42") - printedIs(CUnsignedLong(42), "42") - printedIs(CUnsignedLongLong(42), "42") - printedIs(CSignedChar(42), "42") - printedIs(CShort(42), "42") - printedIs(CInt(42), "42") - printedIs(CLong(42), "42") - printedIs(CLongLong(42), "42") - printedIs(CFloat(1.0), "1.0") - printedIs(CFloat(-1.0), "-1.0") - printedIs(CDouble(1.0), "1.0") - printedIs(CDouble(-1.0), "-1.0") - - printedIs(CWideChar(42), "*") - printedIs(CChar16(42), "42") - printedIs(CChar32(42), "*") - printedIs(CBool(true), "true") - printedIs(CBool(false), "false") - - var s: String = "abc" - printedIs(s, "abc") - debugPrintedIs(s, "\"abc\"") - s = "\\ \' \" \0 \n \r \t \u{05}" - debugPrintedIs(s, "\"\\\\ \\\' \\\" \\0 \\n \\r \\t \\u{05}\"") - - let ch: Character = "a" - printedIs(ch, "a") - debugPrintedIs(ch, "\"a\"") - - var us: UnicodeScalar = "a" - printedIs(us, "a") - debugPrintedIs(us, "\"a\"") - us = "\\" - printedIs(us, "\\") - assertEquals("\"\\\\\"", us.description) - debugPrintedIs(us, "\"\\\\\"") - us = "あ" - printedIs(us, "あ") - assertEquals("\"あ\"", us.description) - debugPrintedIs(us, "\"\\u{3042}\"") - - do { - var implicitlyUnwrappedString: String! = nil - printedIs(implicitlyUnwrappedString, "nil") - implicitlyUnwrappedString = "meow" - printedIs(implicitlyUnwrappedString, "meow") - } - do { - var optionalString: String? = nil - printedIs(optionalString, "nil") - optionalString = "meow" - printedIs(optionalString, "Optional(\"meow\")") - } - do { - struct Wrapper : CustomStringConvertible { - var x: CustomStringConvertible? = nil - - var description: String { - return "Wrapper(" + x.debugDescription + ")" - } - } - printedIs(Wrapper(), "Wrapper(nil)") - printedIs(Wrapper(x: Wrapper()), "Wrapper(Optional(Wrapper(nil)))") - printedIs(Wrapper(x: Wrapper(x: Wrapper())), - "Wrapper(Optional(Wrapper(Optional(Wrapper(nil)))))") - } - - print("test_StdlibTypesPrinted done") -} -test_StdlibTypesPrinted() -// CHECK: test_StdlibTypesPrinted done - -func test_IntegerPrinting() { - if (UInt64(Int.max) > 0x1_0000_0000 as UInt64) { - printedIs(Int.min, "-9223372036854775808") - printedIs(Int.max, "9223372036854775807") - } else { - printedIs(Int.min, "-2147483648") - printedIs(Int.max, "2147483647") - } - printedIs(Int(0), "0") - printedIs(Int(42), "42") - printedIs(Int(-42), "-42") - - if (UInt64(UInt.max) > 0x1_0000_0000 as UInt64) { - printedIs(UInt.max, "18446744073709551615") - } else { - printedIs(UInt.max, "4294967295") - } - printedIs(UInt.min, "0") - printedIs(UInt(0), "0") - printedIs(UInt(42), "42") - - printedIs(Int8.min, "-128") - printedIs(Int8.max, "127") - printedIs(Int8(0), "0") - printedIs(Int8(42), "42") - printedIs(Int8(-42), "-42") - - printedIs(UInt8.min, "0") - printedIs(UInt8.max, "255") - printedIs(UInt8(0), "0") - printedIs(UInt8(42), "42") - - printedIs(Int16.min, "-32768") - printedIs(Int16.max, "32767") - printedIs(Int16(0), "0") - printedIs(Int16(42), "42") - printedIs(Int16(-42), "-42") - - printedIs(UInt16.min, "0") - printedIs(UInt16.max, "65535") - printedIs(UInt16(0), "0") - printedIs(UInt16(42), "42") - - printedIs(Int32.min, "-2147483648") - printedIs(Int32.max, "2147483647") - printedIs(Int32(0), "0") - printedIs(Int32(42), "42") - printedIs(Int32(-42), "-42") - - printedIs(UInt32.min, "0") - printedIs(UInt32.max, "4294967295") - printedIs(UInt32(0), "0") - printedIs(UInt32(42), "42") - - printedIs(Int64.min, "-9223372036854775808") - printedIs(Int64.max, "9223372036854775807") - printedIs(Int64(0), "0") - printedIs(Int64(42), "42") - printedIs(Int64(-42), "-42") - - printedIs(UInt64.min, "0") - printedIs(UInt64.max, "18446744073709551615") - printedIs(UInt64(0), "0") - printedIs(UInt64(42), "42") - - printedIs(Int8(-42), "-42") - printedIs(Int16(-42), "-42") - printedIs(Int32(-42), "-42") - printedIs(Int64(-42), "-42") - printedIs(UInt8(42), "42") - printedIs(UInt16(42), "42") - printedIs(UInt32(42), "42") - printedIs(UInt64(42), "42") - - print("test_IntegerPrinting done") -} -test_IntegerPrinting() -// CHECK: test_IntegerPrinting done - -func test_FloatingPointPrinting() { - func asFloat32(f: Float32) -> Float32 { return f } - func asFloat64(f: Float64) -> Float64 { return f } -#if arch(i386) || arch(x86_64) - func asFloat80(f: Swift.Float80) -> Swift.Float80 { return f } -#endif - - printedIs(Float.infinity, "inf") - printedIs(-Float.infinity, "-inf") - printedIs(Float.NaN, "nan") - printedIs(asFloat32(0.0), "0.0") - printedIs(asFloat32(1.0), "1.0") - printedIs(asFloat32(-1.0), "-1.0") - printedIs(asFloat32(100.125), "100.125") - printedIs(asFloat32(-100.125), "-100.125") - - printedIs(Double.infinity, "inf") - printedIs(-Double.infinity, "-inf") - printedIs(Double.NaN, "nan") - printedIs(asFloat64(0.0), "0.0") - printedIs(asFloat64(1.0), "1.0") - printedIs(asFloat64(-1.0), "-1.0") - printedIs(asFloat64(100.125), "100.125") - printedIs(asFloat64(-100.125), "-100.125") - - printedIs(asFloat32(1.00001), "1.00001") - printedIs(asFloat32(125000000000000000.0), "1.25e+17") - printedIs(asFloat32(12500000000000000.0), "1.25e+16") - printedIs(asFloat32(1250000000000000.0), "1.25e+15") - printedIs(asFloat32(125000000000000.0), "1.25e+14") - printedIs(asFloat32(12500000000000.0), "1.25e+13") - printedIs(asFloat32(1250000000000.0), "1.25e+12") - printedIs(asFloat32(125000000000.0), "1.25e+11") - printedIs(asFloat32(12500000000.0), "1.25e+10") - printedIs(asFloat32(1250000000.0), "1.25e+09") - printedIs(asFloat32(125000000.0), "1.25e+08") - printedIs(asFloat32(12500000.0), "1.25e+07") - printedIs(asFloat32(1250000.0), "1.25e+06") - printedIs(asFloat32(125000.0), "125000.0") - printedIs(asFloat32(12500.0), "12500.0") - printedIs(asFloat32(1250.0), "1250.0") - printedIs(asFloat32(125.0), "125.0") - printedIs(asFloat32(12.5), "12.5") - printedIs(asFloat32(1.25), "1.25") - printedIs(asFloat32(0.125), "0.125") - printedIs(asFloat32(0.0125), "0.0125") - printedIs(asFloat32(0.00125), "0.00125") - printedIs(asFloat32(0.000125), "0.000125") - printedIs(asFloat32(0.0000125), "1.25e-05") - printedIs(asFloat32(0.00000125), "1.25e-06") - printedIs(asFloat32(0.000000125), "1.25e-07") - printedIs(asFloat32(0.0000000125), "1.25e-08") - printedIs(asFloat32(0.00000000125), "1.25e-09") - printedIs(asFloat32(0.000000000125), "1.25e-10") - printedIs(asFloat32(0.0000000000125), "1.25e-11") - printedIs(asFloat32(0.00000000000125), "1.25e-12") - printedIs(asFloat32(0.000000000000125), "1.25e-13") - printedIs(asFloat32(0.0000000000000125), "1.25e-14") - printedIs(asFloat32(0.00000000000000125), "1.25e-15") - printedIs(asFloat32(0.000000000000000125), "1.25e-16") - printedIs(asFloat32(0.0000000000000000125), "1.25e-17") - - printedIs(asFloat64(1.00000000000001), "1.00000000000001") - printedIs(asFloat64(125000000000000000.0), "1.25e+17") - printedIs(asFloat64(12500000000000000.0), "1.25e+16") - printedIs(asFloat64(1250000000000000.0), "1.25e+15") - printedIs(asFloat64(125000000000000.0), "125000000000000.0") - printedIs(asFloat64(12500000000000.0), "12500000000000.0") - printedIs(asFloat64(1250000000000.0), "1250000000000.0") - printedIs(asFloat64(125000000000.0), "125000000000.0") - printedIs(asFloat64(12500000000.0), "12500000000.0") - printedIs(asFloat64(1250000000.0), "1250000000.0") - printedIs(asFloat64(125000000.0), "125000000.0") - printedIs(asFloat64(12500000.0), "12500000.0") - printedIs(asFloat64(1250000.0), "1250000.0") - printedIs(asFloat64(125000.0), "125000.0") - printedIs(asFloat64(12500.0), "12500.0") - printedIs(asFloat64(1250.0), "1250.0") - printedIs(asFloat64(125.0), "125.0") - printedIs(asFloat64(12.5), "12.5") - printedIs(asFloat64(1.25), "1.25") - printedIs(asFloat64(0.125), "0.125") - printedIs(asFloat64(0.0125), "0.0125") - printedIs(asFloat64(0.00125), "0.00125") - printedIs(asFloat64(0.000125), "0.000125") - printedIs(asFloat64(0.0000125), "1.25e-05") - printedIs(asFloat64(0.00000125), "1.25e-06") - printedIs(asFloat64(0.000000125), "1.25e-07") - printedIs(asFloat64(0.0000000125), "1.25e-08") - printedIs(asFloat64(0.00000000125), "1.25e-09") - printedIs(asFloat64(0.000000000125), "1.25e-10") - printedIs(asFloat64(0.0000000000125), "1.25e-11") - printedIs(asFloat64(0.00000000000125), "1.25e-12") - printedIs(asFloat64(0.000000000000125), "1.25e-13") - printedIs(asFloat64(0.0000000000000125), "1.25e-14") - printedIs(asFloat64(0.00000000000000125), "1.25e-15") - printedIs(asFloat64(0.000000000000000125), "1.25e-16") - printedIs(asFloat64(0.0000000000000000125), "1.25e-17") - -#if arch(i386) || arch(x86_64) - printedIs(asFloat80(1.00000000000000001), "1.00000000000000001") - printedIs(asFloat80(12500000000000000000.0), "1.25e+19") - printedIs(asFloat80(1250000000000000000.0), "1.25e+18") - printedIs(asFloat80(125000000000000000.0), "125000000000000000.0") - printedIs(asFloat80(12500000000000000.0), "12500000000000000.0") - printedIs(asFloat80(1250000000000000.0), "1250000000000000.0") - printedIs(asFloat80(125000000000000.0), "125000000000000.0") - printedIs(asFloat80(12500000000000.0), "12500000000000.0") - printedIs(asFloat80(1250000000000.0), "1250000000000.0") - printedIs(asFloat80(125000000000.0), "125000000000.0") - printedIs(asFloat80(12500000000.0), "12500000000.0") - printedIs(asFloat80(1250000000.0), "1250000000.0") - printedIs(asFloat80(125000000.0), "125000000.0") - printedIs(asFloat80(12500000.0), "12500000.0") - printedIs(asFloat80(1250000.0), "1250000.0") - printedIs(asFloat80(125000.0), "125000.0") - printedIs(asFloat80(12500.0), "12500.0") - printedIs(asFloat80(1250.0), "1250.0") - printedIs(asFloat80(125.0), "125.0") - printedIs(asFloat80(12.5), "12.5") - printedIs(asFloat80(1.25), "1.25") - printedIs(asFloat80(0.125), "0.125") - printedIs(asFloat80(0.0125), "0.0125") - printedIs(asFloat80(0.00125), "0.00125") - printedIs(asFloat80(0.000125), "0.000125") - printedIs(asFloat80(0.0000125), "1.25e-05") - printedIs(asFloat80(0.00000125), "1.25e-06") - printedIs(asFloat80(0.000000125), "1.25e-07") - printedIs(asFloat80(0.0000000125), "1.25e-08") - printedIs(asFloat80(0.00000000125), "1.25e-09") - printedIs(asFloat80(0.000000000125), "1.25e-10") - printedIs(asFloat80(0.0000000000125), "1.25e-11") - printedIs(asFloat80(0.00000000000125), "1.25e-12") - printedIs(asFloat80(0.000000000000125), "1.25e-13") - printedIs(asFloat80(0.0000000000000125), "1.25e-14") - printedIs(asFloat80(0.00000000000000125), "1.25e-15") - printedIs(asFloat80(0.000000000000000125), "1.25e-16") - printedIs(asFloat80(0.0000000000000000125), "1.25e-17") +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC #endif - debugPrintedIs(asFloat32(1.1), "1.10000002") - debugPrintedIs(asFloat32(125000000000000000.0), "1.24999998e+17") - debugPrintedIs(asFloat32(1.25), "1.25") - debugPrintedIs(asFloat32(0.0000125), "1.24999997e-05") - - debugPrintedIs(asFloat64(1.1), "1.1000000000000001") - debugPrintedIs(asFloat64(125000000000000000.0), "1.25e+17") - debugPrintedIs(asFloat64(1.25), "1.25") - debugPrintedIs(asFloat64(0.0000125), "1.2500000000000001e-05") - -#if arch(i386) || arch(x86_64) - debugPrintedIs(asFloat80(1.1), "1.10000000000000000002") - debugPrintedIs(asFloat80(125000000000000000.0), "125000000000000000.0") - debugPrintedIs(asFloat80(1.25), "1.25") - debugPrintedIs(asFloat80(0.0000125), "1.25000000000000000001e-05") -#endif - - print("test_FloatingPointPrinting done") -} -test_FloatingPointPrinting() -// CHECK: test_FloatingPointPrinting done - - -func test_BoolPrinting() { - printedIs(Bool(true), "true") - printedIs(Bool(false), "false") - - printedIs(true, "true") - printedIs(false, "false") - - print("test_BoolPrinting done") -} -test_BoolPrinting() -// CHECK: test_BoolPrinting done - -func test_CTypesPrinting() { - printedIs(CChar(42), "42") - printedIs(CUnsignedChar(42), "42") - printedIs(CUnsignedShort(42), "42") - printedIs(CUnsignedInt(42), "42") - printedIs(CUnsignedLong(42), "42") - printedIs(CUnsignedLongLong(42), "42") - printedIs(CSignedChar(42), "42") - printedIs(CShort(42), "42") - printedIs(CInt(42), "42") - printedIs(CLong(42), "42") - printedIs(CLongLong(42), "42") - printedIs(CFloat(1.0), "1.0") - printedIs(CFloat(-1.0), "-1.0") - printedIs(CDouble(1.0), "1.0") - printedIs(CDouble(-1.0), "-1.0") - - printedIs(CWideChar(42), "*") - printedIs(CChar16(42), "42") - printedIs(CChar32(42), "*") - printedIs(CBool(true), "true") - printedIs(CBool(false), "false") - - print("test_CTypesPrinting done") +let PrintTests = TestSuite("Print") +PrintTests.test("Metatype") { + expectPrinted("Int", Int.self) + expectDebugPrinted("Swift.Int", Int.self) } -test_CTypesPrinting() -// CHECK: test_CTypesPrinting done - - -func test_PointerPrinting() { - let nullUP = UnsafeMutablePointer() - let fourByteUP = UnsafeMutablePointer(bitPattern: 0xabcd1234 as UInt) - -#if !(arch(i386) || arch(arm)) - let eightByteAddr: UInt = 0xabcddcba12344321 - let eightByteUP = UnsafeMutablePointer(bitPattern: eightByteAddr) -#endif - -#if arch(i386) || arch(arm) - let expectedNull = "0x00000000" - printedIs(fourByteUP, "0xabcd1234") -#else - let expectedNull = "0x0000000000000000" - printedIs(fourByteUP, "0x00000000abcd1234") - printedIs(eightByteUP, "0xabcddcba12344321") -#endif - - printedIs(nullUP, expectedNull) - - printedIs(UnsafeBufferPointer(start: nullUP, count: 0), - "UnsafeBufferPointer(start: \(expectedNull), length: 0)") - printedIs(UnsafeMutableBufferPointer(start: nullUP, count: 0), - "UnsafeMutableBufferPointer(start: \(expectedNull), length: 0)") - - printedIs(COpaquePointer(), expectedNull) - printedIs(CVaListPointer(_fromUnsafeMutablePointer: nullUP), expectedNull) - printedIs(AutoreleasingUnsafeMutablePointer(), expectedNull) - - print("test_PointerPrinting done") -} -test_PointerPrinting() -// CHECK: test_PointerPrinting done - - -protocol ProtocolUnrelatedToPrinting {} - -struct StructPrintable : CustomStringConvertible, ProtocolUnrelatedToPrinting { - let x: Int - - init(_ x: Int) { - self.x = x - } - - var description: String { - return "►\(x)◀︎" - } -} - -struct LargeStructPrintable : CustomStringConvertible, ProtocolUnrelatedToPrinting { - let a: Int - let b: Int - let c: Int - let d: Int - - init(_ a: Int, _ b: Int, _ c: Int, _ d: Int) { - self.a = a - self.b = b - self.c = c - self.d = d - } - - var description: String { - return "<\(a) \(b) \(c) \(d)>" - } -} - -struct StructDebugPrintable : CustomDebugStringConvertible { - let x: Int - - init(_ x: Int) { - self.x = x - } - - var debugDescription: String { - return "►\(x)◀︎" - } -} - -struct StructVeryPrintable : CustomStringConvertible, CustomDebugStringConvertible, ProtocolUnrelatedToPrinting { - let x: Int - - init(_ x: Int) { - self.x = x - } - - var description: String { - return "" - } - - var debugDescription: String { - return "" - } -} - -struct EmptyStructWithoutDescription {} - -struct WithoutDescription { - let x: Int - - init(_ x: Int) { - self.x = x - } -} - -struct ValuesWithoutDescription { - let t: T - let u: U - let v: V - init(_ t: T, _ u: U, _ v: V) { - self.t = t - self.u = u - self.v = v - } -} - - -class ClassPrintable : CustomStringConvertible, ProtocolUnrelatedToPrinting { - let x: Int - - init(_ x: Int) { - self.x = x - } - - var description: String { - return "►\(x)◀︎" - } -} - -class ClassVeryPrintable : CustomStringConvertible, CustomDebugStringConvertible, ProtocolUnrelatedToPrinting { - let x: Int - - init(_ x: Int) { - self.x = x - } - - var description: String { - return "" - } - - var debugDescription: String { - return "" - } -} - -func test_ObjectPrinting() { - do { - let s = StructPrintable(1) - printedIs(s, "►1◀︎") - } - do { - let s: ProtocolUnrelatedToPrinting = StructPrintable(1) - printedIs(s, "►1◀︎") - } - do { - let s: CustomStringConvertible = StructPrintable(1) - printedIs(s, "►1◀︎") - } - do { - let s: Any = StructPrintable(1) - printedIs(s, "►1◀︎") - } - - do { - let s = LargeStructPrintable(10, 20, 30, 40) - printedIs(s, "<10 20 30 40>") - } - do { - let s: ProtocolUnrelatedToPrinting = LargeStructPrintable(10, 20, 30, 40) - printedIs(s, "<10 20 30 40>") - } - do { - let s: CustomStringConvertible = LargeStructPrintable(10, 20, 30, 40) - printedIs(s, "<10 20 30 40>") - } - do { - let s: Any = LargeStructPrintable(10, 20, 30, 40) - printedIs(s, "<10 20 30 40>") - } - - do { - let s = StructVeryPrintable(1) - printedIs(s, "") - } - do { - let s: ProtocolUnrelatedToPrinting = StructVeryPrintable(1) - printedIs(s, "") - } - do { - let s: CustomStringConvertible = StructVeryPrintable(1) - printedIs(s, "") - } - do { - let s: CustomDebugStringConvertible = StructVeryPrintable(1) - printedIs(s, "") - } - do { - let s: Any = StructVeryPrintable(1) - printedIs(s, "") - } - - do { - let c = ClassPrintable(1) - printedIs(c, "►1◀︎") - } - do { - let c: ProtocolUnrelatedToPrinting = ClassPrintable(1) - printedIs(c, "►1◀︎") - } - do { - let c: CustomStringConvertible = ClassPrintable(1) - printedIs(c, "►1◀︎") - } - do { - let c: Any = ClassPrintable(1) - printedIs(c, "►1◀︎") - } - - do { - let c = ClassVeryPrintable(1) - printedIs(c, "") - } - do { - let c: ProtocolUnrelatedToPrinting = ClassVeryPrintable(1) - printedIs(c, "") - } - do { - let c: CustomStringConvertible = ClassVeryPrintable(1) - printedIs(c, "") - } - do { - let c: CustomDebugStringConvertible = ClassVeryPrintable(1) - printedIs(c, "") - } - do { - let c: Any = ClassVeryPrintable(1) - printedIs(c, "") - } - - print("test_ObjectPrinting done") -} -test_ObjectPrinting() -// CHECK: test_ObjectPrinting done - -func test_ThickMetatypePrintingImpl( - thickMetatype: T.Type, - _ expectedPrint: String, - _ expectedDebug: String -) { - printedIs(thickMetatype, expectedPrint) - printedIs([ thickMetatype ], "[" + expectedDebug + "]") - debugPrintedIs(thickMetatype, expectedDebug) - debugPrintedIs([ thickMetatype ], "[" + expectedDebug + "]") -} - -func test_gcMetatypePrinting() { - let structMetatype = StructPrintable.self - printedIs(structMetatype, "StructPrintable") - debugPrintedIs(structMetatype, "a.StructPrintable") - printedIs([ structMetatype ], "[a.StructPrintable]") - debugPrintedIs([ structMetatype ], "[a.StructPrintable]") - test_ThickMetatypePrintingImpl(structMetatype, "StructPrintable", - "a.StructPrintable") - - let classMetatype = ClassPrintable.self - printedIs(classMetatype, "ClassPrintable") - debugPrintedIs(classMetatype, "a.ClassPrintable") - printedIs([ classMetatype ], "[a.ClassPrintable]") - debugPrintedIs([ classMetatype ], "[a.ClassPrintable]") - test_ThickMetatypePrintingImpl(classMetatype, "ClassPrintable", - "a.ClassPrintable") - - print("test_gcMetatypePrinting done") -} -test_gcMetatypePrinting() -// CHECK: test_gcMetatypePrinting done - -func test_ArrayPrinting() { - let arrayOfInts: [Int] = [] - printedIs(arrayOfInts, "[]") - - printedIs([ 1 ], "[1]") - printedIs([ 1, 2 ], "[1, 2]") - printedIs([ 1, 2, 3 ], "[1, 2, 3]") - - printedIs([ "foo", "bar", "bas" ], "[\"foo\", \"bar\", \"bas\"]") - debugPrintedIs([ "foo", "bar", "bas" ], "[\"foo\", \"bar\", \"bas\"]") - - printedIs([ StructPrintable(1), StructPrintable(2), - StructPrintable(3) ], - "[►1◀︎, ►2◀︎, ►3◀︎]") - - printedIs([ LargeStructPrintable(10, 20, 30, 40), - LargeStructPrintable(50, 60, 70, 80) ], - "[<10 20 30 40>, <50 60 70 80>]") - - printedIs([ StructDebugPrintable(1) ], "[►1◀︎]") - - printedIs([ ClassPrintable(1), ClassPrintable(2), - ClassPrintable(3) ], - "[►1◀︎, ►2◀︎, ►3◀︎]") - - printedIs([ ClassPrintable(1), ClassPrintable(2), - ClassPrintable(3) ] as Array, - "[►1◀︎, ►2◀︎, ►3◀︎]") - - print("test_ArrayPrinting done") -} -test_ArrayPrinting() -// CHECK: test_ArrayPrinting done - -func test_DictionaryPrinting() { - var dictSI: Dictionary = [:] - printedIs(dictSI, "[:]") - debugPrintedIs(dictSI, "[:]") - - dictSI = [ "aaa": 1 ] - printedIs(dictSI, "[\"aaa\": 1]") - debugPrintedIs(dictSI, "[\"aaa\": 1]") - - dictSI = [ "aaa": 1, "bbb": 2 ] - printedIs(dictSI, "[\"aaa\": 1, \"bbb\": 2]", expected2: "[\"bbb\": 2, \"aaa\": 1]") - debugPrintedIs(dictSI, "[\"aaa\": 1, \"bbb\": 2]", expected2: "[\"bbb\": 2, \"aaa\": 1]") - - let dictSS = [ "aaa": "bbb" ] - printedIs(dictSS, "[\"aaa\": \"bbb\"]") - debugPrintedIs(dictSS, "[\"aaa\": \"bbb\"]") - - print("test_DictionaryPrinting done") -} -test_DictionaryPrinting() -// CHECK: test_DictionaryPrinting done - -func test_SetPrinting() { - var sI = Set() - printedIs(sI, "[]") - debugPrintedIs(sI, "Set([])") - - sI = Set([11, 22]) - printedIs(sI, "[11, 22]", expected2: "[22, 11]") - debugPrintedIs(sI, "Set([11, 22])", expected2: "Set([22, 11])") - - let sS = Set(["Hello", "world"]) - printedIs(sS, "[\"Hello\", \"world\"]", expected2: "[\"world\", \"Hello\"]") - debugPrintedIs(sS, "Set([\"Hello\", \"world\"])", expected2: "Set([\"world\", \"Hello\"])") - - print("test_SetPrinting done") -} -test_SetPrinting() -// CHECK: test_SetPrinting done - -func test_TuplePrinting() { - let tuple1 = (42, ()) - printedIs(tuple1, "(42, ())") - - let tuple2 = ((), 42) - printedIs(tuple2, "((), 42)") - - let tuple3 = (42, StructPrintable(3)) - printedIs(tuple3, "(42, ►3◀︎)") - - let tuple4 = (42, LargeStructPrintable(10, 20, 30, 40)) - printedIs(tuple4, "(42, <10 20 30 40>)") - - let tuple5 = (42, ClassPrintable(3)) - printedIs(tuple5, "(42, ►3◀︎)") - - let tuple6 = ([123: 123], (1, 2, "3")) - printedIs(tuple6, "([123: 123], (1, 2, \"3\"))") - - let arrayOfTuples1 = - [ (1, "two", StructPrintable(3), StructDebugPrintable(4), - WithoutDescription(5)) ] - printedIs(arrayOfTuples1, "[(1, \"two\", ►3◀︎, ►4◀︎, a.WithoutDescription(x: 5))]") - - let arrayOfTuples2 = - [ (1, "two", WithoutDescription(3)), - (11, "twenty-two", WithoutDescription(33)), - (111, "two hundred twenty-two", WithoutDescription(333)) ] - printedIs(arrayOfTuples2, "[(1, \"two\", a.WithoutDescription(x: 3)), (11, \"twenty-two\", a.WithoutDescription(x: 33)), (111, \"two hundred twenty-two\", a.WithoutDescription(x: 333))]") - - print("test_TuplePrinting done") -} -test_TuplePrinting() -// CHECK: test_TuplePrinting done - -func test_ArbitraryStructPrinting() { - let arrayOfArbitraryStructs = - [ WithoutDescription(1), WithoutDescription(2), WithoutDescription(3) ] - printedIs( - arrayOfArbitraryStructs, - "[a.WithoutDescription(x: 1), a.WithoutDescription(x: 2), a.WithoutDescription(x: 3)]") - debugPrintedIs( - arrayOfArbitraryStructs, - "[a.WithoutDescription(x: 1), a.WithoutDescription(x: 2), a.WithoutDescription(x: 3)]") - - printedIs( - EmptyStructWithoutDescription(), - "EmptyStructWithoutDescription()") - debugPrintedIs( - EmptyStructWithoutDescription(), - "a.EmptyStructWithoutDescription()") - - printedIs( - ValuesWithoutDescription(1.25, "abc", [ 1, 2, 3 ]), - "ValuesWithoutDescription>(t: 1.25, u: \"abc\", v: [1, 2, 3])") - debugPrintedIs( - ValuesWithoutDescription(1.25, "abc", [ 1, 2, 3 ]), - "a.ValuesWithoutDescription>(t: 1.25, u: \"abc\", v: [1, 2, 3])") - - print("test_ArbitraryStructPrinting done") -} -test_ArbitraryStructPrinting() -// CHECK: test_ArbitraryStructPrinting done - -func test_MetatypePrinting() { - printedIs(Int.self, "Int") - debugPrintedIs(Int.self, "Swift.Int") - - print("test_MetatypePrinting done") -} -test_MetatypePrinting() -// CHECK: test_MetatypePrinting done - -func test_StringInterpolation() { - assertEquals("1", "\(1)") - assertEquals("2", "\(1 + 1)") - assertEquals("aaa1bbb2ccc", "aaa\(1)bbb\(2)ccc") - - assertEquals("1.0", "\(1.0)") - assertEquals("1.5", "\(1.5)") - assertEquals("1e-12", "\(1.0 / (1000000000000))") - - assertEquals("inf", "\(1 / 0.0)") - assertEquals("-inf", "\(-1 / 0.0)") - assertEquals("nan", "\(0 / 0.0)") - - assertEquals("<[►1◀︎, ►2◀︎, ►3◀︎]>", "<\([ StructPrintable(1), StructPrintable(2), StructPrintable(3) ])>") - assertEquals("WithoutDescription(x: 1)", "\(WithoutDescription(1))") - - print("test_StringInterpolation done") -} -test_StringInterpolation() -// CHECK: test_StringInterpolation done - -struct MyString : StringLiteralConvertible, StringInterpolationConvertible { - init(str: String) { - value = str - } - - var value: String - - init(unicodeScalarLiteral value: String) { - self.init(str: value) - } - - init(extendedGraphemeClusterLiteral value: String) { - self.init(str: value) - } - - init(stringLiteral value: String) { - self.init(str: value) - } - - init(stringInterpolation strings: MyString...) { - var result = "" - for s in strings { - result += s.value - } - self.init(str: result) - } - - init(stringInterpolationSegment expr: T) { - self.init(str: "") - } -} - -func test_CustomStringInterpolation() { - assertEquals("", - ("aaa\(1)bbb" as MyString).value) - - print("test_CustomStringInterpolation done") -} -test_CustomStringInterpolation() -// CHECK: test_CustomStringInterpolation done - -func test_StdoutUTF8Printing() { - print("\u{00B5}") -// CHECK: {{^}}µ{{$}} - - print("test_StdoutUTF8Printing done") +PrintTests.test("StringInterpolation") { + expectEqual("1", "\(1)") + expectEqual("2", "\(1 + 1)") + expectEqual("aaa1bbb2ccc", "aaa\(1)bbb\(2)ccc") + + expectEqual("1.0", "\(1.0)") + expectEqual("1.5", "\(1.5)") + expectEqual("1e-12", "\(1.0 / (1000000000000))") + + expectEqual("inf", "\(1 / 0.0)") + expectEqual("-inf", "\(-1 / 0.0)") + expectEqual("nan", "\(0 / 0.0)") + + expectEqual("<[►1◀︎, ►2◀︎, ►3◀︎]>", "<\([ StructPrintable(1), StructPrintable(2), StructPrintable(3) ])>") + expectEqual("WithoutDescription(x: 1)", "\(WithoutDescription(1))") } -test_StdoutUTF8Printing() -// CHECK: test_StdoutUTF8Printing done - -func test_varargs() { - print("", 1, 2, 3, 4, "", separator: "|") // CHECK: |1|2|3|4| - print(1, 2, 3, separator: "\n", terminator: "===") - print(4, 5, 6, separator: "\n") - // CHECK-NEXT: 1 - // CHECK-NEXT: 2 - // CHECK-NEXT: 3===4 - // CHECK-NEXT: 5 - // CHECK-NEXT: 6 - debugPrint("", 1, 2, 3, 4, "", separator: "|") - // CHECK-NEXT: ""|1|2|3|4|"" - debugPrint(1, 2, 3, separator: "\n", terminator: "===") - debugPrint(4, 5, 6, separator: "\n") - // CHECK-NEXT: 1 - // CHECK-NEXT: 2 - // CHECK-NEXT: 3===4 - // CHECK-NEXT: 5 - // CHECK-NEXT: 6 - - var output = "" - print( - "", 1, 2, 3, 4, "", separator: "|", toStream: &output) - print(output == "|1|2|3|4|\n") // CHECK-NEXT: true - output = "" - debugPrint( - "", 1, 2, 3, 4, "", separator: "|", terminator: "", toStream: &output) - print(output == "\"\"|1|2|3|4|\"\"") // CHECK-NEXT: true - print("test_varargs done") +PrintTests.test("StdoutUTF8") { + expectPrinted("µ", "\u{00B5}") } -test_varargs() -// CHECK: test_varargs done -func test_playgroundPrintHook() { - - var printed: String? = nil - _playgroundPrintHook = { printed = $0 } +PrintTests.test("Varargs") { + var s0 = "" + print("", 1, 2, 3, 4, "", separator: "|", toStream: &s0) + expectEqual("|1|2|3|4|\n", s0) - print("", 1, 2, 3, 4, "", separator: "|") // CHECK: |1|2|3|4| - print("%\(printed!)%") // CHECK-NEXT: %|1|2|3|4| - // CHECK-NEXT: % + var s1 = "" + print(1, 2, 3, separator: "\n", terminator: "===", toStream: &s1) + expectEqual("1\n2\n3===", s1) - printed = nil - debugPrint("", 1, 2, 3, 4, "", separator: "|") - // CHECK-NEXT: ""|1|2|3|4|"" - print("%\(printed!)%") // CHECK-NEXT: %""|1|2|3|4|"" - // CHECK-NEXT: % + var s2 = "" + print(4, 5, 6, separator: "\n", toStream: &s2) + expectEqual("4\n5\n6\n", s2) - var explicitStream = "" - printed = nil - print("", 1, 2, 3, 4, "", separator: "!", toStream: &explicitStream) - print(printed) // CHECK-NEXT: nil - print("%\(explicitStream)%") // CHECK-NEXT: %!1!2!3!4! - // CHECK-NEXT: % - - explicitStream = "" - printed = nil - debugPrint( - "", 1, 2, 3, 4, "", separator: "!", toStream: &explicitStream) - print(printed) // CHECK-NEXT: nil - print("%\(explicitStream)%") // CHECK-NEXT: %""!1!2!3!4!"" - // CHECK-NEXT: % - - _playgroundPrintHook = nil - print("test_playgroundPrintHook done") - // CHECK-NEXT: test_playgroundPrintHook done + var s3 = "" + print("", 1, 2, 3, 4, "", separator: "|", toStream: &s3) + expectEqual("|1|2|3|4|\n", s3) } -test_playgroundPrintHook() -if !failed { - print("OK") +PrintTests.test("PlaygroundPrintHook") { + var printed = "" + _playgroundPrintHook = { printed = $0 } + + var s0 = "" + print("", 1, 2, 3, 4, "", separator: "|", toStream: &s0) + expectEqual("|1|2|3|4|\n", s0) + print("%\(s0)%") + expectEqual("%|1|2|3|4|\n%\n", printed) + + printed = "" + var s1 = "" + print("", 1, 2, 3, 4, "", separator: "!", toStream: &s1) + expectEqual("", printed) + print("%\(s1)%") + expectEqual("%!1!2!3!4!\n%\n", printed) } -// CHECK: OK +runAllTests() diff --git a/test/1_stdlib/PrintArray.swift b/test/1_stdlib/PrintArray.swift new file mode 100644 index 0000000000000..e12c88f8b44f1 --- /dev/null +++ b/test/1_stdlib/PrintArray.swift @@ -0,0 +1,43 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main +// REQUIRES: executable_test + +import StdlibUnittest +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintArray") + +PrintTests.test("Printable") { + expectPrinted("[]", [Int]()) + expectPrinted("[1]", [ 1 ]) + expectPrinted("[1, 2]", [ 1, 2 ]) + expectPrinted("[1, 2, 3]", [ 1, 2, 3 ]) + + expectPrinted("[\"foo\", \"bar\", \"bas\"]", [ "foo", "bar", "bas" ]) + expectDebugPrinted("[\"foo\", \"bar\", \"bas\"]", [ "foo", "bar", "bas" ]) + + expectPrinted("[►1◀︎, ►2◀︎, ►3◀︎]", [ StructPrintable(1), + StructPrintable(2), StructPrintable(3) ]) + + expectPrinted("[<10 20 30 40>, <50 60 70 80>]", + [ LargeStructPrintable(10, 20, 30, 40), LargeStructPrintable(50, 60, 70, 80) ]) + + expectPrinted("[►1◀︎]", [ StructDebugPrintable(1) ]) + + expectPrinted("[►1◀︎, ►2◀︎, ►3◀︎]", [ ClassPrintable(1), + ClassPrintable(2), ClassPrintable(3) ]) + + expectPrinted("[►1◀︎, ►2◀︎, ►3◀︎]", [ ClassPrintable(1), + ClassPrintable(2), ClassPrintable(3) ] as Array) +} + +runAllTests() diff --git a/test/1_stdlib/PrintBoolean.swift b/test/1_stdlib/PrintBoolean.swift new file mode 100644 index 0000000000000..a595330108de7 --- /dev/null +++ b/test/1_stdlib/PrintBoolean.swift @@ -0,0 +1,35 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintBoolean") + +PrintTests.test("CustomStringConvertible") { + func hasDescription(any: Any) { + expectTrue(any is CustomStringConvertible) + } + + hasDescription(Bool(true)) + hasDescription(CBool(true)) +} + +PrintTests.test("Printable") { + expectPrinted("true", CBool(true)) + expectPrinted("false", CBool(false)) + + expectPrinted("true", Bool(true)) + expectPrinted("false", Bool(false)) + + expectPrinted("true", true) + expectPrinted("false", false) +} + +runAllTests() diff --git a/test/1_stdlib/PrintClass.swift b/test/1_stdlib/PrintClass.swift new file mode 100644 index 0000000000000..35bcd47fa0cfe --- /dev/null +++ b/test/1_stdlib/PrintClass.swift @@ -0,0 +1,51 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main +// REQUIRES: executable_test + +import StdlibUnittest +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintClass") + +PrintTests.test("ClassPrintable") { + let c0 = ClassPrintable(1) + let c1: ProtocolUnrelatedToPrinting = ClassPrintable(1) + let c2: CustomStringConvertible = ClassPrintable(1) + let c3: Any = ClassPrintable(1) + + expectPrinted("►1◀︎", c0) + expectPrinted("►1◀︎", c1) + expectPrinted("►1◀︎", c2) + expectPrinted("►1◀︎", c3) + + let classMetatype = ClassPrintable.self + expectPrinted("ClassPrintable", classMetatype) + expectDebugPrinted("PrintTestTypes.ClassPrintable", classMetatype) + expectPrinted("[PrintTestTypes.ClassPrintable]", [ classMetatype ]) + expectDebugPrinted("[PrintTestTypes.ClassPrintable]", [ classMetatype ]) +} + +PrintTests.test("ClassVeryPrintable") { + let c0 = ClassVeryPrintable(1) + let c1: ProtocolUnrelatedToPrinting = ClassVeryPrintable(1) + let c2: CustomStringConvertible = ClassVeryPrintable(1) + let c3: CustomDebugStringConvertible = ClassVeryPrintable(1) + let c4: Any = ClassVeryPrintable(1) + + expectPrinted("", c0) + expectPrinted("", c1) + expectPrinted("", c2) + expectPrinted("", c3) + expectPrinted("", c4) +} + +runAllTests() diff --git a/test/1_stdlib/PrintDictionary.swift b/test/1_stdlib/PrintDictionary.swift new file mode 100644 index 0000000000000..ed3eaba721702 --- /dev/null +++ b/test/1_stdlib/PrintDictionary.swift @@ -0,0 +1,33 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintDictionary") + +PrintTests.test("Printable") { + expectPrinted("[:]", [String: Int]()) + expectDebugPrinted("[:]", [String: Int]()) + + expectPrinted("[\"aaa\": 1]", [ "aaa": 1 ]) + expectDebugPrinted("[\"aaa\": 1]", [ "aaa": 1 ]) + + let d0 = [ "aaa": 1, "bbb": 2 ] + expectPrinted(expectedOneOf: [ "[\"aaa\": 1, \"bbb\": 2]", + "[\"bbb\": 2, \"aaa\": 1]" ], d0) + expectDebugPrinted(expectedOneOf: [ "[\"aaa\": 1, \"bbb\": 2]", + "[\"bbb\": 2, \"aaa\": 1]" ], d0) + + let d1 = [ "aaa": "bbb" ] + expectPrinted("[\"aaa\": \"bbb\"]", d1) + expectDebugPrinted("[\"aaa\": \"bbb\"]", d1) +} + +runAllTests() diff --git a/test/1_stdlib/PrintFloat.swift b/test/1_stdlib/PrintFloat.swift new file mode 100644 index 0000000000000..6b2178e2e2c01 --- /dev/null +++ b/test/1_stdlib/PrintFloat.swift @@ -0,0 +1,209 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main.out +// RUN: %target-run %t/main.out +// RUN: %target-run %t/main.out --locale ru_RU.UTF-8 +// REQUIRES: executable_test +// XFAIL: linux + +import StdlibUnittest +import Darwin +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintFloat") + +PrintTests.setUp { + if let localeArgIndex = Process.arguments.indexOf("--locale") { + let locale = Process.arguments[localeArgIndex + 1] + expectEqual("ru_RU.UTF-8", locale) + setlocale(LC_ALL, locale) + } else { + setlocale(LC_ALL, "") + } +} + +PrintTests.test("CustomStringConvertible") { + func hasDescription(any: Any) { + expectTrue(any is CustomStringConvertible) + } + + hasDescription(CFloat(1.0)) + hasDescription(CDouble(1.0)) +} + +PrintTests.test("Printable") { + func asFloat32(f: Float32) -> Float32 { return f } + func asFloat64(f: Float64) -> Float64 { return f } +#if arch(i386) || arch(x86_64) + func asFloat80(f: Swift.Float80) -> Swift.Float80 { return f } +#endif + + expectPrinted("1.0", Float(1.0)) + expectPrinted("-1.0", Float(-1.0)) + expectPrinted("1.0", Double(1.0)) + expectPrinted("-1.0", Double(-1.0)) + + expectPrinted("1.0", CFloat(1.0)) + expectPrinted("-1.0", CFloat(-1.0)) + expectPrinted("1.0", CDouble(1.0)) + expectPrinted("-1.0", CDouble(-1.0)) + + expectPrinted("inf", Float.infinity) + expectPrinted("-inf", -Float.infinity) + expectPrinted("nan", Float.NaN) + expectPrinted("0.0", asFloat32(0.0)) + expectPrinted("1.0", asFloat32(1.0)) + expectPrinted("-1.0", asFloat32(-1.0)) + expectPrinted("100.125", asFloat32(100.125)) + expectPrinted("-100.125", asFloat32(-100.125)) + + expectPrinted("inf", Double.infinity) + expectPrinted("-inf", -Double.infinity) + expectPrinted("nan", Double.NaN) + expectPrinted("0.0", asFloat64(0.0)) + expectPrinted("1.0", asFloat64(1.0)) + expectPrinted("-1.0", asFloat64(-1.0)) + expectPrinted("100.125", asFloat64(100.125)) + expectPrinted("-100.125", asFloat64(-100.125)) + + expectPrinted("1.00001", asFloat32(1.00001)) + expectPrinted("1.25e+17", asFloat32(125000000000000000.0)) + expectPrinted("1.25e+16", asFloat32(12500000000000000.0)) + expectPrinted("1.25e+15", asFloat32(1250000000000000.0)) + expectPrinted("1.25e+14", asFloat32(125000000000000.0)) + expectPrinted("1.25e+13", asFloat32(12500000000000.0)) + expectPrinted("1.25e+12", asFloat32(1250000000000.0)) + expectPrinted("1.25e+11", asFloat32(125000000000.0)) + expectPrinted("1.25e+10", asFloat32(12500000000.0)) + expectPrinted("1.25e+09", asFloat32(1250000000.0)) + expectPrinted("1.25e+08", asFloat32(125000000.0)) + expectPrinted("1.25e+07", asFloat32(12500000.0)) + expectPrinted("1.25e+06", asFloat32(1250000.0)) + expectPrinted("125000.0", asFloat32(125000.0)) + expectPrinted("12500.0", asFloat32(12500.0)) + expectPrinted("1250.0", asFloat32(1250.0)) + expectPrinted("125.0", asFloat32(125.0)) + expectPrinted("12.5", asFloat32(12.5)) + expectPrinted("1.25", asFloat32(1.25)) + expectPrinted("0.125", asFloat32(0.125)) + expectPrinted("0.0125", asFloat32(0.0125)) + expectPrinted("0.00125", asFloat32(0.00125)) + expectPrinted("0.000125", asFloat32(0.000125)) + expectPrinted("1.25e-05", asFloat32(0.0000125)) + expectPrinted("1.25e-06", asFloat32(0.00000125)) + expectPrinted("1.25e-07", asFloat32(0.000000125)) + expectPrinted("1.25e-08", asFloat32(0.0000000125)) + expectPrinted("1.25e-09", asFloat32(0.00000000125)) + expectPrinted("1.25e-10", asFloat32(0.000000000125)) + expectPrinted("1.25e-11", asFloat32(0.0000000000125)) + expectPrinted("1.25e-12", asFloat32(0.00000000000125)) + expectPrinted("1.25e-13", asFloat32(0.000000000000125)) + expectPrinted("1.25e-14", asFloat32(0.0000000000000125)) + expectPrinted("1.25e-15", asFloat32(0.00000000000000125)) + expectPrinted("1.25e-16", asFloat32(0.000000000000000125)) + expectPrinted("1.25e-17", asFloat32(0.0000000000000000125)) + + expectPrinted("1.00000000000001", asFloat64(1.00000000000001)) + expectPrinted("1.25e+17", asFloat64(125000000000000000.0)) + expectPrinted("1.25e+16", asFloat64(12500000000000000.0)) + expectPrinted("1.25e+15", asFloat64(1250000000000000.0)) + expectPrinted("125000000000000.0", asFloat64(125000000000000.0)) + expectPrinted("12500000000000.0", asFloat64(12500000000000.0)) + expectPrinted("1250000000000.0", asFloat64(1250000000000.0)) + expectPrinted("125000000000.0", asFloat64(125000000000.0)) + expectPrinted("12500000000.0", asFloat64(12500000000.0)) + expectPrinted("1250000000.0", asFloat64(1250000000.0)) + expectPrinted("125000000.0", asFloat64(125000000.0)) + expectPrinted("12500000.0", asFloat64(12500000.0)) + expectPrinted("1250000.0", asFloat64(1250000.0)) + expectPrinted("125000.0", asFloat64(125000.0)) + expectPrinted("12500.0", asFloat64(12500.0)) + expectPrinted("1250.0", asFloat64(1250.0)) + expectPrinted("125.0", asFloat64(125.0)) + expectPrinted("12.5", asFloat64(12.5)) + expectPrinted("1.25", asFloat64(1.25)) + expectPrinted("0.125", asFloat64(0.125)) + expectPrinted("0.0125", asFloat64(0.0125)) + expectPrinted("0.00125", asFloat64(0.00125)) + expectPrinted("0.000125", asFloat64(0.000125)) + expectPrinted("1.25e-05", asFloat64(0.0000125)) + expectPrinted("1.25e-06", asFloat64(0.00000125)) + expectPrinted("1.25e-07", asFloat64(0.000000125)) + expectPrinted("1.25e-08", asFloat64(0.0000000125)) + expectPrinted("1.25e-09", asFloat64(0.00000000125)) + expectPrinted("1.25e-10", asFloat64(0.000000000125)) + expectPrinted("1.25e-11", asFloat64(0.0000000000125)) + expectPrinted("1.25e-12", asFloat64(0.00000000000125)) + expectPrinted("1.25e-13", asFloat64(0.000000000000125)) + expectPrinted("1.25e-14", asFloat64(0.0000000000000125)) + expectPrinted("1.25e-15", asFloat64(0.00000000000000125)) + expectPrinted("1.25e-16", asFloat64(0.000000000000000125)) + expectPrinted("1.25e-17", asFloat64(0.0000000000000000125)) + +#if arch(i386) || arch(x86_64) + expectPrinted("1.00000000000000001", asFloat80(1.00000000000000001)) + expectPrinted("1.25e+19", asFloat80(12500000000000000000.0)) + expectPrinted("1.25e+18", asFloat80(1250000000000000000.0)) + expectPrinted("125000000000000000.0", asFloat80(125000000000000000.0)) + expectPrinted("12500000000000000.0", asFloat80(12500000000000000.0)) + expectPrinted("1250000000000000.0", asFloat80(1250000000000000.0)) + expectPrinted("125000000000000.0", asFloat80(125000000000000.0)) + expectPrinted("12500000000000.0", asFloat80(12500000000000.0)) + expectPrinted("1250000000000.0", asFloat80(1250000000000.0)) + expectPrinted("125000000000.0", asFloat80(125000000000.0)) + expectPrinted("12500000000.0", asFloat80(12500000000.0)) + expectPrinted("1250000000.0", asFloat80(1250000000.0)) + expectPrinted("125000000.0", asFloat80(125000000.0)) + expectPrinted("12500000.0", asFloat80(12500000.0)) + expectPrinted("1250000.0", asFloat80(1250000.0)) + expectPrinted("125000.0", asFloat80(125000.0)) + expectPrinted("12500.0", asFloat80(12500.0)) + expectPrinted("1250.0", asFloat80(1250.0)) + expectPrinted("125.0", asFloat80(125.0)) + expectPrinted("12.5", asFloat80(12.5)) + expectPrinted("1.25", asFloat80(1.25)) + expectPrinted("0.125", asFloat80(0.125)) + expectPrinted("0.0125", asFloat80(0.0125)) + expectPrinted("0.00125", asFloat80(0.00125)) + expectPrinted("0.000125", asFloat80(0.000125)) + expectPrinted("1.25e-05", asFloat80(0.0000125)) + expectPrinted("1.25e-06", asFloat80(0.00000125)) + expectPrinted("1.25e-07", asFloat80(0.000000125)) + expectPrinted("1.25e-08", asFloat80(0.0000000125)) + expectPrinted("1.25e-09", asFloat80(0.00000000125)) + expectPrinted("1.25e-10", asFloat80(0.000000000125)) + expectPrinted("1.25e-11", asFloat80(0.0000000000125)) + expectPrinted("1.25e-12", asFloat80(0.00000000000125)) + expectPrinted("1.25e-13", asFloat80(0.000000000000125)) + expectPrinted("1.25e-14", asFloat80(0.0000000000000125)) + expectPrinted("1.25e-15", asFloat80(0.00000000000000125)) + expectPrinted("1.25e-16", asFloat80(0.000000000000000125)) + expectPrinted("1.25e-17", asFloat80(0.0000000000000000125)) +#endif + + expectDebugPrinted("1.10000002", asFloat32(1.1)) + expectDebugPrinted("1.24999998e+17", asFloat32(125000000000000000.0)) + expectDebugPrinted("1.25", asFloat32(1.25)) + expectDebugPrinted("1.24999997e-05", asFloat32(0.0000125)) + + expectDebugPrinted("1.1000000000000001", asFloat64(1.1)) + expectDebugPrinted("1.25e+17", asFloat64(125000000000000000.0)) + expectDebugPrinted("1.25", asFloat64(1.25)) + expectDebugPrinted("1.2500000000000001e-05", asFloat64(0.0000125)) + +#if arch(i386) || arch(x86_64) + expectDebugPrinted("1.10000000000000000002", asFloat80(1.1)) + expectDebugPrinted("125000000000000000.0", asFloat80(125000000000000000.0)) + expectDebugPrinted("1.25", asFloat80(1.25)) + expectDebugPrinted("1.25000000000000000001e-05", asFloat80(0.0000125)) +#endif +} + +runAllTests() diff --git a/test/1_stdlib/PrintInteger.swift b/test/1_stdlib/PrintInteger.swift new file mode 100644 index 0000000000000..491b7059e7300 --- /dev/null +++ b/test/1_stdlib/PrintInteger.swift @@ -0,0 +1,155 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintInteger") +PrintTests.test("CustomStringConvertible") { + func hasDescription(any: Any) { + expectTrue(any is CustomStringConvertible) + } + + hasDescription(Int(42)) + hasDescription(UInt(42)) + + hasDescription(Int8(-42)) + hasDescription(Int16(-42)) + hasDescription(Int32(-42)) + hasDescription(Int64(-42)) + hasDescription(UInt8(42)) + hasDescription(UInt16(42)) + hasDescription(UInt32(42)) + hasDescription(UInt64(42)) + + hasDescription(CChar(42)) + hasDescription(CUnsignedChar(42)) + hasDescription(CUnsignedShort(42)) + hasDescription(CUnsignedInt(42)) + hasDescription(CUnsignedLong(42)) + hasDescription(CUnsignedLongLong(42)) + hasDescription(CSignedChar(42)) + hasDescription(CShort(42)) + hasDescription(CInt(42)) + hasDescription(CLong(42)) + hasDescription(CLongLong(42)) + hasDescription(CWideChar(42)) + hasDescription(CChar16(42)) + hasDescription(CChar32(42)) +} + +PrintTests.test("Printable") { + expectPrinted("42", CChar(42)) + expectPrinted("42", CUnsignedChar(42)) + expectPrinted("42", CUnsignedShort(42)) + expectPrinted("42", CUnsignedInt(42)) + expectPrinted("42", CUnsignedLong(42)) + expectPrinted("42", CUnsignedLongLong(42)) + expectPrinted("42", CSignedChar(42)) + expectPrinted("42", CShort(42)) + expectPrinted("42", CInt(42)) + expectPrinted("42", CLong(42)) + expectPrinted("42", CLongLong(42)) + expectPrinted("*", CWideChar(42)) + expectPrinted("42", CChar16(42)) + expectPrinted("*", CChar32(42)) + + if (UInt64(Int.max) > 0x1_0000_0000 as UInt64) { + expectPrinted("-9223372036854775808", Int.min) + expectPrinted("9223372036854775807", Int.max) + } else { + expectPrinted("-2147483648", Int.min) + expectPrinted("2147483647", Int.max) + } + + expectPrinted("0", Int(0)) + expectPrinted("42", Int(42)) + expectPrinted("-42", Int(-42)) + + if (UInt64(UInt.max) > 0x1_0000_0000 as UInt64) { + expectPrinted("18446744073709551615", UInt.max) + } else { + expectPrinted("4294967295", UInt.max) + } + + expectPrinted("0", UInt.min) + expectPrinted("0", UInt(0)) + expectPrinted("42", UInt(42)) + + expectPrinted("-128", Int8.min) + expectPrinted("127", Int8.max) + expectPrinted("0", Int8(0)) + expectPrinted("42", Int8(42)) + expectPrinted("-42", Int8(-42)) + + expectPrinted("0", UInt8.min) + expectPrinted("255", UInt8.max) + expectPrinted("0", UInt8(0)) + expectPrinted("42", UInt8(42)) + + expectPrinted("-32768", Int16.min) + expectPrinted("32767", Int16.max) + expectPrinted("0", Int16(0)) + expectPrinted("42", Int16(42)) + expectPrinted("-42", Int16(-42)) + + expectPrinted("0", UInt16.min) + expectPrinted("65535", UInt16.max) + expectPrinted("0", UInt16(0)) + expectPrinted("42", UInt16(42)) + + expectPrinted("-2147483648", Int32.min) + expectPrinted("2147483647", Int32.max) + expectPrinted("0", Int32(0)) + expectPrinted("42", Int32(42)) + expectPrinted("-42", Int32(-42)) + + expectPrinted("0", UInt32.min) + expectPrinted("4294967295", UInt32.max) + expectPrinted("0", UInt32(0)) + expectPrinted("42", UInt32(42)) + + expectPrinted("-9223372036854775808", Int64.min) + expectPrinted("9223372036854775807", Int64.max) + expectPrinted("0", Int64(0)) + expectPrinted("42", Int64(42)) + expectPrinted("-42", Int64(-42)) + + expectPrinted("0", UInt64.min) + expectPrinted("18446744073709551615", UInt64.max) + expectPrinted("0", UInt64(0)) + expectPrinted("42", UInt64(42)) + + expectPrinted("-42", Int8(-42)) + expectPrinted("-42", Int16(-42)) + expectPrinted("-42", Int32(-42)) + expectPrinted("-42", Int64(-42)) + expectPrinted("42", UInt8(42)) + expectPrinted("42", UInt16(42)) + expectPrinted("42", UInt32(42)) + expectPrinted("42", UInt64(42)) + + expectPrinted("42", CChar(42)) + expectPrinted("42", CUnsignedChar(42)) + expectPrinted("42", CUnsignedShort(42)) + expectPrinted("42", CUnsignedInt(42)) + expectPrinted("42", CUnsignedLong(42)) + expectPrinted("42", CUnsignedLongLong(42)) + expectPrinted("42", CSignedChar(42)) + expectPrinted("42", CShort(42)) + expectPrinted("42", CInt(42)) + expectPrinted("42", CLong(42)) + expectPrinted("42", CLongLong(42)) + + expectPrinted("*", CWideChar(42)) + expectPrinted("42", CChar16(42)) + expectPrinted("*", CChar32(42)) +} + +runAllTests() diff --git a/test/1_stdlib/PrintPointer.swift b/test/1_stdlib/PrintPointer.swift new file mode 100644 index 0000000000000..e1b5f682c4e32 --- /dev/null +++ b/test/1_stdlib/PrintPointer.swift @@ -0,0 +1,46 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintPointer") +PrintTests.test("Printable") { + let nullUP = UnsafeMutablePointer() + let fourByteUP = UnsafeMutablePointer(bitPattern: 0xabcd1234 as UInt) + +#if !(arch(i386) || arch(arm)) + let eightByteAddr: UInt = 0xabcddcba12344321 + let eightByteUP = UnsafeMutablePointer(bitPattern: eightByteAddr) +#endif + +#if arch(i386) || arch(arm) + let expectedNull = "0x00000000" + expectPrinted("0xabcd1234", fourByteUP) +#else + let expectedNull = "0x0000000000000000" + expectPrinted("0x00000000abcd1234", fourByteUP) + expectPrinted("0xabcddcba12344321", eightByteUP) +#endif + + expectPrinted(expectedNull, nullUP) + + expectPrinted("UnsafeBufferPointer(start: \(expectedNull), length: 0)", + UnsafeBufferPointer(start: nullUP, count: 0)) + expectPrinted("UnsafeMutableBufferPointer(start: \(expectedNull), length: 0)", + UnsafeMutableBufferPointer(start: nullUP, count: 0)) + + expectPrinted(expectedNull, COpaquePointer()) + expectPrinted(expectedNull, CVaListPointer(_fromUnsafeMutablePointer: nullUP)) +#if _runtime(_ObjC) + expectPrinted(expectedNull, AutoreleasingUnsafeMutablePointer()) +#endif +} + +runAllTests() diff --git a/test/1_stdlib/PrintSet.swift b/test/1_stdlib/PrintSet.swift new file mode 100644 index 0000000000000..5c32dec9ea7eb --- /dev/null +++ b/test/1_stdlib/PrintSet.swift @@ -0,0 +1,30 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintSet") +PrintTests.test("Printable") { + expectPrinted("[]", Set()) + expectDebugPrinted("Set([])", Set()) + + let s0 = Set([11, 22]) + expectPrinted(expectedOneOf: [ "[11, 22]", "[22, 11]" ], s0) + expectDebugPrinted(expectedOneOf: [ "Set([11, 22])", + "Set([22, 11])" ], s0) + + let s1 = Set(["Hello", "world"]) + expectPrinted(expectedOneOf: [ "[\"Hello\", \"world\"]", + "[\"world\", \"Hello\"]" ], s1) + expectDebugPrinted(expectedOneOf: [ "Set([\"Hello\", \"world\"])", + "Set([\"world\", \"Hello\"])" ], s1) +} + +runAllTests() diff --git a/test/1_stdlib/PrintString.swift b/test/1_stdlib/PrintString.swift new file mode 100644 index 0000000000000..600847bb70a19 --- /dev/null +++ b/test/1_stdlib/PrintString.swift @@ -0,0 +1,57 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main +// REQUIRES: executable_test + +import StdlibUnittest +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintString") +PrintTests.test("Printable") { + let s0: String = "abc" + expectPrinted("abc", s0) + expectDebugPrinted("\"abc\"", s0) + + let s1: String = "\\ \' \" \0 \n \r \t \u{05}" + expectDebugPrinted("\"\\\\ \\\' \\\" \\0 \\n \\r \\t \\u{05}\"", s1) + + let ch: Character = "a" + expectPrinted("a", ch) + expectDebugPrinted("\"a\"", ch) + + let us0: UnicodeScalar = "a" + expectPrinted("a", us0) + expectDebugPrinted("\"a\"", us0) + + let us1: UnicodeScalar = "\\" + expectPrinted("\\", us1) + expectEqual("\"\\\\\"", us1.description) + expectDebugPrinted("\"\\\\\"", us1) + + let us2: UnicodeScalar = "あ" + expectPrinted("あ", us2) + expectEqual("\"あ\"", us2.description) + expectDebugPrinted("\"\\u{3042}\"", us2) +} + +PrintTests.test("Printable") { + expectPrinted("nil", String!()) + expectPrinted("meow", String!("meow")) + expectPrinted("nil", String?()) + expectPrinted("Optional(\"meow\")", String?("meow")) +} + +PrintTests.test("CustomStringInterpolation") { + let s = ("aaa\(1)bbb" as MyString).value + expectEqual("", s) +} + +runAllTests() diff --git a/test/1_stdlib/PrintStruct.swift b/test/1_stdlib/PrintStruct.swift new file mode 100644 index 0000000000000..7b4fad465c2b4 --- /dev/null +++ b/test/1_stdlib/PrintStruct.swift @@ -0,0 +1,114 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main +// REQUIRES: executable_test + +import StdlibUnittest +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintStruct") + +PrintTests.test("Printable") { + let s0 = [ WithoutDescription(1), WithoutDescription(2), WithoutDescription(3) ] + expectPrinted( + "[PrintTestTypes.WithoutDescription(x: 1), PrintTestTypes.WithoutDescription(x: 2), PrintTestTypes.WithoutDescription(x: 3)]", + s0) + expectDebugPrinted( + "[PrintTestTypes.WithoutDescription(x: 1), PrintTestTypes.WithoutDescription(x: 2), PrintTestTypes.WithoutDescription(x: 3)]", + s0) + + expectPrinted("EmptyStructWithoutDescription()", + EmptyStructWithoutDescription()) + expectDebugPrinted("PrintTestTypes.EmptyStructWithoutDescription()", + EmptyStructWithoutDescription()) + + expectPrinted( + "ValuesWithoutDescription>(t: 1.25, u: \"abc\", v: [1, 2, 3])", + ValuesWithoutDescription(1.25, "abc", [ 1, 2, 3 ])) + expectDebugPrinted( + "PrintTestTypes.ValuesWithoutDescription>(t: 1.25, u: \"abc\", v: [1, 2, 3])", ValuesWithoutDescription(1.25, "abc", [ 1, 2, 3 ])) +} + +PrintTests.test("custom string convertible structs") { + struct Wrapper : CustomStringConvertible { + var x: CustomStringConvertible? = nil + + var description: String { + return "Wrapper(\(x.debugDescription))" + } + } + + expectPrinted("Wrapper(nil)", Wrapper()) + expectPrinted("Wrapper(Optional(Wrapper(nil)))", + Wrapper(x: Wrapper())) + expectPrinted("Wrapper(Optional(Wrapper(Optional(Wrapper(nil)))))", + Wrapper(x: Wrapper(x: Wrapper()))) +} + +func test_ThickMetatypePrintingImpl( + thickMetatype: T.Type, + _ expectedPrint: String, + _ expectedDebug: String + ) { + expectPrinted(expectedPrint, thickMetatype) + expectPrinted("[\(expectedDebug)]", [ thickMetatype ]) + expectDebugPrinted(expectedDebug, thickMetatype) + expectDebugPrinted("[\(expectedDebug)]", [ thickMetatype ]) +} + +PrintTests.test("StructPrintable") { + let s0 = StructPrintable(1) + let s1: ProtocolUnrelatedToPrinting = StructPrintable(1) + let s2: CustomStringConvertible = StructPrintable(1) + let s3: Any = StructPrintable(1) + + expectPrinted("►1◀︎", s0) + expectPrinted("►1◀︎", s1) + expectPrinted("►1◀︎", s2) + expectPrinted("►1◀︎", s3) + + let structMetatype = StructPrintable.self + expectPrinted("StructPrintable", structMetatype) + expectDebugPrinted("PrintTestTypes.StructPrintable", structMetatype) + expectPrinted("[PrintTestTypes.StructPrintable]", [ structMetatype ]) + expectDebugPrinted("[PrintTestTypes.StructPrintable]", [ structMetatype ]) + test_ThickMetatypePrintingImpl(structMetatype, "StructPrintable", + "PrintTestTypes.StructPrintable") +} + +PrintTests.test("LargeStructPrintable") { + let s0 = LargeStructPrintable(10, 20, 30, 40) + let s1: ProtocolUnrelatedToPrinting = LargeStructPrintable(10, 20, 30, 40) + let s2: CustomStringConvertible = LargeStructPrintable(10, 20, 30, 40) + let s3: Any = LargeStructPrintable(10, 20, 30, 40) + + expectPrinted("<10 20 30 40>", s0) + expectPrinted("<10 20 30 40>", s1) + expectPrinted("<10 20 30 40>", s2) + expectPrinted("<10 20 30 40>", s0) + expectPrinted("<10 20 30 40>", s3) +} + +PrintTests.test("StructVeryPrintable") { + let s0 = StructVeryPrintable(1) + let s1: ProtocolUnrelatedToPrinting = StructVeryPrintable(1) + let s2: CustomStringConvertible = StructVeryPrintable(1) + let s3: CustomDebugStringConvertible = StructVeryPrintable(1) + let s4: Any = StructVeryPrintable(1) + + expectPrinted("", s0) + expectPrinted("", s1) + expectPrinted("", s2) + expectPrinted("", s3) + expectPrinted("", s4) +} + +runAllTests() diff --git a/test/1_stdlib/PrintTuple.swift b/test/1_stdlib/PrintTuple.swift new file mode 100644 index 0000000000000..a4e65588c7743 --- /dev/null +++ b/test/1_stdlib/PrintTuple.swift @@ -0,0 +1,39 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: %target-build-swift -c -force-single-frontend-invocation -parse-as-library -emit-module -emit-module-path %t/PrintTestTypes.swiftmodule -o %t/PrintTestTypes.o %S/Inputs/PrintTestTypes.swift +// RUN: %target-build-swift %s -Xlinker %t/PrintTestTypes.o -I %t -L %t -o %t/main +// RUN: %target-run %t/main +// REQUIRES: executable_test + +import StdlibUnittest +import PrintTestTypes + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let PrintTests = TestSuite("PrintTuple") +PrintTests.test("Printable") { + expectPrinted("(42, ())", (42, ())) + expectPrinted("((), 42)", ((), 42)) + expectPrinted("(42, ►3◀︎)", (42, StructPrintable(3))) + expectPrinted("(42, <10 20 30 40>)", + (42, LargeStructPrintable(10, 20, 30, 40))) + expectPrinted("(42, ►3◀︎)", (42, ClassPrintable(3))) + expectPrinted("([123: 123], (1, 2, \"3\"))", + ([123: 123], (1, 2, "3"))) + + let t0 = [ (1, "two", StructPrintable(3), StructDebugPrintable(4), + WithoutDescription(5)) ] + expectPrinted("[(1, \"two\", ►3◀︎, ►4◀︎, PrintTestTypes.WithoutDescription(x: 5))]", + t0) + + let t1 = [ (1, "2", WithoutDescription(3)), + (4, "5", WithoutDescription(6)), + (7, "8", WithoutDescription(9)) ] + expectPrinted("[(1, \"2\", PrintTestTypes.WithoutDescription(x: 3)), (4, \"5\", PrintTestTypes.WithoutDescription(x: 6)), (7, \"8\", PrintTestTypes.WithoutDescription(x: 9))]", t1) +} + +runAllTests() diff --git a/test/1_stdlib/RangeDiagnostics.swift b/test/1_stdlib/RangeDiagnostics.swift index 29cccb658ee30..05a7e6a24f575 100644 --- a/test/1_stdlib/RangeDiagnostics.swift +++ b/test/1_stdlib/RangeDiagnostics.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/RangeTraps.swift b/test/1_stdlib/RangeTraps.swift index cac7717f8354e..b61899b28dc37 100644 --- a/test/1_stdlib/RangeTraps.swift +++ b/test/1_stdlib/RangeTraps.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Reflection.swift b/test/1_stdlib/Reflection.swift index 788a20dca6b3e..f30a7742ef10c 100644 --- a/test/1_stdlib/Reflection.swift +++ b/test/1_stdlib/Reflection.swift @@ -29,8 +29,8 @@ dump(Complex(real: -1.5, imag: -0.75)) // CHECK-NEXT: imag: 44 dump(Complex(real: 22, imag: 44)) // CHECK-NEXT: Reflection.Complex -// CHECK-NEXT: real: is this the real life? -// CHECK-NEXT: imag: is it just fantasy? +// CHECK-NEXT: real: "is this the real life?" +// CHECK-NEXT: imag: "is it just fantasy?" dump(Complex(real: "is this the real life?", imag: "is it just fantasy?")) @@ -52,7 +52,7 @@ class Best : Better { // CHECK-LABEL: Root class: // CHECK-NEXT: Reflection.Good #0 // CHECK-NEXT: x: 11 -// CHECK-NEXT: y: 222 +// CHECK-NEXT: y: "222" print("Root class:") dump(Good()) @@ -61,9 +61,9 @@ dump(Good()) // CHECK-NEXT: super: Reflection.Better // CHECK-NEXT: super: Reflection.Good // CHECK-NEXT: x: 11 -// CHECK-NEXT: y: 222 +// CHECK-NEXT: y: "222" // CHECK-NEXT: z: 333.5 -// CHECK-NEXT: w: 4444 +// CHECK-NEXT: w: "4444" print("Subclass:") dump(Best()) @@ -79,9 +79,9 @@ dump(any) // CHECK-NEXT: super: Reflection.Better // CHECK-NEXT: super: Reflection.Good // CHECK-NEXT: x: 11 -// CHECK-NEXT: y: 222 +// CHECK-NEXT: y: "222" // CHECK-NEXT: z: 333.5 -// CHECK-NEXT: w: 4444 +// CHECK-NEXT: w: "4444" print("Any class:") any = Best() dump(any) @@ -97,15 +97,15 @@ any = 2.5 dump(any) // CHECK-LABEL: Character: -// CHECK-NEXT: a +// CHECK-NEXT: "a" print("Character:") -print(_reflect(Character("a")).summary) +dump(Character("a")) let range = 3...9 -// CHECK-NEXT: 3..<10 -print(_reflect(range).summary) -// CHECK-NEXT: startIndex=3 -print("startIndex=\(_reflect(range)[0].1.summary)") +// CHECK-NEXT: Range(3..<10) +// CHECK-NEXT: startIndex: 3 +// CHECK-NEXT: endIndex: 10 +dump(range) protocol Fooable {} extension Int : Fooable {} @@ -131,65 +131,61 @@ extension Best: Barrable {} // CHECK-NEXT: super: Reflection.Better // CHECK-NEXT: super: Reflection.Good // CHECK-NEXT: x: 11 -// CHECK-NEXT: y: 222 +// CHECK-NEXT: y: "222" // CHECK-NEXT: z: 333.5 -// CHECK-NEXT: w: 4444 +// CHECK-NEXT: w: "4444" print("Barrable class:") var barrable: Barrable = Best() dump(barrable) // CHECK-LABEL: second verse // CHECK-NEXT: Reflection.Best #0 +// CHECK-NEXT: super: Reflection.Better +// CHECK-NEXT: super: Reflection.Good +// CHECK-NEXT: x: 11 +// CHECK-NEXT: y: "222" +// CHECK-NEXT: z: 333.5 +// CHECK-NEXT: w: "4444" print("second verse same as the first:") dump(barrable) -// With _Reflectable protocols we extract the witness table from the container. -// CHECK-LABEL: _Reflectable int: -// CHECK-NEXT: 1 -print("_Reflectable int:") -var reflectable: _Reflectable = 1 -dump(reflectable) - // CHECK-NEXT: Logical: true -switch _reflect(true).quickLookObject { - case .None: print("no quicklook") - case .Some(let ql): - switch ql { - case .Logical(let x): print("Logical: \(x)") - default: print("wrong quicklook type") - } +switch true.customPlaygroundQuickLook() { + case .Logical(let x): print("Logical: \(x)") + default: print("wrong quicklook type") } -// CHECK-NEXT: Hello world -print( _reflect(Optional("Hello world")).summary ) -// CHECK-NEXT: nil -print( _reflect(Optional()).summary ) +// CHECK-NEXT: Optional("Hello world") +// CHECK-NEXT: Some: "Hello world" +dump(Optional("Hello world")) +// CHECK-NEXT: - nil +dump(Optional()) let intArray = [1,2,3,4,5] -let intArrayMirror = _reflect(intArray) // CHECK-NEXT: 5 elements -print(intArrayMirror.summary) -// CHECK-NEXT: [0]: 1 -print("\(intArrayMirror[0].0): \(intArrayMirror[0].1.summary)") -// CHECK-NEXT: [4]: 5 -print("\(intArrayMirror[4].0): \(intArrayMirror[4].1.summary)") - -var justSomeFunction = { (x:Int)->Int in return x + 1 } +// CHECK-NEXT: 1 +// CHECK-NEXT: 2 +// CHECK-NEXT: 3 +// CHECK-NEXT: 4 +// CHECK-NEXT: 5 +dump(intArray) + +var justSomeFunction = { (x:Int) -> Int in return x + 1 } // CHECK-NEXT: (Function) -print(_reflect(justSomeFunction).summary) +dump(justSomeFunction as Any) // CHECK-NEXT: Swift.String -print(_reflect(String.self).summary) +dump(String.self) -// CHECK-NEXT: CollectionOfOne(Howdy Swift!) -// CHECK-NEXT: - element: Howdy Swift! +// CHECK-NEXT: Swift.CollectionOfOne +// CHECK-NEXT: element: "Howdy Swift!" dump(CollectionOfOne("Howdy Swift!")) // CHECK-NEXT: EmptyCollection var emptyCollectionOfInt: EmptyCollection = EmptyCollection() -print(_reflect(emptyCollectionOfInt).summary) +dump(emptyCollectionOfInt) // CHECK-NEXT: .One -print(_reflect(Bit.One).summary) +dump(Bit.One) // CHECK-NEXT: ▿ // CHECK-NEXT: from: 1.0 @@ -197,26 +193,28 @@ print(_reflect(Bit.One).summary) // CHECK-NEXT: by: 3.14 dump(1.0.stride(through: 12.15, by: 3.14)) -// CHECK-NEXT: UnsafeMutablePointer(nil) +// CHECK-NEXT: 0x0000 +// CHECK-NEXT: - pointerValue: 0 var nilUnsafeMutablePointerString: UnsafeMutablePointer = nil -print(_reflect(nilUnsafeMutablePointerString).summary) +dump(nilUnsafeMutablePointerString) -// CHECK-NEXT: UnsafeMutablePointer(0x123456) +// CHECK-NEXT: 123456 +// CHECK-NEXT: - pointerValue: 1193046 var randomUnsafeMutablePointerString = UnsafeMutablePointer( bitPattern: 0x123456) -print(_reflect(randomUnsafeMutablePointerString).summary) +dump(randomUnsafeMutablePointerString) -// CHECK-NEXT: Hello panda +// CHECK-NEXT: "Hello panda" var sanePointerString = UnsafeMutablePointer.alloc(1) sanePointerString.initialize("Hello panda") -print(_reflect(sanePointerString.memory).summary) +dump(sanePointerString.memory) sanePointerString.destroy() sanePointerString.dealloc(1) // Don't crash on types with opaque metadata. rdar://problem/19791252 +// CHECK-NEXT: (Opaque Value) var rawPointer = unsafeBitCast(0 as Int, Builtin.RawPointer.self) dump(rawPointer) -// CHECK: - (Opaque Value) // CHECK-LABEL: and now our song is done print("and now our song is done") diff --git a/test/1_stdlib/ReflectionHashing.swift b/test/1_stdlib/ReflectionHashing.swift index 0a200ef14b7cc..7a375213efcb1 100644 --- a/test/1_stdlib/ReflectionHashing.swift +++ b/test/1_stdlib/ReflectionHashing.swift @@ -41,41 +41,41 @@ Reflection.test("Dictionary") { #if arch(i386) || arch(arm) var expected = "" expected += "▿ 5 key/value pairs\n" - expected += " ▿ [0]: (2 elements)\n" - expected += " - .0: Four\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Four\"\n" expected += " - .1: 4\n" - expected += " ▿ [1]: (2 elements)\n" - expected += " - .0: One\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"One\"\n" expected += " - .1: 1\n" - expected += " ▿ [2]: (2 elements)\n" - expected += " - .0: Two\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Two\"\n" expected += " - .1: 2\n" - expected += " ▿ [3]: (2 elements)\n" - expected += " - .0: Five\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Five\"\n" expected += " - .1: 5\n" - expected += " ▿ [4]: (2 elements)\n" - expected += " - .0: Three\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Three\"\n" expected += " - .1: 3\n" -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) var expected = "" expected += "▿ 5 key/value pairs\n" - expected += " ▿ [0]: (2 elements)\n" - expected += " - .0: Five\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Five\"\n" expected += " - .1: 5\n" - expected += " ▿ [1]: (2 elements)\n" - expected += " - .0: Two\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Two\"\n" expected += " - .1: 2\n" - expected += " ▿ [2]: (2 elements)\n" - expected += " - .0: One\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"One\"\n" expected += " - .1: 1\n" - expected += " ▿ [3]: (2 elements)\n" - expected += " - .0: Three\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Three\"\n" expected += " - .1: 3\n" - expected += " ▿ [4]: (2 elements)\n" - expected += " - .0: Four\n" + expected += " ▿ (2 elements)\n" + expected += " - .0: \"Four\"\n" expected += " - .1: 4\n" #else - fatalError("unipmelemented") + fatalError("unimplemented") #endif expectEqual(expected, output) @@ -90,19 +90,19 @@ Reflection.test("Set") { #if arch(i386) || arch(arm) var expected = "" expected += "▿ 5 members\n" - expected += " - [0]: 3\n" - expected += " - [1]: 1\n" - expected += " - [2]: 5\n" - expected += " - [3]: 2\n" - expected += " - [4]: 4\n" -#elseif arch(x86_64) || arch(arm64) + expected += " - 3\n" + expected += " - 1\n" + expected += " - 5\n" + expected += " - 2\n" + expected += " - 4\n" +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) var expected = "" expected += "▿ 5 members\n" - expected += " - [0]: 5\n" - expected += " - [1]: 2\n" - expected += " - [2]: 3\n" - expected += " - [3]: 1\n" - expected += " - [4]: 4\n" + expected += " - 5\n" + expected += " - 2\n" + expected += " - 3\n" + expected += " - 1\n" + expected += " - 4\n" #else fatalError("unimplemented") #endif diff --git a/test/1_stdlib/Reflection_jit.swift b/test/1_stdlib/Reflection_jit.swift index 1b82c6e83dd8f..7dc4e0b243a82 100644 --- a/test/1_stdlib/Reflection_jit.swift +++ b/test/1_stdlib/Reflection_jit.swift @@ -1,5 +1,4 @@ // Test Reflection.swift in JIT mode. // RUN: %target-jit-run -parse-stdlib %S/Reflection.swift -- %S/Inputs/shuffle.jpg | FileCheck %S/Reflection.swift -// XFAIL: linux // REQUIRES: swift_interpreter diff --git a/test/1_stdlib/Reflection_objc.swift b/test/1_stdlib/Reflection_objc.swift index ec311a193d617..bd1d64df47fc9 100644 --- a/test/1_stdlib/Reflection_objc.swift +++ b/test/1_stdlib/Reflection_objc.swift @@ -51,9 +51,9 @@ class NSBetter : NSGood { } // CHECK-LABEL: Swift ObjC subclass: -// CHECK-NEXT: Reflection.NSBetter #0 +// CHECK-NEXT: #0 // CHECK-NEXT: super: Reflection.NSGood -// CHECK-NEXT: super: +// CHECK-NEXT: super: NSObject print("Swift ObjC subclass:") dump(NSBetter()) @@ -70,6 +70,7 @@ print("We cannot reflect \(NSComparisonResult.OrderedAscending) yet") // // CHECK-LABEL: NSURL: // CHECK-NEXT: file:///Volumes/ +// CHECK-NEXT: - super: NSObject print("NSURL:") dump(NSURL(fileURLWithPath: "/Volumes", isDirectory: true)) @@ -77,8 +78,8 @@ dump(NSURL(fileURLWithPath: "/Volumes", isDirectory: true)) // associated enum tag. // CHECK-NEXT: got the expected quick look text -switch _reflect("woozle wuzzle" as NSString).quickLookObject { -case .Some(.Text("woozle wuzzle")): +switch PlaygroundQuickLook(reflecting: "woozle wuzzle" as NSString) { +case .Text("woozle wuzzle"): print("got the expected quick look text") case _: print("got something else") @@ -86,15 +87,15 @@ case _: // CHECK-NEXT: foobar let somesubclassofnsstring = ("foo" + "bar") as NSString -switch _reflect(somesubclassofnsstring).quickLookObject { - case .Some(.Text(let text)): print(text) +switch PlaygroundQuickLook(reflecting: somesubclassofnsstring) { + case .Text(let text): print(text) default: print("not the expected quicklook") } // CHECK-NEXT: got the expected quick look attributed string let astr = NSAttributedString(string: "yizzle pizzle") -switch _reflect(astr as NSAttributedString).quickLookObject { -case .Some(.AttributedString(let astr2 as NSAttributedString)) +switch PlaygroundQuickLook(reflecting: astr as NSAttributedString) { +case .AttributedString(let astr2 as NSAttributedString) where astr === astr2: print("got the expected quick look attributed string") case _: @@ -102,32 +103,32 @@ case _: } // CHECK-NEXT: got the expected quick look int -switch _reflect(Int.max as NSNumber).quickLookObject { -case .Some(.Int(+Int64(Int.max))): +switch PlaygroundQuickLook(reflecting: Int.max as NSNumber) { +case .Int(+Int64(Int.max)): print("got the expected quick look int") case _: print("got something else") } // CHECK-NEXT: got the expected quick look uint -switch _reflect(NSNumber(unsignedLongLong: UInt64.max)).quickLookObject { -case .Some(.UInt(UInt64.max)): +switch PlaygroundQuickLook(reflecting: NSNumber(unsignedLongLong: UInt64.max)) { +case .UInt(UInt64.max): print("got the expected quick look uint") case _: print("got something else") } // CHECK-NEXT: got the expected quick look double -switch _reflect(22.5 as NSNumber).quickLookObject { -case .Some(.Double(22.5)): +switch PlaygroundQuickLook(reflecting: 22.5 as NSNumber) { +case .Double(22.5): print("got the expected quick look double") case _: print("got something else") } // CHECK-NEXT: got the expected quick look float -switch _reflect(Float32(1.25)).quickLookObject { -case .Some(.Float(1.25)): +switch PlaygroundQuickLook(reflecting: Float32(1.25)) { +case .Float(1.25): print("got the expected quick look float") case _: print("got something else") @@ -138,90 +139,74 @@ case _: // CHECK-NEXT: got the expected quick look bezier path let image = OSImage(contentsOfFile:Process.arguments[1])! -switch _reflect(image).quickLookObject { -case .Some(.Image(let image2 as OSImage)) where image === image2: +switch PlaygroundQuickLook(reflecting: image) { +case .Image(let image2 as OSImage) where image === image2: print("got the expected quick look image") case _: print("got something else") } let color = OSColor.blackColor() -switch _reflect(color).quickLookObject { -case .Some(.Color(let color2 as OSColor)) where color === color2: +switch PlaygroundQuickLook(reflecting: color) { +case .Color(let color2 as OSColor) where color === color2: print("got the expected quick look color") case _: print("got something else") } let path = OSBezierPath() -switch _reflect(path).quickLookObject { -case .Some(.BezierPath(let path2 as OSBezierPath)) where path === path2: +switch PlaygroundQuickLook(reflecting: path) { +case .BezierPath(let path2 as OSBezierPath) where path === path2: print("got the expected quick look bezier path") case _: print("got something else") } +// CHECK-LABEL: Reflecting NSArray: +// CHECK-NEXT: [ 1 2 3 4 5 ] +print("Reflecting NSArray:") let intNSArray : NSArray = [1 as NSNumber,2 as NSNumber,3 as NSNumber,4 as NSNumber,5 as NSNumber] -let intNSArrayMirror = _reflect(intNSArray) -// CHECK-NEXT: 5 elements -print(intNSArrayMirror.summary) -// CHECK-NEXT: [0]: 1 -print("\(intNSArrayMirror[0].0): \(intNSArrayMirror[0].1.summary)") -// CHECK-NEXT: [4]: 5 -print("\(intNSArrayMirror[4].0): \(intNSArrayMirror[4].1.summary)") - - -let numset = NSSet(objects: 1,2,3,4) -let numsetMirror = _reflect(numset) -// CHECK-NEXT: 4 elements -print(numsetMirror.summary) -// CHECK-NEXT: I see all four elements -let num0 = (numsetMirror[0].1.summary) -let num1 = (numsetMirror[1].1.summary) -let num2 = (numsetMirror[2].1.summary) -let num3 = (numsetMirror[3].1.summary) -let have1 = (num0 == "1" || num1 == "1" || num2 == "1" || num3 == "1") -let have2 = (num0 == "2" || num1 == "2" || num2 == "2" || num3 == "2") -let have3 = (num0 == "3" || num1 == "3" || num2 == "3" || num3 == "3") -let have4 = (num0 == "4" || num1 == "4" || num2 == "4" || num3 == "4") -if have1 && have2 && have3 && have4 { - print("I see all four elements") -} else { - print("I see \(num0), \(num1), \(num2), \(num3)") -} - -// CHECK-NEXT: 42 -class MyQLTestClass { - @objc func debugQuickLookObject() -> AnyObject { - return (42 as NSNumber) - } -} - -switch _reflect(MyQLTestClass()).quickLookObject { - case .Some(.Int(let value)): print(value) - case .Some(_): print("non-Int object") - default: print("None") +let arrayMirror = Mirror(reflecting: intNSArray) +var buffer = "[ " +for i in arrayMirror.children { + buffer += "\(i.1) " } +buffer += "]" +print(buffer) -// CHECK-NEXT: nil is good here -class MyNonQLTestClass { - func debugQuickLookObject() -> AnyObject { - return (42 as NSNumber) +// CHECK-LABEL: Reflecting NSSet: +// CHECK-NEXT: NSSet reflection working fine +print("Reflecting NSSet:") +let numset = NSSet(objects: 1,2,3,4) +let numsetMirror = Mirror(reflecting: numset) +var numsetNumbers = Set() +for i in numsetMirror.children { + if let number = i.1 as? Int { + numsetNumbers.insert(number) } } - -switch _reflect(MyNonQLTestClass()).quickLookObject { - case .Some(.Int(let value)): print(value) - case .Some(_): print("non-Int object") - default: print("nil is good here") +if numsetNumbers == Set([1, 2, 3, 4]) { + print("NSSet reflection working fine") +} else { + print("NSSet reflection broken: here are the numbers we got: \(numsetNumbers)") } // CHECK-NEXT: (3.0, 6.0) -print(_reflect(CGPoint(x: 3,y: 6)).summary) +// CHECK-NEXT: x: 3.0 +// CHECK-NEXT: y: 6.0 +dump(CGPoint(x: 3,y: 6)) // CHECK-NEXT: (30.0, 60.0) -print(_reflect(CGSize(width: 30, height: 60)).summary) +// CHECK-NEXT: width: 30.0 +// CHECK-NEXT: height: 60.0 +dump(CGSize(width: 30, height: 60)) // CHECK-NEXT: (50.0, 60.0, 100.0, 150.0) -print(_reflect(CGRect(x: 50, y: 60, width: 100, height: 150)).summary) +// CHECK-NEXT: origin: (50.0, 60.0) +// CHECK-NEXT: x: 50.0 +// CHECK-NEXT: y: 60.0 +// CHECK-NEXT: size: (100.0, 150.0) +// CHECK-NEXT: width: 100.0 +// CHECK-NEXT: height: 150.0 +dump(CGRect(x: 50, y: 60, width: 100, height: 150)) // rdar://problem/18513769 -- Make sure that QuickLookObject lookup correctly // manages memory. @@ -275,7 +260,7 @@ class HasStringQLO : CanaryBase { func testQLO(type: T.Type) { autoreleasepool { - _ = _reflect(type.init()).quickLookObject + _ = PlaygroundQuickLook(reflecting: type.init()) } } diff --git a/test/1_stdlib/Repeat.swift b/test/1_stdlib/Repeat.swift new file mode 100644 index 0000000000000..800b14369a7c6 --- /dev/null +++ b/test/1_stdlib/Repeat.swift @@ -0,0 +1,23 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest +import Swift + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +let RepeatTests = TestSuite("Repeat") +RepeatTests.test("Attributes") { + let r = Repeat(count: 42, repeatedValue: "repeat") + expectEqual(r.count, 42) + expectEqual(r.startIndex, 0) + expectEqual(r.endIndex, 42) + expectEqual(r.repeatedValue, "repeat") +} + +runAllTests() diff --git a/test/1_stdlib/Runtime.swift b/test/1_stdlib/Runtime.swift index 937b3c4ed9955..c418de3511294 100644 --- a/test/1_stdlib/Runtime.swift +++ b/test/1_stdlib/Runtime.swift @@ -1,32 +1,20 @@ // RUN: rm -rf %t && mkdir %t // -// RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g -// RUN: %target-build-swift -parse-stdlib -Xfrontend -disable-access-control -module-name a -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o %s -o %t.out +// RUN: %target-build-swift -parse-stdlib -module-name a %s -o %t.out // RUN: %target-run %t.out // REQUIRES: executable_test -// XFAIL: linux - import Swift import StdlibUnittest -import Foundation -import CoreGraphics import SwiftShims -import MirrorObjC -var nsObjectCanaryCount = 0 -@objc class NSObjectCanary : NSObject { - override init() { - nsObjectCanaryCount += 1 - } - deinit { - nsObjectCanaryCount -= 1 - } -} +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif -struct NSObjectCanaryStruct { - var ref = NSObjectCanary() -} var swiftObjectCanaryCount = 0 class SwiftObjectCanary { @@ -42,348 +30,17 @@ struct SwiftObjectCanaryStruct { var ref = SwiftObjectCanary() } -@objc class ClassA { - init(value: Int) { - self.value = value - } - - var value: Int -} - -struct NotBridgedValueType { - // Keep it pointer-sized. - var canaryRef = SwiftObjectCanary() -} - -struct BridgedValueType : _ObjectiveCBridgeable { - init(value: Int) { - self.value = value - } - - static func _getObjectiveCType() -> Any.Type { - return ClassA.self - } - - func _bridgeToObjectiveC() -> ClassA { - return ClassA(value: value) - } - - static func _isBridgedToObjectiveC() -> Bool { - return true - } - - static func _forceBridgeFromObjectiveC( - x: ClassA, - inout result: BridgedValueType? - ) { - assert(x.value % 2 == 0, "not bridged to Objective-C") - result = BridgedValueType(value: x.value) - } - - static func _conditionallyBridgeFromObjectiveC( - x: ClassA, - inout result: BridgedValueType? - ) -> Bool { - if x.value % 2 == 0 { - result = BridgedValueType(value: x.value) - return true - } - - result = nil - return false - } - - var value: Int - var canaryRef = SwiftObjectCanary() -} - -struct BridgedLargeValueType : _ObjectiveCBridgeable { - init(value: Int) { - value0 = value - value1 = value - value2 = value - value3 = value - value4 = value - value5 = value - value6 = value - value7 = value - } - - static func _getObjectiveCType() -> Any.Type { - return ClassA.self - } - - func _bridgeToObjectiveC() -> ClassA { - assert(value == value0) - return ClassA(value: value0) - } - - static func _isBridgedToObjectiveC() -> Bool { - return true - } - - static func _forceBridgeFromObjectiveC( - x: ClassA, - inout result: BridgedLargeValueType? - ) { - assert(x.value % 2 == 0, "not bridged to Objective-C") - result = BridgedLargeValueType(value: x.value) - } - - static func _conditionallyBridgeFromObjectiveC( - x: ClassA, - inout result: BridgedLargeValueType? - ) -> Bool { - if x.value % 2 == 0 { - result = BridgedLargeValueType(value: x.value) - return true - } - - result = nil - return false - } - - var value: Int { - let x = value0 - assert(value0 == x && value1 == x && value2 == x && value3 == x && - value4 == x && value5 == x && value6 == x && value7 == x) - return x - } - - var (value0, value1, value2, value3): (Int, Int, Int, Int) - var (value4, value5, value6, value7): (Int, Int, Int, Int) - var canaryRef = SwiftObjectCanary() -} - - -struct ConditionallyBridgedValueType : _ObjectiveCBridgeable { - init(value: Int) { - self.value = value - } - - static func _getObjectiveCType() -> Any.Type { - return ClassA.self - } - - func _bridgeToObjectiveC() -> ClassA { - return ClassA(value: value) - } - - static func _forceBridgeFromObjectiveC( - x: ClassA, - inout result: ConditionallyBridgedValueType? - ) { - assert(x.value % 2 == 0, "not bridged from Objective-C") - result = ConditionallyBridgedValueType(value: x.value) - } - - static func _conditionallyBridgeFromObjectiveC( - x: ClassA, - inout result: ConditionallyBridgedValueType? - ) -> Bool { - if x.value % 2 == 0 { - result = ConditionallyBridgedValueType(value: x.value) - return true - } - - result = nil - return false - } - - static func _isBridgedToObjectiveC() -> Bool { - return ((T.self as Any) as? String.Type) == nil - } - - var value: Int - var canaryRef = SwiftObjectCanary() -} - -class BridgedVerbatimRefType { - var value: Int = 42 - var canaryRef = SwiftObjectCanary() -} - -func withSwiftObjectCanary( - createValue: () -> T, - _ check: (T) -> Void, - file: String = __FILE__, line: UInt = __LINE__ -) { - let stackTrace = SourceLocStack(SourceLoc(file, line)) - - swiftObjectCanaryCount = 0 - autoreleasepool { - var valueWithCanary = createValue() - expectEqual(1, swiftObjectCanaryCount, stackTrace: stackTrace) - check(valueWithCanary) - } - expectEqual(0, swiftObjectCanaryCount, stackTrace: stackTrace) -} - var Runtime = TestSuite("Runtime") -func _isClassOrObjCExistential_Opaque(x: T.Type) -> Bool { - return _isClassOrObjCExistential(_opaqueIdentity(x)) -} - -Runtime.test("_isClassOrObjCExistential") { - expectTrue(_isClassOrObjCExistential(NSObjectCanary.self)) - expectTrue(_isClassOrObjCExistential_Opaque(NSObjectCanary.self)) - - expectFalse(_isClassOrObjCExistential(NSObjectCanaryStruct.self)) - expectFalse(_isClassOrObjCExistential_Opaque(NSObjectCanaryStruct.self)) - - expectTrue(_isClassOrObjCExistential(SwiftObjectCanary.self)) - expectTrue(_isClassOrObjCExistential_Opaque(SwiftObjectCanary.self)) - - expectFalse(_isClassOrObjCExistential(SwiftObjectCanaryStruct.self)) - expectFalse(_isClassOrObjCExistential_Opaque(SwiftObjectCanaryStruct.self)) - - typealias SwiftClosure = ()->() - expectFalse(_isClassOrObjCExistential(SwiftClosure.self)) - expectFalse(_isClassOrObjCExistential_Opaque(SwiftClosure.self)) - - typealias ObjCClosure = @convention(block) ()->() - expectTrue(_isClassOrObjCExistential(ObjCClosure.self)) - expectTrue(_isClassOrObjCExistential_Opaque(ObjCClosure.self)) - - expectTrue(_isClassOrObjCExistential(CFArray.self)) - expectTrue(_isClassOrObjCExistential_Opaque(CFArray.self)) - - expectTrue(_isClassOrObjCExistential(CFArray.self)) - expectTrue(_isClassOrObjCExistential_Opaque(CFArray.self)) - - expectTrue(_isClassOrObjCExistential(AnyObject.self)) - expectTrue(_isClassOrObjCExistential_Opaque(AnyObject.self)) - - // AnyClass == AnyObject.Type - expectFalse(_isClassOrObjCExistential(AnyClass.self)) - expectFalse(_isClassOrObjCExistential_Opaque(AnyClass.self)) - - expectFalse(_isClassOrObjCExistential(AnyObject.Protocol.self)) - expectFalse(_isClassOrObjCExistential_Opaque(AnyObject.Protocol.self)) - - expectFalse(_isClassOrObjCExistential(NSObjectCanary.Type.self)) - expectFalse(_isClassOrObjCExistential_Opaque(NSObjectCanary.Type.self)) -} - Runtime.test("_canBeClass") { - expectEqual(1, _canBeClass(NSObjectCanary.self)) - expectEqual(0, _canBeClass(NSObjectCanaryStruct.self)) expectEqual(1, _canBeClass(SwiftObjectCanary.self)) expectEqual(0, _canBeClass(SwiftObjectCanaryStruct.self)) - typealias SwiftClosure = ()->() + typealias SwiftClosure = () -> () expectEqual(0, _canBeClass(SwiftClosure.self)) - - typealias ObjCClosure = @convention(block) ()->() - expectEqual(1, _canBeClass(ObjCClosure.self)) - - expectEqual(1, _canBeClass(CFArray.self)) -} - -Runtime.test("bridgeToObjectiveC") { - expectEmpty(_bridgeToObjectiveC(NotBridgedValueType())) - - expectEqual(42, (_bridgeToObjectiveC(BridgedValueType(value: 42)) as! ClassA).value) - - expectEqual(42, (_bridgeToObjectiveC(BridgedLargeValueType(value: 42)) as! ClassA).value) - - expectEqual(42, (_bridgeToObjectiveC(ConditionallyBridgedValueType(value: 42)) as! ClassA).value) - - expectEmpty(_bridgeToObjectiveC(ConditionallyBridgedValueType(value: 42))) - - var bridgedVerbatimRef = BridgedVerbatimRefType() - expectTrue(_bridgeToObjectiveC(bridgedVerbatimRef) === bridgedVerbatimRef) -} - -Runtime.test("bridgeToObjectiveC/NoLeak") { - withSwiftObjectCanary( - { NotBridgedValueType() }, - { expectEmpty(_bridgeToObjectiveC($0)) }) - - withSwiftObjectCanary( - { BridgedValueType(value: 42) }, - { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) - - withSwiftObjectCanary( - { BridgedLargeValueType(value: 42) }, - { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) - - withSwiftObjectCanary( - { ConditionallyBridgedValueType(value: 42) }, - { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) - - withSwiftObjectCanary( - { ConditionallyBridgedValueType(value: 42) }, - { expectEmpty(_bridgeToObjectiveC($0)) }) - - withSwiftObjectCanary( - { BridgedVerbatimRefType() }, - { expectTrue(_bridgeToObjectiveC($0) === $0) }) -} - -Runtime.test("forceBridgeFromObjectiveC") { - // Bridge back using NotBridgedValueType. - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 21), NotBridgedValueType.self)) - - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 42), NotBridgedValueType.self)) - - expectEmpty(_conditionallyBridgeFromObjectiveC( - BridgedVerbatimRefType(), NotBridgedValueType.self)) - - // Bridge back using BridgedValueType. - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 21), BridgedValueType.self)) - - expectEqual(42, _forceBridgeFromObjectiveC( - ClassA(value: 42), BridgedValueType.self).value) - expectEqual(42, _conditionallyBridgeFromObjectiveC( - ClassA(value: 42), BridgedValueType.self)!.value) - - expectEmpty(_conditionallyBridgeFromObjectiveC( - BridgedVerbatimRefType(), BridgedValueType.self)) - - // Bridge back using BridgedLargeValueType. - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 21), BridgedLargeValueType.self)) - - expectEqual(42, _forceBridgeFromObjectiveC( - ClassA(value: 42), BridgedLargeValueType.self).value) - expectEqual(42, _conditionallyBridgeFromObjectiveC( - ClassA(value: 42), BridgedLargeValueType.self)!.value) - - expectEmpty(_conditionallyBridgeFromObjectiveC( - BridgedVerbatimRefType(), BridgedLargeValueType.self)) - - // Bridge back using BridgedVerbatimRefType. - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 21), BridgedVerbatimRefType.self)) - - expectEmpty(_conditionallyBridgeFromObjectiveC( - ClassA(value: 42), BridgedVerbatimRefType.self)) - - var bridgedVerbatimRef = BridgedVerbatimRefType() - expectTrue(_forceBridgeFromObjectiveC( - bridgedVerbatimRef, BridgedVerbatimRefType.self) === bridgedVerbatimRef) - expectTrue(_conditionallyBridgeFromObjectiveC( - bridgedVerbatimRef, BridgedVerbatimRefType.self)! === bridgedVerbatimRef) -} - -Runtime.test("isBridgedToObjectiveC") { - expectFalse(_isBridgedToObjectiveC(NotBridgedValueType)) - expectTrue(_isBridgedToObjectiveC(BridgedValueType)) - expectTrue(_isBridgedToObjectiveC(BridgedVerbatimRefType)) -} - -Runtime.test("isBridgedVerbatimToObjectiveC") { - expectFalse(_isBridgedVerbatimToObjectiveC(NotBridgedValueType)) - expectFalse(_isBridgedVerbatimToObjectiveC(BridgedValueType)) - expectTrue(_isBridgedVerbatimToObjectiveC(BridgedVerbatimRefType)) } -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // The protocol should be defined in the standard library, otherwise the cast // does not work. @@ -409,7 +66,7 @@ struct Struct2ConformsToP1 : BooleanType, Q1 { var value: T } -// A large struct that can not be stored inline in an opaque buffer. +// A large struct that cannot be stored inline in an opaque buffer. struct Struct3ConformsToP2 : CustomStringConvertible, Q1 { var a: UInt64 = 10 var b: UInt64 = 20 @@ -428,7 +85,7 @@ struct Struct3ConformsToP2 : CustomStringConvertible, Q1 { } } -// A large struct that can not be stored inline in an opaque buffer. +// A large struct that cannot be stored inline in an opaque buffer. struct Struct4ConformsToP2 : CustomStringConvertible, Q1 { var value: T var e: UInt64 = 50 @@ -613,8 +270,6 @@ Runtime.test("dynamic cast to existential with cross-module extensions") { } class SomeClass {} -@objc class SomeObjCClass {} -class SomeNSObjectSubclass : NSObject {} struct SomeStruct {} enum SomeEnum { case A @@ -623,9 +278,6 @@ enum SomeEnum { Runtime.test("typeName") { expectEqual("a.SomeClass", _typeName(SomeClass.self)) - expectEqual("a.SomeObjCClass", _typeName(SomeObjCClass.self)) - expectEqual("a.SomeNSObjectSubclass", _typeName(SomeNSObjectSubclass.self)) - expectEqual("NSObject", _typeName(NSObject.self)) expectEqual("a.SomeStruct", _typeName(SomeStruct.self)) expectEqual("a.SomeEnum", _typeName(SomeEnum.self)) expectEqual("protocol<>.Protocol", _typeName(Any.Protocol.self)) @@ -636,15 +288,6 @@ Runtime.test("typeName") { var a: Any = SomeClass() expectEqual("a.SomeClass", _typeName(a.dynamicType)) - a = SomeObjCClass() - expectEqual("a.SomeObjCClass", _typeName(a.dynamicType)) - - a = SomeNSObjectSubclass() - expectEqual("a.SomeNSObjectSubclass", _typeName(a.dynamicType)) - - a = NSObject() - expectEqual("NSObject", _typeName(a.dynamicType)) - a = SomeStruct() expectEqual("a.SomeStruct", _typeName(a.dynamicType)) @@ -665,6 +308,18 @@ Runtime.test("typeName") { expectEqual("protocol<>.Protocol", _typeName(a.dynamicType)) } +class SomeSubclass : SomeClass {} + +protocol SomeProtocol {} +class SomeConformingClass : SomeProtocol {} + +Runtime.test("typeByName") { + expectTrue(_typeByName("a.SomeClass") == SomeClass.self) + expectTrue(_typeByName("a.SomeSubclass") == SomeSubclass.self) + // name lookup will be via protocol conformance table + expectTrue(_typeByName("a.SomeConformingClass") == SomeConformingClass.self) +} + Runtime.test("demangleName") { expectEqual("", _stdlib_demangleName("")) expectEqual("abc", _stdlib_demangleName("abc")) @@ -729,108 +384,23 @@ Runtime.test("_stdlib_atomicCompareExchangeStrongPtr") { } } -class GenericClass {} -class MultiGenericClass {} -struct GenericStruct {} -enum GenericEnum {} - -struct PlainStruct {} -enum PlainEnum {} - -protocol ProtocolA {} -protocol ProtocolB {} - -Runtime.test("Generic class ObjC runtime names") { - expectEqual("_TtGC1a12GenericClassSi_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassVS_11PlainStruct_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassOS_9PlainEnum_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassTVS_11PlainStructOS_9PlainEnumS1___", - NSStringFromClass(GenericClass<(PlainStruct, PlainEnum, PlainStruct)>.self)) - expectEqual("_TtGC1a12GenericClassMVS_11PlainStruct_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassFMVS_11PlainStructS1__", - NSStringFromClass(GenericClass PlainStruct>.self)) - - expectEqual("_TtGC1a12GenericClassFzMVS_11PlainStructS1__", - NSStringFromClass(GenericClass PlainStruct>.self)) - expectEqual("_TtGC1a12GenericClassFTVS_11PlainStructROS_9PlainEnum_Si_", - NSStringFromClass(GenericClass<(PlainStruct, inout PlainEnum) -> Int>.self)) - - expectEqual("_TtGC1a12GenericClassPS_9ProtocolA__", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassPS_9ProtocolAS_9ProtocolB__", - NSStringFromClass(GenericClass>.self)) - expectEqual("_TtGC1a12GenericClassPMPS_9ProtocolAS_9ProtocolB__", - NSStringFromClass(GenericClass.Type>.self)) - expectEqual("_TtGC1a12GenericClassMPS_9ProtocolAS_9ProtocolB__", - NSStringFromClass(GenericClass.Protocol>.self)) - - expectEqual("_TtGC1a12GenericClassCSo7CFArray_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassVSC9NSDecimal_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassCSo8NSObject_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassCSo8NSObject_", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassPSo9NSCopying__", - NSStringFromClass(GenericClass.self)) - expectEqual("_TtGC1a12GenericClassPSo9NSCopyingS_9ProtocolAS_9ProtocolB__", - NSStringFromClass(GenericClass>.self)) - - expectEqual("_TtGC1a17MultiGenericClassGVS_13GenericStructSi_GOS_11GenericEnumGS2_Si___", - NSStringFromClass(MultiGenericClass, - GenericEnum>>.self)) -} - Runtime.test("casting AnyObject to class metatypes") { do { var ao: AnyObject = SomeClass() expectTrue(ao as? Any.Type == nil) expectTrue(ao as? AnyClass == nil) - - ao = SomeNSObjectSubclass() - expectTrue(ao as? Any.Type == nil) - expectTrue(ao as? AnyClass == nil) - - ao = SomeClass.self - expectTrue(ao as? Any.Type == SomeClass.self) - expectTrue(ao as? AnyClass == SomeClass.self) - expectTrue(ao as? SomeClass.Type == SomeClass.self) - - ao = SomeNSObjectSubclass.self - expectTrue(ao as? Any.Type == SomeNSObjectSubclass.self) - expectTrue(ao as? AnyClass == SomeNSObjectSubclass.self) - expectTrue(ao as? SomeNSObjectSubclass.Type == SomeNSObjectSubclass.self) } do { var a: Any = SomeClass() expectTrue(a as? Any.Type == nil) expectTrue(a as? AnyClass == nil) - - a = SomeNSObjectSubclass() - expectTrue(a as? Any.Type == nil) - expectTrue(a as? AnyClass == nil) - + a = SomeClass.self expectTrue(a as? Any.Type == SomeClass.self) expectTrue(a as? AnyClass == SomeClass.self) expectTrue(a as? SomeClass.Type == SomeClass.self) } - - do { - var nso: NSObject = SomeNSObjectSubclass() - expectTrue(nso as? AnyClass == nil) - - nso = (SomeNSObjectSubclass.self as AnyObject) as! NSObject - expectTrue(nso as? Any.Type == SomeNSObjectSubclass.self) - expectTrue(nso as? AnyClass == SomeNSObjectSubclass.self) - expectTrue(nso as? SomeNSObjectSubclass.Type == SomeNSObjectSubclass.self) - } } class Malkovich: Malkovichable { @@ -893,155 +463,6 @@ Runtime.test("Struct layout with reference storage types") { print(malkovich) } -var RuntimeFoundationWrappers = TestSuite("RuntimeFoundationWrappers") - -RuntimeFoundationWrappers.test("_stdlib_NSObject_isEqual/NoLeak") { - nsObjectCanaryCount = 0 - autoreleasepool { - let a = NSObjectCanary() - let b = NSObjectCanary() - expectEqual(2, nsObjectCanaryCount) - _stdlib_NSObject_isEqual(a, b) - } - expectEqual(0, nsObjectCanaryCount) -} - -var nsStringCanaryCount = 0 -@objc class NSStringCanary : NSString { - override init() { - nsStringCanaryCount += 1 - super.init() - } - required init(coder: NSCoder) { - fatalError("don't call this initializer") - } - deinit { - nsStringCanaryCount -= 1 - } - @objc override var length: Int { - return 0 - } - @objc override func characterAtIndex(index: Int) -> unichar { - fatalError("out-of-bounds access") - } -} - -RuntimeFoundationWrappers.test( - "_stdlib_compareNSStringDeterministicUnicodeCollation/NoLeak" -) { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - let b = NSStringCanary() - expectEqual(2, nsStringCanaryCount) - _stdlib_compareNSStringDeterministicUnicodeCollation(a, b) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringNFDHashValue/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_NSStringNFDHashValue(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringASCIIHashValue/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_NSStringASCIIHashValue(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringHasPrefixNFD/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - let b = NSStringCanary() - expectEqual(2, nsStringCanaryCount) - _stdlib_NSStringHasPrefixNFD(a, b) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringHasSuffixNFD/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - let b = NSStringCanary() - expectEqual(2, nsStringCanaryCount) - _stdlib_NSStringHasSuffixNFD(a, b) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringLowercaseString/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_NSStringLowercaseString(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_NSStringUppercaseString/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_NSStringUppercaseString(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_CFStringCreateCopy/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_binary_CFStringCreateCopy(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_CFStringGetLength/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_binary_CFStringGetLength(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("_stdlib_CFStringGetCharactersPtr/NoLeak") { - nsStringCanaryCount = 0 - autoreleasepool { - let a = NSStringCanary() - expectEqual(1, nsStringCanaryCount) - _stdlib_binary_CFStringGetCharactersPtr(a) - } - expectEqual(0, nsStringCanaryCount) -} - -RuntimeFoundationWrappers.test("bridgedNSArray") { - var c = [NSObject]() - autoreleasepool { - let a = [NSObject]() - let b = a as NSArray - c = b as! [NSObject] - } - c.append(NSObject()) - // expect no crash. -} - var Reflection = TestSuite("Reflection") func wrap1 (x: Any) -> Any { return x } @@ -1060,7 +481,7 @@ Reflection.test("nested existential containers") { Reflection.test("dumpToAStream") { var output = "" dump([ 42, 4242 ], &output) - expectEqual("▿ 2 elements\n - [0]: 42\n - [1]: 4242\n", output) + expectEqual("▿ 2 elements\n - 42\n - 4242\n", output) } struct StructWithDefaultMirror { @@ -1075,7 +496,7 @@ Reflection.test("Struct/NonGeneric/DefaultMirror") { do { var output = "" dump(StructWithDefaultMirror("123"), &output) - expectEqual("▿ a.StructWithDefaultMirror\n - s: 123\n", output) + expectEqual("▿ a.StructWithDefaultMirror\n - s: \"123\"\n", output) } do { @@ -1083,16 +504,10 @@ Reflection.test("Struct/NonGeneric/DefaultMirror") { // the internal _MirrorType implementation gets memory management right. var output = "" dump(StructWithDefaultMirror("\(456)"), &output) - expectEqual("▿ a.StructWithDefaultMirror\n - s: 456\n", output) + expectEqual("▿ a.StructWithDefaultMirror\n - s: \"456\"\n", output) } - // Structs have no identity and thus no object identifier - expectEmpty(_reflect(StructWithDefaultMirror("")).objectIdentifier) - - // The default mirror provides no quick look object - expectEmpty(_reflect(StructWithDefaultMirror("")).quickLookObject) - - expectEqual(.Struct, _reflect(StructWithDefaultMirror("")).disposition) + expectEqual(.Struct, Mirror(reflecting: StructWithDefaultMirror("")).displayStyle) } struct GenericStructWithDefaultMirror { @@ -1112,11 +527,11 @@ Reflection.test("Struct/Generic/DefaultMirror") { "▿ a.GenericStructWithDefaultMirror>>>\n" + " - first: 123\n" + " ▿ second: 3 elements\n" + - " ▿ [0]: abc\n" + - " - Some: abc\n" + - " ▿ [1]: 456\n" + + " ▿ Optional(\"abc\")\n" + + " - Some: \"abc\"\n" + + " ▿ Optional(456)\n" + " - Some: 456\n" + - " ▿ [2]: 789.25\n" + + " ▿ Optional(789.25)\n" + " - Some: 789.25\n" expectEqual(expected, output) @@ -1137,8 +552,8 @@ Reflection.test("Enum/NoPayload/DefaultMirror") { let expected = "▿ 2 elements\n" + - " - [0]: a.NoPayloadEnumWithDefaultMirror.A\n" + - " - [1]: a.NoPayloadEnumWithDefaultMirror.ß\n" + " - a.NoPayloadEnumWithDefaultMirror.A\n" + + " - a.NoPayloadEnumWithDefaultMirror.ß\n" expectEqual(expected, output) } @@ -1174,7 +589,7 @@ Reflection.test("Enum/SingletonGeneric/DefaultMirror") { let expected = "▿ a.SingletonGenericEnumWithDefaultMirror.OnlyOne\n" + - " - OnlyOne: IIfx\n" + " - OnlyOne: \"IIfx\"\n" expectEqual(expected, output) } @@ -1206,11 +621,11 @@ Reflection.test("Enum/SinglePayloadNonGeneric/DefaultMirror") { let expected = "▿ 3 elements\n" + - " - [0]: a.SinglePayloadNonGenericEnumWithDefaultMirror.Cat\n" + - " - [1]: a.SinglePayloadNonGenericEnumWithDefaultMirror.Dog\n" + - " ▿ [2]: a.SinglePayloadNonGenericEnumWithDefaultMirror.Volleyball\n" + + " - a.SinglePayloadNonGenericEnumWithDefaultMirror.Cat\n" + + " - a.SinglePayloadNonGenericEnumWithDefaultMirror.Dog\n" + + " ▿ a.SinglePayloadNonGenericEnumWithDefaultMirror.Volleyball\n" + " ▿ Volleyball: (2 elements)\n" + - " - .0: Wilson\n" + + " - .0: \"Wilson\"\n" + " - .1: 2000\n" expectEqual(expected, output) @@ -1234,13 +649,13 @@ Reflection.test("Enum/SinglePayloadGeneric/DefaultMirror") { let expected = "▿ 3 elements\n" + - " - [0]: a.SinglePayloadGenericEnumWithDefaultMirror>.Well\n" + - " - [1]: a.SinglePayloadGenericEnumWithDefaultMirror>.Faucet\n" + - " ▿ [2]: a.SinglePayloadGenericEnumWithDefaultMirror>.Pipe\n" + + " - a.SinglePayloadGenericEnumWithDefaultMirror>.Well\n" + + " - a.SinglePayloadGenericEnumWithDefaultMirror>.Faucet\n" + + " ▿ a.SinglePayloadGenericEnumWithDefaultMirror>.Pipe\n" + " ▿ Pipe: (2 elements)\n" + " - .0: 408\n" + " ▿ .1: 1 element\n" + - " - [0]: 415\n" + " - 415\n" expectEqual(expected, output) } @@ -1265,11 +680,11 @@ Reflection.test("Enum/MultiPayloadTagBitsNonGeneric/DefaultMirror") { let expected = "▿ 4 elements\n" + - " - [0]: a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Plus\n" + - " - [1]: a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.SE30\n" + - " ▿ [2]: a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Classic\n" + + " - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Plus\n" + + " - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.SE30\n" + + " ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Classic\n" + " - Classic: 16\n" + - " ▿ [3]: a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Performa\n" + + " ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Performa\n" + " - Performa: 220\n" expectEqual(expected, output) @@ -1310,13 +725,13 @@ Reflection.test("Enum/MultiPayloadSpareBitsNonGeneric/DefaultMirror") { let expected = "▿ 5 elements\n" + - " - [0]: a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacWrite\n" + - " - [1]: a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacPaint\n" + - " - [2]: a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.FileMaker\n" + - " ▿ [3]: a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.ClarisWorks\n" + + " - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacWrite\n" + + " - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacPaint\n" + + " - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.FileMaker\n" + + " ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.ClarisWorks\n" + " ▿ ClarisWorks: a.Floppy #0\n" + " - capacity: 800\n" + - " ▿ [4]: a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.HyperCard\n" + + " ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.HyperCard\n" + " ▿ HyperCard: a.CDROM #1\n" + " - capacity: 600\n" @@ -1346,12 +761,12 @@ Reflection.test("Enum/MultiPayloadTagBitsSmallNonGeneric/DefaultMirror") { let expected = "▿ 5 elements\n" + - " - [0]: a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacWrite\n" + - " - [1]: a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacPaint\n" + - " - [2]: a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.FileMaker\n" + - " ▿ [3]: a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.ClarisWorks\n" + + " - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacWrite\n" + + " - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacPaint\n" + + " - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.FileMaker\n" + + " ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.ClarisWorks\n" + " - ClarisWorks: true\n" + - " ▿ [4]: a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.HyperCard\n" + + " ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.HyperCard\n" + " - HyperCard: false\n" expectEqual(expected, output) @@ -1382,14 +797,14 @@ Reflection.test("Enum/MultiPayloadGeneric/DefaultMirror") { let expected = "▿ 6 elements\n" + - " - [0]: a.MultiPayloadGenericEnumWithDefaultMirror.IIe\n" + - " - [1]: a.MultiPayloadGenericEnumWithDefaultMirror.IIgs\n" + - " ▿ [2]: a.MultiPayloadGenericEnumWithDefaultMirror.Centris\n" + + " - a.MultiPayloadGenericEnumWithDefaultMirror.IIe\n" + + " - a.MultiPayloadGenericEnumWithDefaultMirror.IIgs\n" + + " ▿ a.MultiPayloadGenericEnumWithDefaultMirror.Centris\n" + " - Centris: 4096\n" + - " ▿ [3]: a.MultiPayloadGenericEnumWithDefaultMirror.Quadra\n" + - " - Quadra: 160MB\n" + - " - [4]: a.MultiPayloadGenericEnumWithDefaultMirror.PowerBook170\n" + - " - [5]: a.MultiPayloadGenericEnumWithDefaultMirror.PowerBookDuo220\n" + " ▿ a.MultiPayloadGenericEnumWithDefaultMirror.Quadra\n" + + " - Quadra: \"160MB\"\n" + + " - a.MultiPayloadGenericEnumWithDefaultMirror.PowerBook170\n" + + " - a.MultiPayloadGenericEnumWithDefaultMirror.PowerBookDuo220\n" expectEqual(expected, output) } @@ -1427,57 +842,7 @@ Reflection.test("Enum/IndirectGeneric/DefaultMirror") { "Cons(0, a.List.Cons(1, a.List.Nil))") } -/// A type that provides its own mirror. -struct BrilliantMirror : _MirrorType { - let _value: Brilliant - - init (_ _value: Brilliant) { - self._value = _value - } - - var value: Any { - return _value - } - - var valueType: Any.Type { - return value.dynamicType - } - - var objectIdentifier: ObjectIdentifier? { - return ObjectIdentifier(_value) - } - - var count: Int { - return 3 - } - - subscript(i: Int) -> (String, _MirrorType) { - switch i { - case 0: - return ("first", _reflect(_value.first)) - case 1: - return ("second", _reflect(_value.second)) - case 2: - return ("self", self) - case _: - _preconditionFailure("child index out of bounds") - } - } - - var summary: String { - return "Brilliant(\(_value.first), \(_value.second))" - } - - var quickLookObject: PlaygroundQuickLook? { - return nil - } - - var disposition: _MirrorDisposition { - return .Container - } -} - -class Brilliant : _Reflectable { +class Brilliant : CustomReflectable { let first: Int let second: String @@ -1486,8 +851,8 @@ class Brilliant : _Reflectable { self.second = snd } - func _getMirror() -> _MirrorType { - return BrilliantMirror(self) + func customMirror() -> Mirror { + return Mirror(self, children: ["first": first, "second": second, "self": self]) } } @@ -1504,10 +869,10 @@ Reflection.test("CustomMirror") { dump(Brilliant(123, "four five six"), &output) let expected = - "▿ Brilliant(123, four five six) #0\n" + + "▿ a.Brilliant #0\n" + " - first: 123\n" + - " - second: four five six\n" + - " ▿ self: Brilliant(123, four five six) #0\n" + " - second: \"four five six\"\n" + + " ▿ self: a.Brilliant #0\n" expectEqual(expected, output) } @@ -1515,7 +880,7 @@ Reflection.test("CustomMirror") { do { var output = "" dump(Brilliant(123, "four five six"), &output, maxDepth: 0) - expectEqual("▹ Brilliant(123, four five six) #0\n", output) + expectEqual("▹ a.Brilliant #0\n", output) } do { @@ -1523,9 +888,9 @@ Reflection.test("CustomMirror") { dump(Brilliant(123, "four five six"), &output, maxItems: 3) let expected = - "▿ Brilliant(123, four five six) #0\n" + + "▿ a.Brilliant #0\n" + " - first: 123\n" + - " - second: four five six\n" + + " - second: \"four five six\"\n" + " (1 more child)\n" expectEqual(expected, output) @@ -1536,7 +901,7 @@ Reflection.test("CustomMirror") { dump(Brilliant(123, "four five six"), &output, maxItems: 2) let expected = - "▿ Brilliant(123, four five six) #0\n" + + "▿ a.Brilliant #0\n" + " - first: 123\n" + " (2 more children)\n" @@ -1548,14 +913,12 @@ Reflection.test("CustomMirror") { dump(Brilliant(123, "four five six"), &output, maxItems: 1) let expected = - "▿ Brilliant(123, four five six) #0\n" + + "▿ a.Brilliant #0\n" + " (3 children)\n" expectEqual(expected, output) } - expectEqual(.Container, _reflect(Brilliant(123, "four five six")).disposition) - do { // Check that object identifiers are unique to class instances. let a = Brilliant(1, "") @@ -1590,34 +953,10 @@ Reflection.test("CustomMirrorIsInherited") { dump(Irradiant(), &output) let expected = - "▿ Brilliant(400, ) #0\n" + + "▿ a.Brilliant #0\n" + " - first: 400\n" + - " - second: \n" + - " ▿ self: Brilliant(400, ) #0\n" - - expectEqual(expected, output) - } -} - -class SwiftFooMoreDerivedObjCClass : FooMoreDerivedObjCClass { - let first: Int = 123 - let second: String = "abc" -} - -Reflection.test("Class/ObjectiveCBase/Default") { - do { - let value = SwiftFooMoreDerivedObjCClass() - var output = "" - dump(value, &output) - - let expected = - "▿ a.SwiftFooMoreDerivedObjCClass #0\n" + - " ▿ super: This is FooObjCClass\n" + - " ▿ FooDerivedObjCClass: This is FooObjCClass\n" + - " ▿ FooObjCClass: This is FooObjCClass\n" + - " - NSObject: This is FooObjCClass\n" + - " - first: 123\n" + - " - second: abc\n" + " - second: \"\"\n" + + " ▿ self: a.Brilliant #0\n" expectEqual(expected, output) } @@ -1626,9 +965,6 @@ Reflection.test("Class/ObjectiveCBase/Default") { protocol SomeNativeProto {} extension Int: SomeNativeProto {} -@objc protocol SomeObjCProto {} -extension SomeClass: SomeObjCProto {} - Reflection.test("MetatypeMirror") { do { var output = "" @@ -1648,47 +984,17 @@ Reflection.test("MetatypeMirror") { dump(nativeProtocolMetatype, &output) expectEqual(expectedInt, output) - expectEqual(_reflect(concreteMetatype).objectIdentifier!, - _reflect(anyMetatype).objectIdentifier!) - expectEqual(_reflect(concreteMetatype).objectIdentifier!, - _reflect(nativeProtocolMetatype).objectIdentifier!) - - let concreteClassMetatype = SomeClass.self let expectedSomeClass = "- a.SomeClass #0\n" output = "" dump(concreteClassMetatype, &output) expectEqual(expectedSomeClass, output) - let objcProtocolMetatype: SomeObjCProto.Type = SomeClass.self - output = "" - dump(objcProtocolMetatype, &output) - expectEqual(expectedSomeClass, output) - - expectEqual(_reflect(concreteClassMetatype).objectIdentifier!, - _reflect(objcProtocolMetatype).objectIdentifier!) - let nativeProtocolConcreteMetatype = SomeNativeProto.self let expectedNativeProtocolConcrete = "- a.SomeNativeProto #0\n" output = "" dump(nativeProtocolConcreteMetatype, &output) expectEqual(expectedNativeProtocolConcrete, output) - - let objcProtocolConcreteMetatype = SomeObjCProto.self - let expectedObjCProtocolConcrete = "- a.SomeObjCProto #0\n" - output = "" - dump(objcProtocolConcreteMetatype, &output) - expectEqual(expectedObjCProtocolConcrete, output) - - typealias Composition = protocol - let compositionConcreteMetatype = Composition.self - let expectedComposition = "- protocol #0\n" - output = "" - dump(compositionConcreteMetatype, &output) - expectEqual(expectedComposition, output) - - let objcDefinedProtoType = NSObjectProtocol.self - expectEqual(String(objcDefinedProtoType), "NSObject") } } @@ -1701,17 +1007,16 @@ Reflection.test("TupleMirror") { let expected = "▿ (2 elements)\n" + - " ▿ .0: Brilliant(384, seven six eight) #0\n" + + " ▿ .0: a.Brilliant #0\n" + " - first: 384\n" + - " - second: seven six eight\n" + - " ▿ self: Brilliant(384, seven six eight) #0\n" + + " - second: \"seven six eight\"\n" + + " ▿ self: a.Brilliant #0\n" + " ▿ .1: a.StructWithDefaultMirror\n" + - " - s: nine\n" + " - s: \"nine\"\n" expectEqual(expected, output) - expectEmpty(_reflect(tuple).quickLookObject) - expectEqual(.Tuple, _reflect(tuple).disposition) + expectEqual(.Tuple, Mirror(reflecting: tuple).displayStyle) } do { @@ -1725,7 +1030,7 @@ Reflection.test("TupleMirror") { " - .0: 1\n" + " - .1: 2.5\n" + " - .2: false\n" + - " - .3: three\n" + " - .3: \"three\"\n" expectEqual(expected, output) } @@ -1740,37 +1045,17 @@ Reflection.test("TupleMirror") { "▿ (2 elements)\n" + " - .0: 1\n" + " ▿ .1: (2 elements)\n" + - " - .0: Hello\n" + - " - .1: World\n" + " - .0: \"Hello\"\n" + + " - .1: \"World\"\n" expectEqual(expected, output) } } class DullClass {} -Reflection.test("ObjectIdentity") { - // Check that the primitive _MirrorType implementation produces appropriately - // unique identifiers for class instances. - - let x = DullClass() - let y = DullClass() - let o = NSObject() - let p = NSObject() - - checkEquatable( - true, _reflect(x).objectIdentifier!, _reflect(x).objectIdentifier!) - checkEquatable( - false, _reflect(x).objectIdentifier!, _reflect(y).objectIdentifier!) - checkEquatable( - true, _reflect(o).objectIdentifier!, _reflect(o).objectIdentifier!) - checkEquatable( - false, _reflect(o).objectIdentifier!, _reflect(p).objectIdentifier!) - checkEquatable( - false, _reflect(o).objectIdentifier!, _reflect(y).objectIdentifier!) - - expectEmpty(_reflect(x).quickLookObject) - expectEqual(.Class, _reflect(x).disposition) +Reflection.test("ClassReflection") { + expectEqual(.Class, Mirror(reflecting: DullClass()).displayStyle) } Reflection.test("String/Mirror") { @@ -1779,7 +1064,7 @@ Reflection.test("String/Mirror") { dump("", &output) let expected = - "- \n" + "- \"\"\n" expectEqual(expected, output) } @@ -1793,7 +1078,7 @@ Reflection.test("String/Mirror") { dump("\u{61}\u{304b}\u{3099}\u{1f425}", &output) let expected = - "- \u{61}\u{304b}\u{3099}\u{1f425}\n" + "- \"\u{61}\u{304b}\u{3099}\u{1f425}\"\n" expectEqual(expected, output) } @@ -1807,14 +1092,14 @@ Reflection.test("String.UTF8View/Mirror") { dump("\u{61}\u{304b}\u{3099}".utf8, &output) let expected = - "▿ \u{61}\u{304b}\u{3099}\n" + - " - [0]: 97\n" + - " - [1]: 227\n" + - " - [2]: 129\n" + - " - [3]: 139\n" + - " - [4]: 227\n" + - " - [5]: 130\n" + - " - [6]: 153\n" + "▿ UTF8View(\"\u{61}\u{304b}\u{3099}\")\n" + + " - 97\n" + + " - 227\n" + + " - 129\n" + + " - 139\n" + + " - 227\n" + + " - 130\n" + + " - 153\n" expectEqual(expected, output) } @@ -1828,12 +1113,12 @@ Reflection.test("String.UTF16View/Mirror") { dump("\u{61}\u{304b}\u{3099}\u{1f425}".utf16, &output) let expected = - "▿ \u{61}\u{304b}\u{3099}\u{1f425}\n" + - " - [0]: 97\n" + - " - [1]: 12363\n" + - " - [2]: 12441\n" + - " - [3]: 55357\n" + - " - [4]: 56357\n" + "▿ StringUTF16(\"\u{61}\u{304b}\u{3099}\u{1f425}\")\n" + + " - 97\n" + + " - 12363\n" + + " - 12441\n" + + " - 55357\n" + + " - 56357\n" expectEqual(expected, output) } @@ -1847,11 +1132,11 @@ Reflection.test("String.UnicodeScalarView/Mirror") { dump("\u{61}\u{304b}\u{3099}\u{1f425}".unicodeScalars, &output) let expected = - "▿ \u{61}\u{304b}\u{3099}\u{1f425}\n" + - " - [0]: \u{61}\n" + - " - [1]: \u{304b}\n" + - " - [2]: \u{3099}\n" + - " - [3]: \u{1f425}\n" + "▿ StringUnicodeScalarView(\"\u{61}\u{304b}\u{3099}\u{1f425}\")\n" + + " - \"\u{61}\"\n" + + " - \"\\u{304B}\"\n" + + " - \"\\u{3099}\"\n" + + " - \"\\u{0001F425}\"\n" expectEqual(expected, output) } @@ -1864,7 +1149,7 @@ Reflection.test("Character/Mirror") { dump(input, &output) let expected = - "- \u{61}\n" + "- \"\u{61}\"\n" expectEqual(expected, output) } @@ -1877,7 +1162,7 @@ Reflection.test("Character/Mirror") { dump(input, &output) let expected = - "- \u{304b}\u{3099}\n" + "- \"\u{304b}\u{3099}\"\n" expectEqual(expected, output) } @@ -1889,7 +1174,7 @@ Reflection.test("Character/Mirror") { dump(input, &output) let expected = - "- \u{1f425}\n" + "- \"\u{1f425}\"\n" expectEqual(expected, output) } @@ -1903,7 +1188,7 @@ Reflection.test("UnicodeScalar") { dump(input, &output) let expected = - "- \u{61}\n" + "- \"\u{61}\"\n" expectEqual(expected, output) } @@ -1915,7 +1200,7 @@ Reflection.test("UnicodeScalar") { dump(input, &output) let expected = - "- \u{304b}\n" + "- \"\\u{304B}\"\n" expectEqual(expected, output) } @@ -1927,7 +1212,7 @@ Reflection.test("UnicodeScalar") { dump(input, &output) let expected = - "- \u{3099}\n" + "- \"\\u{3099}\"\n" expectEqual(expected, output) } @@ -1939,7 +1224,7 @@ Reflection.test("UnicodeScalar") { dump(input, &output) let expected = - "- \u{1f425}\n" + "- \"\\u{0001F425}\"\n" expectEqual(expected, output) } @@ -2036,120 +1321,6 @@ Reflection.test("Double") { } } -Reflection.test("CGPoint") { - var output = "" - dump(CGPoint(x: 1.25, y: 2.75), &output) - - let expected = - "▿ (1.25, 2.75)\n" + - " - x: 1.25\n" + - " - y: 2.75\n" - - expectEqual(expected, output) -} - -Reflection.test("CGSize") { - var output = "" - dump(CGSize(width: 1.25, height: 2.75), &output) - - let expected = - "▿ (1.25, 2.75)\n" + - " - width: 1.25\n" + - " - height: 2.75\n" - - expectEqual(expected, output) -} - -Reflection.test("CGRect") { - var output = "" - dump( - CGRect( - origin: CGPoint(x: 1.25, y: 2.25), - size: CGSize(width: 10.25, height: 11.75)), - &output) - - let expected = - "▿ (1.25, 2.25, 10.25, 11.75)\n" + - " ▿ origin: (1.25, 2.25)\n" + - " - x: 1.25\n" + - " - y: 2.25\n" + - " ▿ size: (10.25, 11.75)\n" + - " - width: 10.25\n" + - " - height: 11.75\n" - - expectEqual(expected, output) -} - -Reflection.test("Unmanaged/nil") { - var output = "" - var optionalURL: Unmanaged? = nil - dump(optionalURL, &output) - - let expected = "- nil\n" - - expectEqual(expected, output) -} - -Reflection.test("Unmanaged/not-nil") { - var output = "" - var optionalURL: Unmanaged? = - Unmanaged.passRetained(CFURLCreateWithString(nil, "http://llvm.org/", nil)) - dump(optionalURL, &output) - - let expected = - "▿ Swift.Unmanaged<__ObjC.CFURL>\n" + - " ▿ Some: Swift.Unmanaged<__ObjC.CFURL>\n" + - " ▿ _value: http://llvm.org/ #0\n" + - " - NSObject: http://llvm.org/\n" - - expectEqual(expected, output) - - optionalURL!.release() -} - -Reflection.test("TupleMirror/NoLeak") { - do { - nsObjectCanaryCount = 0 - autoreleasepool { - var tuple = (1, NSObjectCanary()) - expectEqual(1, nsObjectCanaryCount) - var output = "" - dump(tuple, &output) - } - expectEqual(0, nsObjectCanaryCount) - } - do { - nsObjectCanaryCount = 0 - autoreleasepool { - var tuple = (1, NSObjectCanaryStruct()) - expectEqual(1, nsObjectCanaryCount) - var output = "" - dump(tuple, &output) - } - expectEqual(0, nsObjectCanaryCount) - } - do { - swiftObjectCanaryCount = 0 - autoreleasepool { - var tuple = (1, SwiftObjectCanary()) - expectEqual(1, swiftObjectCanaryCount) - var output = "" - dump(tuple, &output) - } - expectEqual(0, swiftObjectCanaryCount) - } - do { - swiftObjectCanaryCount = 0 - autoreleasepool { - var tuple = (1, SwiftObjectCanaryStruct()) - expectEqual(1, swiftObjectCanaryCount) - var output = "" - dump(tuple, &output) - } - expectEqual(0, swiftObjectCanaryCount) - } -} - // A struct type and class type whose NominalTypeDescriptor.FieldNames // data is exactly eight bytes long. FieldNames data of exactly // 4 or 8 or 16 bytes was once miscompiled on arm64. @@ -2191,9 +1362,9 @@ Reflection.test("MirrorMirror") { Reflection.test("COpaquePointer/null") { // Don't crash on null pointers. rdar://problem/19708338 var sequence = COpaquePointer() - var mirror = _reflect(sequence) - var child = mirror[0] - expectEqual("(Opaque Value)", child.1.summary) + var mirror = Mirror(reflecting: sequence) + var child = mirror.children.first! + expectEqual("(Opaque Value)", "\(child.1)") } Reflection.test("StaticString/Mirror") { @@ -2202,7 +1373,7 @@ Reflection.test("StaticString/Mirror") { dump("" as StaticString, &output) let expected = - "- \n" + "- \"\"\n" expectEqual(expected, output) } @@ -2216,49 +1387,12 @@ Reflection.test("StaticString/Mirror") { dump("\u{61}\u{304b}\u{3099}\u{1f425}" as StaticString, &output) let expected = - "- \u{61}\u{304b}\u{3099}\u{1f425}\n" + "- \"\u{61}\u{304b}\u{3099}\u{1f425}\"\n" expectEqual(expected, output) } } -class TestArtificialSubclass: NSObject { - dynamic var foo = "foo" -} - -var KVOHandle = 0 - -Reflection.test("Name of metatype of artificial subclass") { - let obj = TestArtificialSubclass() - // Trigger the creation of a KVO subclass for TestArtificialSubclass. - obj.addObserver(obj, forKeyPath: "foo", options: [.New], context: &KVOHandle) - obj.removeObserver(obj, forKeyPath: "foo") - - expectEqual("\(obj.dynamicType)", "TestArtificialSubclass") -} - -@objc class StringConvertibleInDebugAndOtherwise : NSObject { - override var description: String { return "description" } - override var debugDescription: String { return "debugDescription" } -} - -Reflection.test("NSObject is properly CustomDebugStringConvertible") { - let object = StringConvertibleInDebugAndOtherwise() - expectEqual(String(reflecting: object), object.debugDescription) -} - -Reflection.test("NSRange QuickLook") { - let rng = NSRange(location:Int.min, length:5) - let ql = PlaygroundQuickLook(reflecting: rng) - switch ql { - case .Range(let loc, let len): - expectEqual(loc, Int64(Int.min)) - expectEqual(len, 5) - default: - expectUnreachable("PlaygroundQuickLook for NSRange did not match Range") - } -} - var BitTwiddlingTestSuite = TestSuite("BitTwiddling") func computeCountLeadingZeroes(x: Int64) -> Int64 { @@ -2295,7 +1429,7 @@ BitTwiddlingTestSuite.test("_isPowerOf2/Int") { expectTrue(_isPowerOf2(asInt(1024))) #if arch(i386) || arch(arm) // Not applicable to 32-bit architectures. -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) expectTrue(_isPowerOf2(asInt(0x8000_0000))) #else fatalError("implement") @@ -2323,19 +1457,6 @@ BitTwiddlingTestSuite.test("_floorLog2") { expectEqual(_floorLog2(Int64.max), 62) // 63 minus 1 for sign bit. } -class SomeSubclass : SomeClass {} - -var ObjCConformsToProtocolTestSuite = TestSuite("ObjCConformsToProtocol") - -ObjCConformsToProtocolTestSuite.test("cast/instance") { - expectTrue(SomeClass() is SomeObjCProto) - expectTrue(SomeSubclass() is SomeObjCProto) -} -ObjCConformsToProtocolTestSuite.test("cast/metatype") { - expectTrue(SomeClass.self is SomeObjCProto.Type) - expectTrue(SomeSubclass.self is SomeObjCProto.Type) -} - var AvailabilityVersionsTestSuite = TestSuite("AvailabilityVersions") AvailabilityVersionsTestSuite.test("lexicographic_compare") { diff --git a/test/1_stdlib/RuntimeObjC.swift b/test/1_stdlib/RuntimeObjC.swift new file mode 100644 index 0000000000000..a7fdcbdb409cd --- /dev/null +++ b/test/1_stdlib/RuntimeObjC.swift @@ -0,0 +1,882 @@ +// RUN: rm -rf %t && mkdir %t +// +// RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g +// RUN: %target-build-swift -parse-stdlib -Xfrontend -disable-access-control -module-name a -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o %s -o %t.out +// RUN: %target-run %t.out +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import Swift +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + +import Foundation +import CoreGraphics +import SwiftShims +import MirrorObjC + +var nsObjectCanaryCount = 0 +@objc class NSObjectCanary : NSObject { + override init() { + nsObjectCanaryCount += 1 + } + deinit { + nsObjectCanaryCount -= 1 + } +} + +struct NSObjectCanaryStruct { + var ref = NSObjectCanary() +} + +var swiftObjectCanaryCount = 0 +class SwiftObjectCanary { + init() { + swiftObjectCanaryCount += 1 + } + deinit { + swiftObjectCanaryCount -= 1 + } +} + +struct SwiftObjectCanaryStruct { + var ref = SwiftObjectCanary() +} + +@objc class ClassA { + init(value: Int) { + self.value = value + } + + var value: Int +} + +struct NotBridgedValueType { + // Keep it pointer-sized. + var canaryRef = SwiftObjectCanary() +} + +struct BridgedValueType : _ObjectiveCBridgeable { + init(value: Int) { + self.value = value + } + + static func _getObjectiveCType() -> Any.Type { + return ClassA.self + } + + func _bridgeToObjectiveC() -> ClassA { + return ClassA(value: value) + } + + static func _isBridgedToObjectiveC() -> Bool { + return true + } + + static func _forceBridgeFromObjectiveC( + x: ClassA, + inout result: BridgedValueType? + ) { + assert(x.value % 2 == 0, "not bridged to Objective-C") + result = BridgedValueType(value: x.value) + } + + static func _conditionallyBridgeFromObjectiveC( + x: ClassA, + inout result: BridgedValueType? + ) -> Bool { + if x.value % 2 == 0 { + result = BridgedValueType(value: x.value) + return true + } + + result = nil + return false + } + + var value: Int + var canaryRef = SwiftObjectCanary() +} + +struct BridgedLargeValueType : _ObjectiveCBridgeable { + init(value: Int) { + value0 = value + value1 = value + value2 = value + value3 = value + value4 = value + value5 = value + value6 = value + value7 = value + } + + static func _getObjectiveCType() -> Any.Type { + return ClassA.self + } + + func _bridgeToObjectiveC() -> ClassA { + assert(value == value0) + return ClassA(value: value0) + } + + static func _isBridgedToObjectiveC() -> Bool { + return true + } + + static func _forceBridgeFromObjectiveC( + x: ClassA, + inout result: BridgedLargeValueType? + ) { + assert(x.value % 2 == 0, "not bridged to Objective-C") + result = BridgedLargeValueType(value: x.value) + } + + static func _conditionallyBridgeFromObjectiveC( + x: ClassA, + inout result: BridgedLargeValueType? + ) -> Bool { + if x.value % 2 == 0 { + result = BridgedLargeValueType(value: x.value) + return true + } + + result = nil + return false + } + + var value: Int { + let x = value0 + assert(value0 == x && value1 == x && value2 == x && value3 == x && + value4 == x && value5 == x && value6 == x && value7 == x) + return x + } + + var (value0, value1, value2, value3): (Int, Int, Int, Int) + var (value4, value5, value6, value7): (Int, Int, Int, Int) + var canaryRef = SwiftObjectCanary() +} + + +struct ConditionallyBridgedValueType : _ObjectiveCBridgeable { + init(value: Int) { + self.value = value + } + + static func _getObjectiveCType() -> Any.Type { + return ClassA.self + } + + func _bridgeToObjectiveC() -> ClassA { + return ClassA(value: value) + } + + static func _forceBridgeFromObjectiveC( + x: ClassA, + inout result: ConditionallyBridgedValueType? + ) { + assert(x.value % 2 == 0, "not bridged from Objective-C") + result = ConditionallyBridgedValueType(value: x.value) + } + + static func _conditionallyBridgeFromObjectiveC( + x: ClassA, + inout result: ConditionallyBridgedValueType? + ) -> Bool { + if x.value % 2 == 0 { + result = ConditionallyBridgedValueType(value: x.value) + return true + } + + result = nil + return false + } + + static func _isBridgedToObjectiveC() -> Bool { + return ((T.self as Any) as? String.Type) == nil + } + + var value: Int + var canaryRef = SwiftObjectCanary() +} + +class BridgedVerbatimRefType { + var value: Int = 42 + var canaryRef = SwiftObjectCanary() +} + +func withSwiftObjectCanary( + createValue: () -> T, + _ check: (T) -> Void, + file: String = __FILE__, line: UInt = __LINE__ +) { + let stackTrace = SourceLocStack(SourceLoc(file, line)) + + swiftObjectCanaryCount = 0 + autoreleasepool { + var valueWithCanary = createValue() + expectEqual(1, swiftObjectCanaryCount, stackTrace: stackTrace) + check(valueWithCanary) + } + expectEqual(0, swiftObjectCanaryCount, stackTrace: stackTrace) +} + +var Runtime = TestSuite("Runtime") + +func _isClassOrObjCExistential_Opaque(x: T.Type) -> Bool { + return _isClassOrObjCExistential(_opaqueIdentity(x)) +} + +Runtime.test("_isClassOrObjCExistential") { + expectTrue(_isClassOrObjCExistential(NSObjectCanary.self)) + expectTrue(_isClassOrObjCExistential_Opaque(NSObjectCanary.self)) + + expectFalse(_isClassOrObjCExistential(NSObjectCanaryStruct.self)) + expectFalse(_isClassOrObjCExistential_Opaque(NSObjectCanaryStruct.self)) + + expectTrue(_isClassOrObjCExistential(SwiftObjectCanary.self)) + expectTrue(_isClassOrObjCExistential_Opaque(SwiftObjectCanary.self)) + + expectFalse(_isClassOrObjCExistential(SwiftObjectCanaryStruct.self)) + expectFalse(_isClassOrObjCExistential_Opaque(SwiftObjectCanaryStruct.self)) + + typealias SwiftClosure = () -> () + expectFalse(_isClassOrObjCExistential(SwiftClosure.self)) + expectFalse(_isClassOrObjCExistential_Opaque(SwiftClosure.self)) + + typealias ObjCClosure = @convention(block) () -> () + expectTrue(_isClassOrObjCExistential(ObjCClosure.self)) + expectTrue(_isClassOrObjCExistential_Opaque(ObjCClosure.self)) + + expectTrue(_isClassOrObjCExistential(CFArray.self)) + expectTrue(_isClassOrObjCExistential_Opaque(CFArray.self)) + + expectTrue(_isClassOrObjCExistential(CFArray.self)) + expectTrue(_isClassOrObjCExistential_Opaque(CFArray.self)) + + expectTrue(_isClassOrObjCExistential(AnyObject.self)) + expectTrue(_isClassOrObjCExistential_Opaque(AnyObject.self)) + + // AnyClass == AnyObject.Type + expectFalse(_isClassOrObjCExistential(AnyClass.self)) + expectFalse(_isClassOrObjCExistential_Opaque(AnyClass.self)) + + expectFalse(_isClassOrObjCExistential(AnyObject.Protocol.self)) + expectFalse(_isClassOrObjCExistential_Opaque(AnyObject.Protocol.self)) + + expectFalse(_isClassOrObjCExistential(NSObjectCanary.Type.self)) + expectFalse(_isClassOrObjCExistential_Opaque(NSObjectCanary.Type.self)) +} + +Runtime.test("_canBeClass") { + expectEqual(1, _canBeClass(NSObjectCanary.self)) + expectEqual(0, _canBeClass(NSObjectCanaryStruct.self)) + + typealias ObjCClosure = @convention(block) () -> () + expectEqual(1, _canBeClass(ObjCClosure.self)) + + expectEqual(1, _canBeClass(CFArray.self)) +} + +Runtime.test("bridgeToObjectiveC") { + expectEmpty(_bridgeToObjectiveC(NotBridgedValueType())) + + expectEqual(42, (_bridgeToObjectiveC(BridgedValueType(value: 42)) as! ClassA).value) + + expectEqual(42, (_bridgeToObjectiveC(BridgedLargeValueType(value: 42)) as! ClassA).value) + + expectEqual(42, (_bridgeToObjectiveC(ConditionallyBridgedValueType(value: 42)) as! ClassA).value) + + expectEmpty(_bridgeToObjectiveC(ConditionallyBridgedValueType(value: 42))) + + var bridgedVerbatimRef = BridgedVerbatimRefType() + expectTrue(_bridgeToObjectiveC(bridgedVerbatimRef) === bridgedVerbatimRef) +} + +Runtime.test("bridgeToObjectiveC/NoLeak") { + withSwiftObjectCanary( + { NotBridgedValueType() }, + { expectEmpty(_bridgeToObjectiveC($0)) }) + + withSwiftObjectCanary( + { BridgedValueType(value: 42) }, + { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) + + withSwiftObjectCanary( + { BridgedLargeValueType(value: 42) }, + { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) + + withSwiftObjectCanary( + { ConditionallyBridgedValueType(value: 42) }, + { expectEqual(42, (_bridgeToObjectiveC($0) as! ClassA).value) }) + + withSwiftObjectCanary( + { ConditionallyBridgedValueType(value: 42) }, + { expectEmpty(_bridgeToObjectiveC($0)) }) + + withSwiftObjectCanary( + { BridgedVerbatimRefType() }, + { expectTrue(_bridgeToObjectiveC($0) === $0) }) +} + +Runtime.test("forceBridgeFromObjectiveC") { + // Bridge back using NotBridgedValueType. + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 21), NotBridgedValueType.self)) + + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 42), NotBridgedValueType.self)) + + expectEmpty(_conditionallyBridgeFromObjectiveC( + BridgedVerbatimRefType(), NotBridgedValueType.self)) + + // Bridge back using BridgedValueType. + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 21), BridgedValueType.self)) + + expectEqual(42, _forceBridgeFromObjectiveC( + ClassA(value: 42), BridgedValueType.self).value) + expectEqual(42, _conditionallyBridgeFromObjectiveC( + ClassA(value: 42), BridgedValueType.self)!.value) + + expectEmpty(_conditionallyBridgeFromObjectiveC( + BridgedVerbatimRefType(), BridgedValueType.self)) + + // Bridge back using BridgedLargeValueType. + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 21), BridgedLargeValueType.self)) + + expectEqual(42, _forceBridgeFromObjectiveC( + ClassA(value: 42), BridgedLargeValueType.self).value) + expectEqual(42, _conditionallyBridgeFromObjectiveC( + ClassA(value: 42), BridgedLargeValueType.self)!.value) + + expectEmpty(_conditionallyBridgeFromObjectiveC( + BridgedVerbatimRefType(), BridgedLargeValueType.self)) + + // Bridge back using BridgedVerbatimRefType. + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 21), BridgedVerbatimRefType.self)) + + expectEmpty(_conditionallyBridgeFromObjectiveC( + ClassA(value: 42), BridgedVerbatimRefType.self)) + + var bridgedVerbatimRef = BridgedVerbatimRefType() + expectTrue(_forceBridgeFromObjectiveC( + bridgedVerbatimRef, BridgedVerbatimRefType.self) === bridgedVerbatimRef) + expectTrue(_conditionallyBridgeFromObjectiveC( + bridgedVerbatimRef, BridgedVerbatimRefType.self)! === bridgedVerbatimRef) +} + + +Runtime.test("isBridgedToObjectiveC") { + expectFalse(_isBridgedToObjectiveC(NotBridgedValueType)) + expectTrue(_isBridgedToObjectiveC(BridgedValueType)) + expectTrue(_isBridgedToObjectiveC(BridgedVerbatimRefType)) +} + +Runtime.test("isBridgedVerbatimToObjectiveC") { + expectFalse(_isBridgedVerbatimToObjectiveC(NotBridgedValueType)) + expectFalse(_isBridgedVerbatimToObjectiveC(BridgedValueType)) + expectTrue(_isBridgedVerbatimToObjectiveC(BridgedVerbatimRefType)) +} + +//===----------------------------------------------------------------------===// + +class SomeClass {} +@objc class SomeObjCClass {} +class SomeNSObjectSubclass : NSObject {} + +Runtime.test("typeName") { + expectEqual("a.SomeObjCClass", _typeName(SomeObjCClass.self)) + expectEqual("a.SomeNSObjectSubclass", _typeName(SomeNSObjectSubclass.self)) + expectEqual("NSObject", _typeName(NSObject.self)) + + var a : Any = SomeObjCClass() + expectEqual("a.SomeObjCClass", _typeName(a.dynamicType)) + + a = SomeNSObjectSubclass() + expectEqual("a.SomeNSObjectSubclass", _typeName(a.dynamicType)) + + a = NSObject() + expectEqual("NSObject", _typeName(a.dynamicType)) +} + +class GenericClass {} +class MultiGenericClass {} +struct GenericStruct {} +enum GenericEnum {} + +struct PlainStruct {} +enum PlainEnum {} + +protocol ProtocolA {} +protocol ProtocolB {} + +Runtime.test("Generic class ObjC runtime names") { + expectEqual("_TtGC1a12GenericClassSi_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassVS_11PlainStruct_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassOS_9PlainEnum_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassTVS_11PlainStructOS_9PlainEnumS1___", + NSStringFromClass(GenericClass<(PlainStruct, PlainEnum, PlainStruct)>.self)) + expectEqual("_TtGC1a12GenericClassMVS_11PlainStruct_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassFMVS_11PlainStructS1__", + NSStringFromClass(GenericClass PlainStruct>.self)) + + expectEqual("_TtGC1a12GenericClassFzMVS_11PlainStructS1__", + NSStringFromClass(GenericClass PlainStruct>.self)) + expectEqual("_TtGC1a12GenericClassFTVS_11PlainStructROS_9PlainEnum_Si_", + NSStringFromClass(GenericClass<(PlainStruct, inout PlainEnum) -> Int>.self)) + + expectEqual("_TtGC1a12GenericClassPS_9ProtocolA__", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassPS_9ProtocolAS_9ProtocolB__", + NSStringFromClass(GenericClass>.self)) + expectEqual("_TtGC1a12GenericClassPMPS_9ProtocolAS_9ProtocolB__", + NSStringFromClass(GenericClass.Type>.self)) + expectEqual("_TtGC1a12GenericClassMPS_9ProtocolAS_9ProtocolB__", + NSStringFromClass(GenericClass.Protocol>.self)) + + expectEqual("_TtGC1a12GenericClassCSo7CFArray_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassVSC9NSDecimal_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassCSo8NSObject_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassCSo8NSObject_", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassPSo9NSCopying__", + NSStringFromClass(GenericClass.self)) + expectEqual("_TtGC1a12GenericClassPSo9NSCopyingS_9ProtocolAS_9ProtocolB__", + NSStringFromClass(GenericClass>.self)) + + expectEqual("_TtGC1a17MultiGenericClassGVS_13GenericStructSi_GOS_11GenericEnumGS2_Si___", + NSStringFromClass(MultiGenericClass, + GenericEnum>>.self)) +} + +Runtime.test("typeByName") { + // Make sure we don't crash if we have foreign classes in the + // table -- those don't have NominalTypeDescriptors + print(CFArray.self) + expectTrue(_typeByName("a.SomeClass") == SomeClass.self) + expectTrue(_typeByName("DoesNotExist") == nil) +} + +Runtime.test("casting AnyObject to class metatypes") { + do { + var ao: AnyObject = SomeClass.self + expectTrue(ao as? Any.Type == SomeClass.self) + expectTrue(ao as? AnyClass == SomeClass.self) + expectTrue(ao as? SomeClass.Type == SomeClass.self) + } + + do { + var ao : AnyObject = SomeNSObjectSubclass() + expectTrue(ao as? Any.Type == nil) + expectTrue(ao as? AnyClass == nil) + + ao = SomeNSObjectSubclass.self + expectTrue(ao as? Any.Type == SomeNSObjectSubclass.self) + expectTrue(ao as? AnyClass == SomeNSObjectSubclass.self) + expectTrue(ao as? SomeNSObjectSubclass.Type == SomeNSObjectSubclass.self) + } + + do { + var a : Any = SomeNSObjectSubclass() + expectTrue(a as? Any.Type == nil) + expectTrue(a as? AnyClass == nil) + } + + do { + var nso: NSObject = SomeNSObjectSubclass() + expectTrue(nso as? AnyClass == nil) + + nso = (SomeNSObjectSubclass.self as AnyObject) as! NSObject + expectTrue(nso as? Any.Type == SomeNSObjectSubclass.self) + expectTrue(nso as? AnyClass == SomeNSObjectSubclass.self) + expectTrue(nso as? SomeNSObjectSubclass.Type == SomeNSObjectSubclass.self) + } +} + +var RuntimeFoundationWrappers = TestSuite("RuntimeFoundationWrappers") + +RuntimeFoundationWrappers.test("_stdlib_NSObject_isEqual/NoLeak") { + nsObjectCanaryCount = 0 + autoreleasepool { + let a = NSObjectCanary() + let b = NSObjectCanary() + expectEqual(2, nsObjectCanaryCount) + _stdlib_NSObject_isEqual(a, b) + } + expectEqual(0, nsObjectCanaryCount) +} + +var nsStringCanaryCount = 0 +@objc class NSStringCanary : NSString { + override init() { + nsStringCanaryCount += 1 + super.init() + } + required init(coder: NSCoder) { + fatalError("don't call this initializer") + } + deinit { + nsStringCanaryCount -= 1 + } + @objc override var length: Int { + return 0 + } + @objc override func characterAtIndex(index: Int) -> unichar { + fatalError("out-of-bounds access") + } +} + +RuntimeFoundationWrappers.test( + "_stdlib_compareNSStringDeterministicUnicodeCollation/NoLeak" +) { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + let b = NSStringCanary() + expectEqual(2, nsStringCanaryCount) + _stdlib_compareNSStringDeterministicUnicodeCollation(a, b) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringNFDHashValue/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_NSStringNFDHashValue(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringASCIIHashValue/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_NSStringASCIIHashValue(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringHasPrefixNFD/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + let b = NSStringCanary() + expectEqual(2, nsStringCanaryCount) + _stdlib_NSStringHasPrefixNFD(a, b) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringHasSuffixNFD/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + let b = NSStringCanary() + expectEqual(2, nsStringCanaryCount) + _stdlib_NSStringHasSuffixNFD(a, b) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringLowercaseString/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_NSStringLowercaseString(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_NSStringUppercaseString/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_NSStringUppercaseString(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_CFStringCreateCopy/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_binary_CFStringCreateCopy(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_CFStringGetLength/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_binary_CFStringGetLength(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("_stdlib_CFStringGetCharactersPtr/NoLeak") { + nsStringCanaryCount = 0 + autoreleasepool { + let a = NSStringCanary() + expectEqual(1, nsStringCanaryCount) + _stdlib_binary_CFStringGetCharactersPtr(a) + } + expectEqual(0, nsStringCanaryCount) +} + +RuntimeFoundationWrappers.test("bridgedNSArray") { + var c = [NSObject]() + autoreleasepool { + let a = [NSObject]() + let b = a as NSArray + c = b as! [NSObject] + } + c.append(NSObject()) + // expect no crash. +} + +var Reflection = TestSuite("Reflection") + +class SwiftFooMoreDerivedObjCClass : FooMoreDerivedObjCClass { + let first: Int = 123 + let second: String = "abc" +} + +Reflection.test("Class/ObjectiveCBase/Default") { + do { + let value = SwiftFooMoreDerivedObjCClass() + var output = "" + dump(value, &output) + + let expected = + "▿ This is FooObjCClass #0\n" + + " - super: FooMoreDerivedObjCClass\n" + + " - super: FooDerivedObjCClass\n" + + " - super: FooObjCClass\n" + + " - super: NSObject\n" + + " - first: 123\n" + + " - second: \"abc\"\n" + + expectEqual(expected, output) + } +} +protocol SomeNativeProto {} +@objc protocol SomeObjCProto {} +extension SomeClass: SomeObjCProto {} + +Reflection.test("MetatypeMirror") { + do { + let concreteClassMetatype = SomeClass.self + let expectedSomeClass = "- a.SomeClass #0\n" + let objcProtocolMetatype: SomeObjCProto.Type = SomeClass.self + var output = "" + dump(objcProtocolMetatype, &output) + expectEqual(expectedSomeClass, output) + + let objcProtocolConcreteMetatype = SomeObjCProto.self + let expectedObjCProtocolConcrete = "- a.SomeObjCProto #0\n" + output = "" + dump(objcProtocolConcreteMetatype, &output) + expectEqual(expectedObjCProtocolConcrete, output) + + typealias Composition = protocol + let compositionConcreteMetatype = Composition.self + let expectedComposition = "- protocol #0\n" + output = "" + dump(compositionConcreteMetatype, &output) + expectEqual(expectedComposition, output) + + let objcDefinedProtoType = NSObjectProtocol.self + expectEqual(String(objcDefinedProtoType), "NSObject") + } +} + +Reflection.test("CGPoint") { + var output = "" + dump(CGPoint(x: 1.25, y: 2.75), &output) + + let expected = + "▿ (1.25, 2.75)\n" + + " - x: 1.25\n" + + " - y: 2.75\n" + + expectEqual(expected, output) +} + +Reflection.test("CGSize") { + var output = "" + dump(CGSize(width: 1.25, height: 2.75), &output) + + let expected = + "▿ (1.25, 2.75)\n" + + " - width: 1.25\n" + + " - height: 2.75\n" + + expectEqual(expected, output) +} + +Reflection.test("CGRect") { + var output = "" + dump( + CGRect( + origin: CGPoint(x: 1.25, y: 2.25), + size: CGSize(width: 10.25, height: 11.75)), + &output) + + let expected = + "▿ (1.25, 2.25, 10.25, 11.75)\n" + + " ▿ origin: (1.25, 2.25)\n" + + " - x: 1.25\n" + + " - y: 2.25\n" + + " ▿ size: (10.25, 11.75)\n" + + " - width: 10.25\n" + + " - height: 11.75\n" + + expectEqual(expected, output) +} + +Reflection.test("Unmanaged/nil") { + var output = "" + var optionalURL: Unmanaged? = nil + dump(optionalURL, &output) + + let expected = "- nil\n" + + expectEqual(expected, output) +} + +Reflection.test("Unmanaged/not-nil") { + var output = "" + var optionalURL: Unmanaged? = + Unmanaged.passRetained(CFURLCreateWithString(nil, "http://llvm.org/", nil)) + dump(optionalURL, &output) + + let expected = + "▿ Optional(Swift.Unmanaged<__ObjC.CFURL>(_value: http://llvm.org/))\n" + + " ▿ Some: Swift.Unmanaged<__ObjC.CFURL>\n" + + " - _value: http://llvm.org/ #0\n" + + " - super: NSObject\n" + + expectEqual(expected, output) + + optionalURL!.release() +} + +Reflection.test("TupleMirror/NoLeak") { + do { + nsObjectCanaryCount = 0 + autoreleasepool { + var tuple = (1, NSObjectCanary()) + expectEqual(1, nsObjectCanaryCount) + var output = "" + dump(tuple, &output) + } + expectEqual(0, nsObjectCanaryCount) + } + do { + nsObjectCanaryCount = 0 + autoreleasepool { + var tuple = (1, NSObjectCanaryStruct()) + expectEqual(1, nsObjectCanaryCount) + var output = "" + dump(tuple, &output) + } + expectEqual(0, nsObjectCanaryCount) + } + do { + swiftObjectCanaryCount = 0 + autoreleasepool { + var tuple = (1, SwiftObjectCanary()) + expectEqual(1, swiftObjectCanaryCount) + var output = "" + dump(tuple, &output) + } + expectEqual(0, swiftObjectCanaryCount) + } + do { + swiftObjectCanaryCount = 0 + autoreleasepool { + var tuple = (1, SwiftObjectCanaryStruct()) + expectEqual(1, swiftObjectCanaryCount) + var output = "" + dump(tuple, &output) + } + expectEqual(0, swiftObjectCanaryCount) + } +} + +class TestArtificialSubclass: NSObject { + dynamic var foo = "foo" +} + +var KVOHandle = 0 + +Reflection.test("Name of metatype of artificial subclass") { + let obj = TestArtificialSubclass() + // Trigger the creation of a KVO subclass for TestArtificialSubclass. + obj.addObserver(obj, forKeyPath: "foo", options: [.New], context: &KVOHandle) + obj.removeObserver(obj, forKeyPath: "foo") + + expectEqual("\(obj.dynamicType)", "TestArtificialSubclass") +} + +@objc class StringConvertibleInDebugAndOtherwise : NSObject { + override var description: String { return "description" } + override var debugDescription: String { return "debugDescription" } +} + +Reflection.test("NSObject is properly CustomDebugStringConvertible") { + let object = StringConvertibleInDebugAndOtherwise() + expectEqual(String(reflecting: object), object.debugDescription) +} + +Reflection.test("NSRange QuickLook") { + let rng = NSRange(location:Int.min, length:5) + let ql = PlaygroundQuickLook(reflecting: rng) + switch ql { + case .Range(let loc, let len): + expectEqual(loc, Int64(Int.min)) + expectEqual(len, 5) + default: + expectUnreachable("PlaygroundQuickLook for NSRange did not match Range") + } +} + +class SomeSubclass : SomeClass {} + +var ObjCConformsToProtocolTestSuite = TestSuite("ObjCConformsToProtocol") + +ObjCConformsToProtocolTestSuite.test("cast/instance") { + expectTrue(SomeClass() is SomeObjCProto) + expectTrue(SomeSubclass() is SomeObjCProto) +} + +ObjCConformsToProtocolTestSuite.test("cast/metatype") { + expectTrue(SomeClass.self is SomeObjCProto.Type) + expectTrue(SomeSubclass.self is SomeObjCProto.Type) +} + +runAllTests() diff --git a/test/1_stdlib/SceneKit.swift b/test/1_stdlib/SceneKit.swift index 39431ed3fa6c8..033aa2c6b9b75 100644 --- a/test/1_stdlib/SceneKit.swift +++ b/test/1_stdlib/SceneKit.swift @@ -5,6 +5,15 @@ // UNSUPPORTED: OS=watchos import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + import SceneKit // SceneKit is only available on iOS 8.0 and above and on OS X 10.8 and above. @@ -38,8 +47,8 @@ if #available(iOS 8.0, OSX 10.10, *) { node.position.z = scn_float_from_cg expectTrue(SCNVector3EqualToVector3(node.position, scn_vec3_ref)) - let f1: SCNFloat = scn_vec3_ref.x; - let f2: SCNFloat = scn_vec4_ref.y; + let f1: SCNFloat = scn_vec3_ref.x + let f2: SCNFloat = scn_vec4_ref.y expectEqual(f1, 1.0); expectEqual(f2, 2.0); } diff --git a/test/1_stdlib/SequenceWrapperTest.swift b/test/1_stdlib/SequenceWrapperTest.swift index da18bd8ac1e35..306f8ab0d90da 100644 --- a/test/1_stdlib/SequenceWrapperTest.swift +++ b/test/1_stdlib/SequenceWrapperTest.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -13,6 +13,13 @@ // REQUIRES: executable_test import StdlibUnittest +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + struct BasicSequenceWrapper< Base_: SequenceType > : _SequenceWrapperType, SequenceType { @@ -27,11 +34,11 @@ let indirect = LoggingSequence(direct) let dispatchLog = base.log func expectWrapperDispatch( - @autoclosure directOperation: ()->R1, - @autoclosure _ indirectOperation: ()->R2, + @autoclosure directOperation: () -> R1, + @autoclosure _ indirectOperation: () -> R2, _ counters: TypeIndexed, //===--- TRACE boilerplate ----------------------------------------------===// - @autoclosure _ message: ()->String = "", + @autoclosure _ message: () -> String = "", showFrame: Bool = true, stackTrace: SourceLocStack = SourceLocStack(), file: String = __FILE__, line: UInt = __LINE__ diff --git a/test/1_stdlib/SetTraps.swift b/test/1_stdlib/SetTraps.swift index a9085d67536b0..4df2e4a37d733 100644 --- a/test/1_stdlib/SetTraps.swift +++ b/test/1_stdlib/SetTraps.swift @@ -7,11 +7,7 @@ // RUN: %target-run %t/a.out_Release // REQUIRES: executable_test -// FIXME: rdar://problem/19648117 Needs splitting objc parts out -// XFAIL: linux - import StdlibUnittest -import Foundation // Also import modules which are used by StdlibUnittest internally. This // workaround is needed to link all required libraries in case we compile @@ -21,51 +17,8 @@ import SwiftPrivate import ObjectiveC #endif -struct NotBridgedKeyTy : Equatable, Hashable { - init(_ value: Int) { - self.value = value - } - var hashValue: Int { - return value - } - var value: Int -} - -func == (lhs: NotBridgedKeyTy, rhs: NotBridgedKeyTy) -> Bool { - return lhs.value == rhs.value -} - -assert(!_isBridgedToObjectiveC(NotBridgedKeyTy.self)) - -struct NotBridgedValueTy {} - -assert(!_isBridgedToObjectiveC(NotBridgedValueTy.self)) - -class BridgedVerbatimRefTy : Equatable, Hashable { - init(_ value: Int) { - self.value = value - } - var hashValue: Int { - return value - } - var value: Int -} - -func == (lhs: BridgedVerbatimRefTy, rhs: BridgedVerbatimRefTy) -> Bool { - return lhs.value == rhs.value -} - -assert(_isBridgedToObjectiveC(BridgedVerbatimRefTy.self)) -assert(_isBridgedVerbatimToObjectiveC(BridgedVerbatimRefTy.self)) - var SetTraps = TestSuite("SetTraps") -SetTraps.test("sanity") { - // Sanity checks. This code should not trap. - var s = Set() - var nss = s as NSSet -} - SetTraps.test("RemoveInvalidIndex1") .skip(.Custom( { _isFastAssertConfiguration() }, @@ -124,102 +77,5 @@ SetTraps.test("RemoveFirstFromEmpty") s.removeFirst() } -class TestObjCKeyTy : NSObject { - init(_ value: Int) { - self.value = value - } - - override func isEqual(object: AnyObject!) -> Bool { - if let other = object { - if let otherObjcKey = other as? TestObjCKeyTy { - return self.value == otherObjcKey.value - } - } - return false - } - - override var hash : Int { - return value - } - - var value: Int -} - -struct TestBridgedKeyTy : Hashable, _ObjectiveCBridgeable { - static func _isBridgedToObjectiveC() -> Bool { - return true - } - - init(_ value: Int) { self.value = value } - - var hashValue: Int { return value } - - static func _getObjectiveCType() -> Any.Type { - return TestObjCKeyTy.self - } - - func _bridgeToObjectiveC() -> TestObjCKeyTy { - return TestObjCKeyTy(value) - } - - static func _forceBridgeFromObjectiveC( - x: TestObjCKeyTy, - inout result: TestBridgedKeyTy? - ) { - result = TestBridgedKeyTy(x.value) - } - - static func _conditionallyBridgeFromObjectiveC( - x: TestObjCKeyTy, - inout result: TestBridgedKeyTy? - ) -> Bool { - result = TestBridgedKeyTy(x.value) - return true - } - - var value: Int -} - -func ==(x: TestBridgedKeyTy, y: TestBridgedKeyTy) -> Bool { - return x.value == y.value -} - -SetTraps.test("BridgedKeyIsNotNSCopyable1") { - // This Set is bridged in O(1). - var s: Set = [ TestObjCKeyTy(10) ] - var nss = s as NSSet - - // Unlike NSDictionary, NSSet does not require NSCopying from its element - // type. - let copiedSet = nss.mutableCopy() as! NSMutableSet - expectEqual(10, (copiedSet.anyObject() as! TestObjCKeyTy).value) -} - -SetTraps.test("Downcast1") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let s: Set = [ NSObject(), NSObject() ] - let s2: Set = _setDownCast(s) - expectCrashLater() - let v1 = s2.contains(TestObjCKeyTy(10)) - let v2 = s2.contains(TestObjCKeyTy(20)) - - // This triggers failure. - for m in s2 { } -} - -SetTraps.test("Downcast2") - .skip(.Custom( - { _isFastAssertConfiguration() }, - reason: "this trap is not guaranteed to happen in -Ounchecked")) - .code { - let s: Set = [ TestObjCKeyTy(10), NSObject() ] - expectCrashLater() - let s2: Set = _setBridgeFromObjectiveC(s) - let v1 = s2.contains(TestBridgedKeyTy(10)) -} - runAllTests() diff --git a/test/1_stdlib/SetTrapsObjC.swift b/test/1_stdlib/SetTrapsObjC.swift new file mode 100644 index 0000000000000..12562c35f0229 --- /dev/null +++ b/test/1_stdlib/SetTrapsObjC.swift @@ -0,0 +1,164 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %target-build-swift %s -o %t/a.out_Debug +// RUN: %target-build-swift %s -o %t/a.out_Release -O +// +// RUN: %target-run %t/a.out_Debug +// RUN: %target-run %t/a.out_Release +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import StdlibUnittest +import Foundation + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + +struct NotBridgedKeyTy : Equatable, Hashable { + init(_ value: Int) { + self.value = value + } + var hashValue: Int { + return value + } + var value: Int +} + +func == (lhs: NotBridgedKeyTy, rhs: NotBridgedKeyTy) -> Bool { + return lhs.value == rhs.value +} + +assert(!_isBridgedToObjectiveC(NotBridgedKeyTy.self)) + +struct NotBridgedValueTy {} + +assert(!_isBridgedToObjectiveC(NotBridgedValueTy.self)) + +class BridgedVerbatimRefTy : Equatable, Hashable { + init(_ value: Int) { + self.value = value + } + var hashValue: Int { + return value + } + var value: Int +} + +func == (lhs: BridgedVerbatimRefTy, rhs: BridgedVerbatimRefTy) -> Bool { + return lhs.value == rhs.value +} + +assert(_isBridgedToObjectiveC(BridgedVerbatimRefTy.self)) +assert(_isBridgedVerbatimToObjectiveC(BridgedVerbatimRefTy.self)) + +var SetTraps = TestSuite("SetTraps") + +SetTraps.test("sanity") { + // Sanity checks. This code should not trap. + var s = Set() + var nss = s as NSSet +} + +class TestObjCKeyTy : NSObject { + init(_ value: Int) { + self.value = value + } + + override func isEqual(object: AnyObject!) -> Bool { + if let other = object { + if let otherObjcKey = other as? TestObjCKeyTy { + return self.value == otherObjcKey.value + } + } + return false + } + + override var hash : Int { + return value + } + + var value: Int +} + +struct TestBridgedKeyTy : Hashable, _ObjectiveCBridgeable { + static func _isBridgedToObjectiveC() -> Bool { + return true + } + + init(_ value: Int) { self.value = value } + + var hashValue: Int { return value } + + static func _getObjectiveCType() -> Any.Type { + return TestObjCKeyTy.self + } + + func _bridgeToObjectiveC() -> TestObjCKeyTy { + return TestObjCKeyTy(value) + } + + static func _forceBridgeFromObjectiveC( + x: TestObjCKeyTy, + inout result: TestBridgedKeyTy? + ) { + result = TestBridgedKeyTy(x.value) + } + + static func _conditionallyBridgeFromObjectiveC( + x: TestObjCKeyTy, + inout result: TestBridgedKeyTy? + ) -> Bool { + result = TestBridgedKeyTy(x.value) + return true + } + + var value: Int +} + +func ==(x: TestBridgedKeyTy, y: TestBridgedKeyTy) -> Bool { + return x.value == y.value +} + +SetTraps.test("BridgedKeyIsNotNSCopyable1") { + // This Set is bridged in O(1). + var s: Set = [ TestObjCKeyTy(10) ] + var nss = s as NSSet + + // Unlike NSDictionary, NSSet does not require NSCopying from its element + // type. + let copiedSet = nss.mutableCopy() as! NSMutableSet + expectEqual(10, (copiedSet.anyObject() as! TestObjCKeyTy).value) +} + +SetTraps.test("Downcast1") + .skip(.Custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .code { + let s: Set = [ NSObject(), NSObject() ] + let s2: Set = _setDownCast(s) + expectCrashLater() + let v1 = s2.contains(TestObjCKeyTy(10)) + let v2 = s2.contains(TestObjCKeyTy(20)) + + // This triggers failure. + for m in s2 { } +} + +SetTraps.test("Downcast2") + .skip(.Custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .code { + let s: Set = [ TestObjCKeyTy(10), NSObject() ] + expectCrashLater() + let s2: Set = _setBridgeFromObjectiveC(s) + let v1 = s2.contains(TestBridgedKeyTy(10)) +} + +runAllTests() diff --git a/test/1_stdlib/SpriteKit.swift b/test/1_stdlib/SpriteKit.swift index 2d2491abcfdf0..eb579f37b0504 100644 --- a/test/1_stdlib/SpriteKit.swift +++ b/test/1_stdlib/SpriteKit.swift @@ -9,6 +9,15 @@ import Foundation import SpriteKit +// Check that the subscript is there. +@available(OSX,introduced=10.10) +@available(iOS,introduced=8.0) +@available(tvOS,introduced=8.0) +@available(watchOS,introduced=2.0) +func testSubscript(node: SKNode) { + var nodes: [SKNode] = node["me"] +} + // SKColor is NSColor on OS X and UIColor on iOS. var r = CGFloat(0) diff --git a/test/1_stdlib/Strideable.swift b/test/1_stdlib/Strideable.swift index d580c55d92a12..c8b5badcdc731 100644 --- a/test/1_stdlib/Strideable.swift +++ b/test/1_stdlib/Strideable.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/StringDiagnostics.swift b/test/1_stdlib/StringDiagnostics.swift index ce4c978874f39..5a600e00dc54f 100644 --- a/test/1_stdlib/StringDiagnostics.swift +++ b/test/1_stdlib/StringDiagnostics.swift @@ -46,7 +46,7 @@ func testAmbiguousStringComparisons(s: String) { func acceptsSequence(sequence: S) {} func testStringIsNotASequence(s: String) { - acceptsSequence(s) // expected-error {{cannot invoke 'acceptsSequence' with an argument list of type '(String)'}} expected-note {{expected an argument list of type '(S)'}} + acceptsSequence(s) // expected-error {{argument type 'String' does not conform to expected type 'SequenceType'}} } func testStringDeprecation(hello: String) { diff --git a/test/1_stdlib/StringOrderRelation.swift b/test/1_stdlib/StringOrderRelation.swift new file mode 100644 index 0000000000000..00c39168373ff --- /dev/null +++ b/test/1_stdlib/StringOrderRelation.swift @@ -0,0 +1,31 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + +var StringOrderRelationTestSuite = TestSuite("StringOrderRelation") + +StringOrderRelationTestSuite.test("StringOrderRelation/ASCII/NullByte") + .xfail(.LinuxAny(reason: "String comparison: ICU vs. Foundation")) + .xfail(.FreeBSDAny(reason: "String comparison: ICU vs. Foundation")) + .code { + let baseString = "a" + let nullbyteString = "a\0" + expectTrue(baseString < nullbyteString) + expectTrue(baseString <= nullbyteString) + expectFalse(baseString > nullbyteString) + expectFalse(baseString >= nullbyteString) + expectFalse(baseString == nullbyteString) + expectTrue(baseString != nullbyteString) +} + +runAllTests() + diff --git a/test/1_stdlib/StringTraps.swift b/test/1_stdlib/StringTraps.swift index 304f0cac5f623..3fb0f04cfc974 100644 --- a/test/1_stdlib/StringTraps.swift +++ b/test/1_stdlib/StringTraps.swift @@ -7,10 +7,7 @@ // RUN: %target-run %t/a.out_Release // REQUIRES: executable_test -// XFAIL: linux - import StdlibUnittest -import Foundation // Also import modules which are used by StdlibUnittest internally. This // workaround is needed to link all required libraries in case we compile @@ -29,10 +26,10 @@ StringTraps.test("startIndex/predecessor") .code { var s = "abc" var i = s.startIndex - ++i - --i + i = i.successor() + i = i.predecessor() expectCrashLater() - --i + i = i.predecessor() } StringTraps.test("endIndex/successor") @@ -42,11 +39,11 @@ StringTraps.test("endIndex/successor") .code { var s = "abc" var i = s.startIndex - ++i - ++i - ++i + i = i.successor() + i = i.successor() + i = i.successor() expectCrashLater() - ++i + i = i.successor() } StringTraps.test("subscript(_:)/endIndex") @@ -56,9 +53,9 @@ StringTraps.test("subscript(_:)/endIndex") .code { var s = "abc" var i = s.startIndex - ++i - ++i - ++i + i = i.successor() + i = i.successor() + i = i.successor() expectCrashLater() s[i] } @@ -70,11 +67,11 @@ StringTraps.test("UTF8ViewEndIndexSuccessor") .code { var s = "abc" var i = s.utf8.startIndex - ++i - ++i - ++i + i = i.successor() + i = i.successor() + i = i.successor() expectCrashLater() - ++i + i = i.successor() } StringTraps.test("UTF8ViewSubscript/endIndex") @@ -84,9 +81,9 @@ StringTraps.test("UTF8ViewSubscript/endIndex") .code { var s = "abc" var i = s.utf8.startIndex - ++i - ++i - ++i + i = i.successor() + i = i.successor() + i = i.successor() expectCrashLater() s.utf8[i] } @@ -98,7 +95,7 @@ StringTraps.test("UTF16ViewSubscript/DecrementedStartIndex") .code { var s = "abc" var i = s.utf16.startIndex - --i + i = i.predecessor() expectCrashLater() s.utf16[i] } @@ -110,9 +107,9 @@ StringTraps.test("UTF16ViewSubscript/endIndex") .code { var s = "abc" var i = s.utf16.startIndex - ++i - ++i - ++i + i = i.successor() + i = i.successor() + i = i.successor() expectCrashLater() s.utf16[i] } diff --git a/test/1_stdlib/SwiftObjectNSObject.swift b/test/1_stdlib/SwiftObjectNSObject.swift index 61ecfa232807f..380a691fa59ba 100644 --- a/test/1_stdlib/SwiftObjectNSObject.swift +++ b/test/1_stdlib/SwiftObjectNSObject.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information diff --git a/test/1_stdlib/Tuple.swift.gyb b/test/1_stdlib/Tuple.swift.gyb new file mode 100644 index 0000000000000..3429ef0cd9d0f --- /dev/null +++ b/test/1_stdlib/Tuple.swift.gyb @@ -0,0 +1,161 @@ +// RUN: rm -f %t.swift %t.out + +// RUN: %S/../../utils/gyb %s -o %t.swift +// RUN: %S/../../utils/line-directive %t.swift -- %target-build-swift %t.swift -o %t.out +// RUN: %S/../../utils/line-directive %t.swift -- %target-run %t.out +// REQUIRES: executable_test + +import StdlibUnittest + +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +#if _runtime(_ObjC) +import ObjectiveC +#endif + +var TupleTestSuite = TestSuite("Tuple") + +// Test tuple comparison operators +// all the tuple types use the same basic implementation for the operators +// so testing any arity tests the logic for them all. +// Include at least one invocation for all arities as a sanity check. + +% maxArity = 6 # the highest arity the operators are defined for + +func testEquality( + lhs: (A,B,C), equal: Bool, to rhs: (A,B,C), + //===--- TRACE boilerplate ----------------------------------------------===// + @autoclosure _ message: ()->String = "", + showFrame: Bool = true, + stackTrace: SourceLocStack = SourceLocStack(), + file: String = __FILE__, line: UInt = __LINE__ +) { + let trace = stackTrace.pushIf(showFrame, file: file, line: line) + expectEqual(equal, lhs == rhs, stackTrace: trace) + expectEqual(equal, rhs == lhs, stackTrace: trace) + expectEqual(!equal, lhs != rhs, stackTrace: trace) + expectEqual(!equal, rhs != lhs, stackTrace: trace) +} + +TupleTestSuite.test("Tuple/equality") { + testEquality((1,2,3), equal: true, to: (1,2,3)) + testEquality((1,2,3), equal: false, to: (1,2,4)) + testEquality((1,2,3), equal: false, to: (1,3,3)) + testEquality((1,2,3), equal: false, to: (2,2,3)) + testEquality((1,"2",3), equal: true, to: (1,"2",3)) + testEquality((1,"2",3), equal: false, to: (1,"3",3)) + testEquality(("one", 2.2, 3..<5), equal: true, to: ("one", 2.2, 3..<5)) + + testEquality((1.0, 2.0, 3.0), equal: false, to: (1.0, 2.0, .NaN)) + testEquality((1.0, 2.0, 3.0), equal: false, to: (1.0, .NaN, 3.0)) + testEquality((1.0, 2.0, 3.0), equal: false, to: (.NaN, 2.0, 3.0)) + testEquality((1.0, 2.0, 3.0), equal: false, to: (.NaN, .NaN, .NaN)) + testEquality((1.0, 2.0, Float.NaN), equal: false, to: (1.0, 2.0, 3.0)) + testEquality((1.0, 2.0, Float.NaN), equal: false, to: (1.0, 2.0, Float.NaN)) + testEquality((Float.NaN, Float.NaN, Float.NaN), equal: false, to: (.NaN, .NaN, .NaN)) + testEquality((Float.NaN, Float.NaN, Float.NaN), equal: false, to: (1.0, 2.0, 3.0)) + + expectTrue((1,2) == (1,2)) + expectTrue((1,2) != (1,3)) + expectTrue((1,2,3,4) == (1,2,3,4)) + expectTrue((1,2,3,4) != (1,2,3,3)) + expectTrue((1,2,3,4,5) == (1,2,3,4,5)) + expectTrue((1,2,3,4,5) != (1,2,3,4,4)) + expectTrue((1,2,3,4,5,6) == (1,2,3,4,5,6)) + expectTrue((1,2,3,4,5,6) != (1,2,3,4,5,5)) +} + +TupleTestSuite.test("Tuple/equality/sanity-check") { + // sanity check all arities +% for arity in range(2, maxArity + 1): +% a = str(tuple(range(1, arity + 1))) +% b = "({}, 0)".format(", ".join([str(i) for i in range(1, arity)])) +% c = "(0, {})".format(", ".join([str(i) for i in range(2, arity + 1)])) + expectTrue(${a} == ${a}) + expectTrue(${a} != ${b}) + expectTrue(${b} != ${a}) + expectTrue(${a} != ${c}) + expectTrue(${c} != ${a}) +% end +} + +enum Ordering : Equatable { + case LessThan + case EqualTo + case GreaterThan + case UnorderedWith // Comparable defines strict total order, but Float disobeys that with NaN + + var isLT: Bool { + return self == .LessThan + } + var isEQ: Bool { + return self == .EqualTo + } + var isGT: Bool { + return self == .GreaterThan + } +} + +func testOrdering( + lhs: (A,B,C), _ ordering: Ordering, _ rhs: (A, B, C), + //===--- TRACE boilerplate ----------------------------------------------===// + @autoclosure _ message: ()->String = "", + showFrame: Bool = true, + stackTrace: SourceLocStack = SourceLocStack(), + file: String = __FILE__, line: UInt = __LINE__ +) { + let trace = stackTrace.pushIf(showFrame, file: file, line: line) + expectEqual(ordering.isLT, lhs < rhs, stackTrace: trace) + expectEqual(ordering.isLT, rhs > lhs, stackTrace: trace) + expectEqual(ordering.isLT || ordering.isEQ, lhs <= rhs, stackTrace: trace) + expectEqual(ordering.isLT || ordering.isEQ, rhs >= lhs, stackTrace: trace) + expectEqual(ordering.isGT, lhs > rhs, stackTrace: trace) + expectEqual(ordering.isGT, rhs < lhs, stackTrace: trace) + expectEqual(ordering.isGT || ordering.isEQ, lhs >= rhs, stackTrace: trace) + expectEqual(ordering.isGT || ordering.isEQ, rhs <= lhs, stackTrace: trace) +} + +TupleTestSuite.test("Tuple/comparison") { + testOrdering((1,2,3), .EqualTo, (1,2,3)) + testOrdering((1,2,3), .LessThan, (1,2,4)) + testOrdering((1,2,3), .GreaterThan, (1,2,2)) + testOrdering((1,3,2), .GreaterThan, (1,2,3)) + testOrdering((0,2,3), .LessThan, (1,2,3)) + testOrdering((3,2,1), .GreaterThan, (1,2,3)) + + testOrdering(("one", 2, 3.3), .EqualTo, ("one", 2, 3.3)) + testOrdering(("one", 2, 3.3), .LessThan, ("one", 2, 3.4)) + testOrdering(("on", 2, 3.3), .LessThan, ("one", 1, 3.2)) + + testOrdering((1, 2, Float.NaN), .UnorderedWith, (1, 2, .NaN)) + testOrdering((1, Float.NaN, 3), .UnorderedWith, (1, 2, 3)) + testOrdering((Double.NaN, 2, 3), .UnorderedWith, (.NaN, 2, 3)) + testOrdering((Float.NaN, Float.NaN, Float.NaN), .UnorderedWith, (1, 2, 3)) + testOrdering((1, 2, 3.0), .UnorderedWith, (1, 2, .NaN)) + testOrdering((1, 2, 3.0), .LessThan, (1, 3, .NaN)) + testOrdering((1, 2, 3.0), .GreaterThan, (1, 1, .NaN)) + testOrdering((1, 2.0, 3), .LessThan, (2, .NaN, 3)) + testOrdering((1, 2.0, 3), .GreaterThan, (0, .NaN, 3)) + testOrdering((1, 2, Float.NaN), .LessThan, (1, 3, 3.0)) + testOrdering((1, Float.NaN, 3), .GreaterThan, (0, 2.0, 3)) + testOrdering(("one", "two", 3.0), .GreaterThan, ("a", "b", .NaN)) + testOrdering(("one", "two", .NaN), .GreaterThan, ("a", "b", 3.0)) + testOrdering((1.0, "two", "three"), .UnorderedWith, (.NaN, "two", "four")) + testOrdering((.NaN, "two", "three"), .UnorderedWith, (1.0, "two", "four")) +} + +TupleTestSuite.test("Tuple/comparison/sanity-check") { + // sanity check all arities +% for arity in range(2, maxArity + 1): +% a = str(tuple(range(1, arity + 1))) +% b = "({}, 0)".format(", ".join([str(i) for i in range(1, arity)])) +% c = "(0, {})".format(", ".join([str(i) for i in range(2, arity + 1)])) + expectTrue(${b} < ${a}) + expectTrue(${b} <= ${a}) + expectTrue(${a} > ${c}) + expectTrue(${a} >= ${c}) +% end +} + +runAllTests() diff --git a/test/1_stdlib/Unicode.swift b/test/1_stdlib/Unicode.swift index 23ab35ffed72a..c1863dde90aab 100644 --- a/test/1_stdlib/Unicode.swift +++ b/test/1_stdlib/Unicode.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information @@ -15,6 +15,14 @@ import Swift import StdlibUnittest +// Also import modules which are used by StdlibUnittest internally. This +// workaround is needed to link all required libraries in case we compile +// StdlibUnittest with -sil-serialize-all. +import SwiftPrivate +#if _runtime(_ObjC) +import ObjectiveC +#endif + var UnicodeInternals = TestSuite("UnicodeInternals") UnicodeInternals.test("copy") { @@ -22,11 +30,11 @@ UnicodeInternals.test("copy") { var u16: [UTF16.CodeUnit] = [ 6, 7, 8, 9, 10, 11 ] u16.withUnsafeMutableBufferPointer { - (u16)->() in + (u16) -> () in let p16 = u16.baseAddress u8.withUnsafeMutableBufferPointer { - (u8)->() in + (u8) -> () in let p8 = u8.baseAddress UTF16._copy(p8, destination: p16, count: 3) @@ -44,3 +52,4 @@ UnicodeInternals.test("copy") { } } +runAllTests() diff --git a/test/1_stdlib/UnsafePointer.swift.gyb b/test/1_stdlib/UnsafePointer.swift.gyb index 8d685d1ea113a..decbbb4315b2b 100644 --- a/test/1_stdlib/UnsafePointer.swift.gyb +++ b/test/1_stdlib/UnsafePointer.swift.gyb @@ -60,9 +60,9 @@ var UnsafeMutablePointerTestSuite = TestSuite("UnsafeMutablePointer") var COpaquePointerTestSuite = TestSuite("COpaquePointer") % for (SelfName, SelfType) in [ -% ( 'UnsafePointer', 'UnsafePointer' ), -% ( 'UnsafeMutablePointer', 'UnsafeMutablePointer'), -% ( 'COpaquePointer', 'COpaquePointer' ) ]: +% ('UnsafePointer', 'UnsafePointer'), +% ('UnsafeMutablePointer', 'UnsafeMutablePointer'), +% ('COpaquePointer', 'COpaquePointer')]: ${SelfName}TestSuite.test("convertFromNil") { let ptr: ${SelfType} = nil @@ -132,7 +132,7 @@ class Missile { static var missilesLaunched = 0 let number: Int init(_ number: Int) { self.number = number } - deinit { Missile.missilesLaunched++ } + deinit { Missile.missilesLaunched += 1 } } func checkPointerCorrectness(check: Check, @@ -270,5 +270,70 @@ UnsafeMutablePointerTestSuite.test("initializeFrom.Right") { } } +UnsafePointerTestSuite.test("customMirror") { + // Ensure that the custom mirror works properly, including when the raw value + // is greater than Int.max + let reallyBigInt: UInt = UInt(Int.max) + 1 + let ptr = UnsafePointer(bitPattern: reallyBigInt) + let mirror = ptr.customMirror() + expectEqual(1, mirror.children.count) +#if arch(i386) || arch(arm) + expectEqual("18446744071562067968", String(mirror.children.first!.1)) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) + expectEqual("9223372036854775808", String(mirror.children.first!.1)) +#else + fatalError("Unimplemented") +#endif +} + +UnsafePointerTestSuite.test("customPlaygroundQuickLook") { + // Ensure that the custom playground quicklook works properly, including when + // the raw value is greater than Int.max + let reallyBigInt: UInt = UInt(Int.max) + 1 + let ptr = UnsafePointer(bitPattern: reallyBigInt) + if case let .Text(desc) = ptr.customPlaygroundQuickLook() { +#if arch(i386) || arch(arm) + expectEqual("UnsafePointer(0xFFFFFFFF80000000)", desc) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) + expectEqual("UnsafePointer(0x8000000000000000)", desc) +#else + fatalError("Unimplemented") +#endif + } else { + expectTrue(false) + } +} + +UnsafeMutablePointerTestSuite.test("customMirror") { + let reallyBigInt: UInt = UInt(Int.max) + 1 + let ptr = UnsafeMutablePointer(bitPattern: reallyBigInt) + let mirror = ptr.customMirror() + expectEqual(1, mirror.children.count) +#if arch(i386) || arch(arm) + expectEqual("18446744071562067968", String(mirror.children.first!.1)) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) + expectEqual("9223372036854775808", String(mirror.children.first!.1)) +#else + fatalError("Unimplemented") +#endif +} + +UnsafeMutablePointerTestSuite.test("customPlaygroundQuickLook") { + let reallyBigInt: UInt = UInt(Int.max) + 1 + let ptr = UnsafeMutablePointer(bitPattern: reallyBigInt) + let isProperDisposition : Bool + if case let .Text(desc) = ptr.customPlaygroundQuickLook() { +#if arch(i386) || arch(arm) + expectEqual("UnsafeMutablePointer(0xFFFFFFFF80000000)", desc) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) + expectEqual("UnsafeMutablePointer(0x8000000000000000)", desc) +#else + fatalError("Unimplemented") +#endif + } else { + expectTrue(false) + } +} + runAllTests() diff --git a/test/BuildConfigurations/basicDeclarations.swift b/test/BuildConfigurations/basicDeclarations.swift index 1ebef409fa0c3..0bbe0c0436944 100644 --- a/test/BuildConfigurations/basicDeclarations.swift +++ b/test/BuildConfigurations/basicDeclarations.swift @@ -3,7 +3,7 @@ class A {} #if FOO -typealias A1 = A; +typealias A1 = A #endif var a: A = A() var a1: A1 = A1() // should not result in an error @@ -16,14 +16,14 @@ var c = C() // should not result in an error class D { #if FOO - var x: Int; + var x: Int #endif init() { #if !BAR x = "BAR"; // should not result in an error #else - x = 1; + x = 1 #endif } } @@ -48,13 +48,13 @@ var i: Int = f1() protocol P1 { #if FOO - func fFOO() -> Int; + func fFOO() -> Int #endif #if !BAR - func fNotBAR() -> Int; + func fNotBAR() -> Int #else - func fBAR() -> Int; + func fBAR() -> Int #endif } diff --git a/test/BuildConfigurations/basicParseErrors.swift b/test/BuildConfigurations/basicParseErrors.swift index 286bee275d106..56b06df37d263 100644 --- a/test/BuildConfigurations/basicParseErrors.swift +++ b/test/BuildConfigurations/basicParseErrors.swift @@ -8,7 +8,7 @@ var x = 0 var y = 0 #endif -#if swift(FOO) // expected-error {{unexpected target configuration expression (expected 'os' or 'arch')}} +#if foo(BAR) // expected-error {{unexpected target configuration expression (expected 'os', 'arch', or 'swift')}} var z = 0 #endif @@ -28,7 +28,7 @@ func h() {} #endif /* bbb */ #if foo.bar() - .baz() // expected-error {{unexpected target configuration expression (expected 'os' or 'arch')}} + .baz() // expected-error {{unexpected target configuration expression (expected 'os', 'arch', or 'swift')}} #endif diff --git a/test/BuildConfigurations/compiler_version.swift b/test/BuildConfigurations/compiler_version.swift new file mode 100644 index 0000000000000..02127bbfb4739 --- /dev/null +++ b/test/BuildConfigurations/compiler_version.swift @@ -0,0 +1,67 @@ +// RUN: %target-parse-verify-swift + +#if _compiler_version("999.*.999.999.999") + let w = 1 +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + +#if _compiler_version("10.*.10.10") + +#if os(iOS) + let z = 1 +#else + let z = 1 +#endif + +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#if os(iOS) + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + +#if !_compiler_version("777.*.7") + // This shouldn't emit any diagnostics. + $#%^*& +#endif + +#if _compiler_version("700a.*.10") // expected-error {{version component contains non-numeric characters}} +#endif + +#if _compiler_version("...") // expected-error {{found empty version component}} +// expected-error@-1 {{found empty version component}} +// expected-error@-2 {{found empty version component}} +#endif + +#if _compiler_version("") // expected-error {{version requirement is empty}} + let y = 1 +#else + let thisWillStillParseBecauseConfigIsError = 1 +#endif + +#if _compiler_version("700.0.100") // expected-warning {{the second version component is not used for comparison}} +#endif + +#if _compiler_version("700.*.1.1.1.1") // expected-error {{version must not have more than five components}} +#endif + +#if _compiler_version("9223372.*.1.1.1") // expected-error {{version component out of range: must be in [0, 9223371]}} +#endif + +#if _compiler_version("700.*.1000.1.1") // expected-error {{version component out of range: must be in [0, 999]}} +#endif + +#if _compiler_version("700.*.1.1000.1") // expected-error {{version component out of range: must be in [0, 999]}} +#endif + +#if _compiler_version("700.*.1.1.1000") // expected-error {{version component out of range: must be in [0, 999]}} +#endif diff --git a/test/BuildConfigurations/language_version.swift b/test/BuildConfigurations/language_version.swift new file mode 100644 index 0000000000000..36d04ec4d04da --- /dev/null +++ b/test/BuildConfigurations/language_version.swift @@ -0,0 +1,54 @@ +// RUN: %target-parse-verify-swift + +#if swift(>=1.0) + let w = 1 +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + +#if swift(>=1.2) + +#if os(iOS) + let z = 1 +#else + let z = 1 +#endif + +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#if os(iOS) + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#else + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + +#if !swift(>=1.0) + // This shouldn't emit any diagnostics. + $#%^*& +#endif + +#if swift(">=7.1") // expected-error {{unexpected target configuration argument: expected a unary comparison, such as '>=2.2'}} +#endif + +#if swift(">=2n.2") // expected-error {{unexpected target configuration argument: expected a unary comparison, such as '>=2.2'}} +#endif + +#if swift("") // expected-error {{unexpected target configuration argument: expected a unary comparison, such as '>=2.2'}} +#endif + +// We won't expect three version components to work for now. +#if swift(>=2.2.1) // expected-error {{expected named member of numeric literal}} +#endif + +#if swift(>=2.0, *) // expected-error {{expected only one argument to target configuration expression}} +#endif + +#if swift(>=, 2.0) // expected-error {{expected only one argument to target configuration expression}} +#endif diff --git a/test/BuildConfigurations/module_top_level.swift b/test/BuildConfigurations/module_top_level.swift index 6ccdd61a5aa5d..1f206431a06c9 100644 --- a/test/BuildConfigurations/module_top_level.swift +++ b/test/BuildConfigurations/module_top_level.swift @@ -4,6 +4,6 @@ class C {} func > (lhs: C, rhs: C) -> Bool { - return false; + return false } #endif diff --git a/test/BuildConfigurations/pound-if-inside-function-4.swift b/test/BuildConfigurations/pound-if-inside-function-4.swift index fe648ad4b8de7..f2a77d4d853bc 100644 --- a/test/BuildConfigurations/pound-if-inside-function-4.swift +++ b/test/BuildConfigurations/pound-if-inside-function-4.swift @@ -5,7 +5,7 @@ func foo() { // expected-note {{to match this opening '{'}} #if BLAH - _ = 123; + _ = 123 #elseif !BLAH #else #else // expected-error{{further conditions after #else are unreachable}} diff --git a/test/BuildConfigurations/pound-if-top-level-3.swift b/test/BuildConfigurations/pound-if-top-level-3.swift index 9d66539e3d830..86f21c83ae3af 100644 --- a/test/BuildConfigurations/pound-if-top-level-3.swift +++ b/test/BuildConfigurations/pound-if-top-level-3.swift @@ -1,6 +1,5 @@ // RUN: %target-parse-verify-swift -// e xpected-error@+1{{unexpected configuration expression type}} #if arch(x86_64) // expected-error@+2{{expected '{' in protocol type}} // expected-error@+1{{expected #else or #endif at end of configuration block}} diff --git a/test/BuildConfigurations/powerpc64LinuxTarget.swift b/test/BuildConfigurations/powerpc64LinuxTarget.swift new file mode 100644 index 0000000000000..186766473e2cc --- /dev/null +++ b/test/BuildConfigurations/powerpc64LinuxTarget.swift @@ -0,0 +1,8 @@ +// RUN: %swift -parse %s -verify -D FOO -D BAR -target powerpc64-unknown-linux-gnu -disable-objc-interop -D FOO -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target powerpc64-unknown-linux-gnu + +#if arch(powerpc64) && os(Linux) && _runtime(_Native) +class C {} +var x = C() +#endif +var y = x diff --git a/test/BuildConfigurations/powerpc64leLinuxTarget.swift b/test/BuildConfigurations/powerpc64leLinuxTarget.swift new file mode 100644 index 0000000000000..586972fa83706 --- /dev/null +++ b/test/BuildConfigurations/powerpc64leLinuxTarget.swift @@ -0,0 +1,8 @@ +// RUN: %swift -parse %s -verify -D FOO -D BAR -target powerpc64le-unknown-linux-gnu -disable-objc-interop -D FOO -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target powerpc64le-unknown-linux-gnu + +#if arch(powerpc64le) && os(Linux) && _runtime(_Native) +class C {} +var x = C() +#endif +var y = x diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dff17a08b7fc6..019523540c9d0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -173,7 +173,10 @@ if(PYTHONINTERP_FOUND) set(test_dependencies) get_test_dependencies("${SDK}" test_dependencies) list(APPEND test_dependencies - "swift-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") + "swift-test-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") + + set(validation_test_dependencies + "swiftStdlibCollectionUnittest-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") set(test_bin_dir "${CMAKE_CURRENT_BINARY_DIR}${VARIANT_SUFFIX}") set(validation_test_bin_dir @@ -206,7 +209,7 @@ if(PYTHONINTERP_FOUND) ${command_upload_stdlib} ${command_clean_test_results_dir} COMMAND ${lit_command} "${validation_test_bin_dir}" - DEPENDS ${test_dependencies} + DEPENDS ${test_dependencies} ${validation_test_dependencies} COMMENT "Running Swift validation tests for ${VARIANT_TRIPLE}" ${cmake_3_2_USES_TERMINAL}) @@ -214,7 +217,7 @@ if(PYTHONINTERP_FOUND) ${command_upload_stdlib} ${command_clean_test_results_dir} COMMAND ${lit_command} "${validation_test_bin_dir}" "${test_bin_dir}" - DEPENDS ${test_dependencies} + DEPENDS ${test_dependencies} ${validation_test_dependencies} COMMENT "Running all Swift tests for ${VARIANT_TRIPLE}" ${cmake_3_2_USES_TERMINAL}) endforeach() diff --git a/test/ClangModules/Inputs/SwiftPrivateAttr.txt b/test/ClangModules/Inputs/SwiftPrivateAttr.txt index 06331fbd4c4c4..53c5cbadebf7b 100644 --- a/test/ClangModules/Inputs/SwiftPrivateAttr.txt +++ b/test/ClangModules/Inputs/SwiftPrivateAttr.txt @@ -95,5 +95,8 @@ struct NSOptions : OptionSetType { static var B: NSOptions { get } } typealias __PrivCFTypeRef = __PrivCFType +class __PrivCFType { +} typealias __PrivCFSubRef = __PrivCFSub +typealias __PrivCFSub = __PrivCFTypeRef typealias __PrivInt = Int32 diff --git a/test/ClangModules/Inputs/custom-modules/CFAndObjC.h b/test/ClangModules/Inputs/custom-modules/CFAndObjC.h new file mode 100644 index 0000000000000..fe8bb45b07539 --- /dev/null +++ b/test/ClangModules/Inputs/custom-modules/CFAndObjC.h @@ -0,0 +1,7 @@ +typedef const struct __attribute__((objc_bridge(id))) __MyProblematicObject *MyProblematicObjectRef; + +@interface MyProblematicObject +@end + +typedef float MyProblematicAlias; +typedef MyProblematicObjectRef MyProblematicAliasRef; diff --git a/test/ClangModules/Inputs/custom-modules/MacrosRedefA.h b/test/ClangModules/Inputs/custom-modules/MacrosRedefA.h new file mode 100644 index 0000000000000..f6e75f0410d87 --- /dev/null +++ b/test/ClangModules/Inputs/custom-modules/MacrosRedefA.h @@ -0,0 +1,2 @@ +#define REDEF_1 "hello" +#define REDEF_2 "world" diff --git a/test/ClangModules/Inputs/custom-modules/MacrosRedefB.h b/test/ClangModules/Inputs/custom-modules/MacrosRedefB.h new file mode 100644 index 0000000000000..9b3eaa886687b --- /dev/null +++ b/test/ClangModules/Inputs/custom-modules/MacrosRedefB.h @@ -0,0 +1,2 @@ +#define REDEF_1 "hello" +#define REDEF_2 "Swift" diff --git a/test/ClangModules/Inputs/custom-modules/SwiftName.h b/test/ClangModules/Inputs/custom-modules/SwiftName.h index aaa2353381c6e..cf98fe59a59c1 100644 --- a/test/ClangModules/Inputs/custom-modules/SwiftName.h +++ b/test/ClangModules/Inputs/custom-modules/SwiftName.h @@ -8,7 +8,7 @@ enum SWIFT_NAME(ColorKind) ColorType { CT_blue, }; -typedef struct { +typedef struct SWIFT_NAME(Point) { int X SWIFT_NAME(x); int Y SWIFT_NAME(y); } PointType; diff --git a/test/ClangModules/Inputs/custom-modules/module.map b/test/ClangModules/Inputs/custom-modules/module.map index fd50090b15466..23a7d22ca6dfc 100644 --- a/test/ClangModules/Inputs/custom-modules/module.map +++ b/test/ClangModules/Inputs/custom-modules/module.map @@ -7,6 +7,11 @@ module AvailabilityExtras { export * } +module CFAndObjC { + header "CFAndObjC.h" + export * +} + module ClangModuleUser { header "ClangModuleUser.h" export * @@ -128,3 +133,11 @@ module Requires { module SwiftName { header "SwiftName.h" } + +module MacrosRedefA { + header "MacrosRedefA.h" +} + +module MacrosRedefB { + header "MacrosRedefB.h" +} diff --git a/test/ClangModules/Inputs/enum-objc.h b/test/ClangModules/Inputs/enum-objc.h new file mode 100644 index 0000000000000..3b9df46d6207e --- /dev/null +++ b/test/ClangModules/Inputs/enum-objc.h @@ -0,0 +1,10 @@ +@import Foundation; + +#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type + +typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") { + ObjCEnumOne = 1, + ObjCEnumTwo, + ObjCEnumThree +}; diff --git a/test/ClangModules/MixedSource/Inputs/mixed-target/header.h b/test/ClangModules/MixedSource/Inputs/mixed-target/header.h index e97103f97284b..e8664db286412 100644 --- a/test/ClangModules/MixedSource/Inputs/mixed-target/header.h +++ b/test/ClangModules/MixedSource/Inputs/mixed-target/header.h @@ -48,3 +48,12 @@ typedef NS_ENUM(short, AALevel) { BBB = 2 }; + +@interface ConflictingName1 +@end +@protocol ConflictingName1 +@end +@protocol ConflictingName2 +@end +@interface ConflictingName2 +@end diff --git a/test/ClangModules/MixedSource/Inputs/resolve-cross-language/Base.swift b/test/ClangModules/MixedSource/Inputs/resolve-cross-language/Base.swift index 3d05a94f0d775..2b4bade79dff9 100644 --- a/test/ClangModules/MixedSource/Inputs/resolve-cross-language/Base.swift +++ b/test/ClangModules/MixedSource/Inputs/resolve-cross-language/Base.swift @@ -21,7 +21,14 @@ extension BaseClass { case Zung } +@objc(RenamedEnum) public enum SwiftEnum: CShort { + case Quux + case Corge + case Grault +} + @objc public class AnotherClass { @objc public func getEnum() -> BaseEnum { return .Zung } + @objc public func getSwiftEnum() -> SwiftEnum { return .Quux } public init() {} } diff --git a/test/ClangModules/MixedSource/Inputs/resolve-cross-language/BaseUser.framework/Headers/BaseUser.h b/test/ClangModules/MixedSource/Inputs/resolve-cross-language/BaseUser.framework/Headers/BaseUser.h index eb1873e10463a..b5b577a91fab3 100644 --- a/test/ClangModules/MixedSource/Inputs/resolve-cross-language/BaseUser.framework/Headers/BaseUser.h +++ b/test/ClangModules/MixedSource/Inputs/resolve-cross-language/BaseUser.framework/Headers/BaseUser.h @@ -13,6 +13,7 @@ void useBaseProtoObjC(id ); @interface BaseClass (ObjCExtensions) - (void)categoryMethod; - (BaseEnum)baseEnumMethod:(BaseEnum)be; +- (RenamedEnum)renamedEnumMethod:(RenamedEnum)se; @end typedef OBJC_ENUM(unsigned char, BaseEnumObjC) { @@ -27,8 +28,29 @@ void useBaseEnum(BaseEnum); BaseEnumObjC getBaseEnumObjC(); void useBaseEnumObjC(BaseEnumObjC); +// temporarily redefine OBJC_ENUM because ClangImporter cares about the macro name +#undef OBJC_ENUM +#define OBJC_ENUM(_type, _name, SWIFT_NAME) enum _name : _type _name __attribute__((swift_name(SWIFT_NAME))); enum __attribute__((swift_name(SWIFT_NAME))) _name : _type + +typedef OBJC_ENUM(unsigned char, RenamedEnumObjC, "SwiftEnumObjC") { + RenamedEnumObjCQuux = RenamedEnumQuux, + RenamedEnumObjCCorge = RenamedEnumCorge, + RenamedEnumObjCGrault = RenamedEnumGrault, +}; + +// put OBJC_ENUM back just in case +#undef OBJC_ENUM +#define OBJC_ENUM(_type, _name) enum _name : _type _name; enum _name : _type + +RenamedEnum getRenamedEnum(); +void useRenamedEnum(RenamedEnum); + +RenamedEnumObjC getRenamedEnumObjC(); +void useRenamedEnumObjC(RenamedEnumObjC); + @protocol EnumProto - (BaseEnum)getEnum; +- (RenamedEnum)getSwiftEnum; @end @interface AnotherClass (EnumProtoConformance) diff --git a/test/ClangModules/MixedSource/mixed-target-using-header.swift b/test/ClangModules/MixedSource/mixed-target-using-header.swift index 0122d9b44b926..de0980d346460 100644 --- a/test/ClangModules/MixedSource/mixed-target-using-header.swift +++ b/test/ClangModules/MixedSource/mixed-target-using-header.swift @@ -57,3 +57,15 @@ func testFoundationOverlay() { _ = NSUTF8StringEncoding // no ambiguity _ = NSUTF8StringEncoding as UInt // and we should get the overlay version } + +func testProtocolNamingConflict() { + let a: ConflictingName1? = nil + var b: ConflictingName1Protocol? + b = a // expected-error {{cannot assign value of type 'ConflictingName1?' to type 'ConflictingName1Protocol?'}} + _ = b + + let c: ConflictingName2? = nil + var d: ConflictingName2Protocol? + d = c // expected-error {{cannot assign value of type 'ConflictingName2?' to type 'ConflictingName2Protocol?'}} + _ = d +} diff --git a/test/ClangModules/MixedSource/resolve-cross-language.swift b/test/ClangModules/MixedSource/resolve-cross-language.swift index b143ddd8af3c8..d07393283f858 100644 --- a/test/ClangModules/MixedSource/resolve-cross-language.swift +++ b/test/ClangModules/MixedSource/resolve-cross-language.swift @@ -20,6 +20,12 @@ be = getBaseClass().baseEnumMethod(be) be = AnotherClass().getEnum() var beo: BaseEnumObjC = getBaseEnumObjC() useBaseEnumObjC(beo) +var se: SwiftEnum = getRenamedEnum() +useRenamedEnum(se) +se = getBaseClass().renamedEnumMethod(se) +se = AnotherClass().getSwiftEnum() +var seo: SwiftEnumObjC = getRenamedEnumObjC() +useRenamedEnumObjC(seo) // Check type resolution. useBaseClass(getBaseClassObjC()) @@ -44,5 +50,17 @@ beo = BaseEnumObjC.Dah var beoRaw: CUnsignedChar = beo.rawValue +se = SwiftEnum.Quux +se = SwiftEnum.Corge +se = SwiftEnum.Grault + +var seRaw: CShort = se.rawValue + +seo = SwiftEnumObjC.Quux +seo = SwiftEnumObjC.Corge +seo = SwiftEnumObjC.Grault + +var seoRaw: CUnsignedChar = seo.rawValue + // Make sure we're actually parsing stuff. useBaseClass() // expected-error{{missing argument for parameter #1}} diff --git a/test/ClangModules/attr-swift_name_renaming.swift b/test/ClangModules/attr-swift_name_renaming.swift index 81ed168467a0d..8e378c01959ea 100644 --- a/test/ClangModules/attr-swift_name_renaming.swift +++ b/test/ClangModules/attr-swift_name_renaming.swift @@ -8,17 +8,17 @@ func test() { drawString("hello", 3, 5) // expected-error{{missing argument labels 'x:y:' in call}} // Enum name remapping. - var color: ColorKind = CT_red // FIXME: expected-error{{use of undeclared type 'ColorKind'}} + var color: ColorKind = CT_red var colo2: ColorType = CT_Red // FIXME: should provide Fix-It expected-error{{use of undeclared type 'ColorType'}} - // Typedef-of-anonymous-type-name renamming - var p = Point() // FIXME: expected-error{{use of unresolved identifier 'Point'}} - var p2 = PointType() // FIXME: should error + // Typedef-of-anonymous-type-name renaming + var p = Point() + var p2 = PointType() // FIXME: should provide Fix-It expected-error{{use of unresolved identifier 'PointType'}} // Field name remapping p.x = 7 // Typedef renaming - var mi: MyInt = 5 // FIXME: expected-error{{use of undeclared type 'MyInt'}} + var mi: MyInt = 5 var mi2: my_int_t = 7 // FIXME: should provide Fix-It expected-error{{use of undeclared type 'my_int_t'}} } diff --git a/test/ClangModules/autolinking.swift b/test/ClangModules/autolinking.swift index 64cd70ef25e03..3ceec2cf31182 100644 --- a/test/ClangModules/autolinking.swift +++ b/test/ClangModules/autolinking.swift @@ -11,7 +11,11 @@ // RUN: %target-swift-frontend %s -sdk %S/Inputs -I %S/Inputs/custom-modules -emit-ir -disable-autolink-framework LinkFramework -o %t/with-disabled.ll // RUN: FileCheck --check-prefix=CHECK-WITH-DISABLED %s < %t/with-disabled.ll +// Linux uses a different autolinking mechanism, based on +// swift-autolink-extract. This file tests the Darwin mechanism. // UNSUPPORTED: OS=linux-gnu +// UNSUPPORTED: OS=linux-gnueabihf +// UNSUPPORTED: OS=freebsd import LinkMusket import LinkFramework diff --git a/test/ClangModules/availability.swift b/test/ClangModules/availability.swift index 40bb0e6abb664..a0cf8ab0ae385 100644 --- a/test/ClangModules/availability.swift +++ b/test/ClangModules/availability.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse -verify -I %S/Inputs/custom-modules %s -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse -verify -I %S/Inputs/custom-modules -enable-swift-name-lookup-tables %s // REQUIRES: objc_interop diff --git a/test/ClangModules/availability_implicit_macosx.swift b/test/ClangModules/availability_implicit_macosx.swift index ee5600c536ca7..52f0295a91c50 100644 --- a/test/ClangModules/availability_implicit_macosx.swift +++ b/test/ClangModules/availability_implicit_macosx.swift @@ -1,5 +1,5 @@ -// RUN: %swift -parse -verify -target x86_64-apple-macosx10.10 %clang-importer-sdk -I %S/Inputs/custom-modules %s %S/Inputs/availability_implicit_macosx_other.swift -// RUN: not %swift -parse -target x86_64-apple-macosx10.10 %clang-importer-sdk -I %S/Inputs/custom-modules %s %S/Inputs/availability_implicit_macosx_other.swift 2>&1 | FileCheck %s '--implicit-check-not=:0' +// RUN: %swift -parse -verify -target x86_64-apple-macosx10.51 %clang-importer-sdk -I %S/Inputs/custom-modules %s %S/Inputs/availability_implicit_macosx_other.swift +// RUN: not %swift -parse -target x86_64-apple-macosx10.51 %clang-importer-sdk -I %S/Inputs/custom-modules %s %S/Inputs/availability_implicit_macosx_other.swift 2>&1 | FileCheck %s '--implicit-check-not=:0' // REQUIRES: OS=macosx @@ -29,15 +29,15 @@ func useClassThatTriggersImportOfPotentiallyUnavailableOptions() { } func directUseShouldStillTriggerDeprecationWarning() { - _ = NSDeprecatedOptions.First // expected-warning {{'NSDeprecatedOptions' was deprecated in OS X 10.10: Use a different API}} - _ = NSDeprecatedEnum.First // expected-warning {{'NSDeprecatedEnum' was deprecated in OS X 10.10: Use a different API}} + _ = NSDeprecatedOptions.First // expected-warning {{'NSDeprecatedOptions' was deprecated in OS X 10.51: Use a different API}} + _ = NSDeprecatedEnum.First // expected-warning {{'NSDeprecatedEnum' was deprecated in OS X 10.51: Use a different API}} } -func useInSignature(options: NSDeprecatedOptions) { // expected-warning {{'NSDeprecatedOptions' was deprecated in OS X 10.10: Use a different API}} +func useInSignature(options: NSDeprecatedOptions) { // expected-warning {{'NSDeprecatedOptions' was deprecated in OS X 10.51: Use a different API}} } class SuperClassWithDeprecatedInitializer { - @available(OSX, introduced=10.9, deprecated=10.10) + @available(OSX, introduced=10.9, deprecated=10.51) init() { } } @@ -49,39 +49,39 @@ class SubClassWithSynthesizedDesignedInitializerOverride : SuperClassWithDepreca } func callImplicitInitializerOnSubClassWithSynthesizedDesignedInitializerOverride() { - _ = SubClassWithSynthesizedDesignedInitializerOverride() // expected-warning {{'init()' was deprecated in OS X 10.10}} + _ = SubClassWithSynthesizedDesignedInitializerOverride() // expected-warning {{'init()' was deprecated in OS X 10.51}} } -@available(OSX, introduced=10.9, deprecated=10.10) +@available(OSX, introduced=10.9, deprecated=10.51) class DeprecatedSuperClass { var i : Int = 7 // Causes initializer to be synthesized } -class NotDeprecatedSubClassOfDeprecatedSuperClass : DeprecatedSuperClass { // expected-warning {{'DeprecatedSuperClass' was deprecated in OS X 10.10}} +class NotDeprecatedSubClassOfDeprecatedSuperClass : DeprecatedSuperClass { // expected-warning {{'DeprecatedSuperClass' was deprecated in OS X 10.51}} } -func callImplicitInitalizerOnNotDeprecatedSubClassOfDeprecatedSuperClass() { +func callImplicitInitializerOnNotDeprecatedSubClassOfDeprecatedSuperClass() { // We do not expect a warning here because the synthesized initializer // in NotDeprecatedSubClassOfDeprecatedSuperClass is not itself marked // deprecated. _ = NotDeprecatedSubClassOfDeprecatedSuperClass() } -@available(OSX, introduced=10.9, deprecated=10.10) +@available(OSX, introduced=10.9, deprecated=10.51) class DeprecatedSubClassOfDeprecatedSuperClass : DeprecatedSuperClass { } // Tests synthesis of materializeForSet class ClassWithLimitedAvailabilityAccessors { var limitedGetter: Int { - @available(OSX, introduced=10.11) + @available(OSX, introduced=10.52) get { return 10 } set(newVal) {} } var limitedSetter: Int { get { return 10 } - @available(OSX, introduced=10.11) + @available(OSX, introduced=10.52) set(newVal) {} } } @@ -103,7 +103,7 @@ func unavailableUseInUnavailableFunction() { } -@available(OSX 10.11, *) +@available(OSX 10.52, *) func foo() { let _ = SubOfOtherWithInit() } diff --git a/test/ClangModules/cf.swift b/test/ClangModules/cf.swift index 33efa829d4e58..2ac6b9132e3cf 100644 --- a/test/ClangModules/cf.swift +++ b/test/ClangModules/cf.swift @@ -3,6 +3,7 @@ // REQUIRES: objc_interop import CoreCooling +import CFAndObjC func assertUnmanaged(t: Unmanaged) {} func assertManaged(t: T) {} @@ -119,3 +120,21 @@ func testOutParametersBad() { let item: CCItem? CCRefrigeratorGetItemUnaudited(0, 0, item) // expected-error {{cannot convert value of type 'Int' to expected argument type 'CCRefrigerator!'}} } + +func nameCollisions() { + var objc: MyProblematicObject? + var cf: MyProblematicObjectRef? + cf = objc // expected-error {{cannot assign value of type 'MyProblematicObject?' to type 'MyProblematicObjectRef?'}} + objc = cf // expected-error {{cannot assign value of type 'MyProblematicObjectRef?' to type 'MyProblematicObject?'}} + + var cfAlias: MyProblematicAliasRef? + cfAlias = cf // okay + cf = cfAlias // okay + + var otherAlias: MyProblematicAlias? + otherAlias = cfAlias // expected-error {{cannot assign value of type 'MyProblematicAliasRef?' to type 'MyProblematicAlias?'}} + cfAlias = otherAlias // expected-error {{cannot assign value of type 'MyProblematicAlias?' to type 'MyProblematicAliasRef?'}} + + func isOptionalFloat(inout _: Optional) {} + isOptionalFloat(&otherAlias) // okay +} diff --git a/test/ClangModules/ctypes_parse.swift b/test/ClangModules/ctypes_parse.swift index dbc1dc65b13a5..11369bfa3cc65 100644 --- a/test/ClangModules/ctypes_parse.swift +++ b/test/ClangModules/ctypes_parse.swift @@ -32,7 +32,7 @@ func testAnonEnum() { a = AnonConst2 #if arch(i386) || arch(arm) _ = a as CUnsignedLongLong -#elseif arch(x86_64) || arch(arm64) +#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) _ = a as CUnsignedLong #else __portMe() diff --git a/test/ClangModules/enum-objc.swift b/test/ClangModules/enum-objc.swift new file mode 100644 index 0000000000000..5b8f0fe2e246b --- /dev/null +++ b/test/ClangModules/enum-objc.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend -emit-sil %s -import-objc-header %S/Inputs/enum-objc.h -verify + +// REQUIRES: objc_interop + +func test(value: SwiftEnum) { + switch value { + case .One: break + case .Two: break + case .Three: break + } // no error +} diff --git a/test/ClangModules/enum-with-target.swift b/test/ClangModules/enum-with-target.swift index 9095cbb71eb05..3dfe3e208f9e9 100644 --- a/test/ClangModules/enum-with-target.swift +++ b/test/ClangModules/enum-with-target.swift @@ -1,5 +1,5 @@ -// RUN: %swift %clang-importer-sdk -target x86_64-apple-macosx10.9 -parse %s -verify -// RUN: %swift %clang-importer-sdk -target x86_64-apple-macosx10.10 -parse %s -verify +// RUN: %swift %clang-importer-sdk -target x86_64-apple-macosx10.51 -parse %s -verify +// RUN: %swift %clang-importer-sdk -target x86_64-apple-macosx10.52 -parse %s -verify // REQUIRES: OS=macosx import Foundation diff --git a/test/ClangModules/foreign_errors.swift b/test/ClangModules/foreign_errors.swift index 48098e7ce473e..53c6f3422e1a4 100644 --- a/test/ClangModules/foreign_errors.swift +++ b/test/ClangModules/foreign_errors.swift @@ -98,7 +98,7 @@ func testSwiftError() throws { } // rdar://21074857 -func needsNonThrowing(fn: () -> ()) {} +func needsNonThrowing(fn: () -> Void) {} func testNSErrorExhaustive() { needsNonThrowing { do { diff --git a/test/ClangModules/macros_redef.swift b/test/ClangModules/macros_redef.swift new file mode 100644 index 0000000000000..6e37fcc3be256 --- /dev/null +++ b/test/ClangModules/macros_redef.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -parse -verify %s + +import MacrosRedefA +import MacrosRedefB + +func testMacroRedef() { + var s: String + s = REDEF_1 + s = REDEF_2 // expected-error{{ambiguous use of 'REDEF_2'}} +} + diff --git a/test/ClangModules/no-sdk.swift b/test/ClangModules/no-sdk.swift index e4fddc726511c..eb1685eebc65c 100644 --- a/test/ClangModules/no-sdk.swift +++ b/test/ClangModules/no-sdk.swift @@ -2,6 +2,6 @@ // RUN: %target-swift-frontend -parse -sdk "" -I %S/Inputs/custom-modules %s // Verify that we can still import modules even without an SDK. -import ExternIntX; +import ExternIntX let y: CInt = ExternIntX.x diff --git a/test/ClangModules/nullability_silgen.swift b/test/ClangModules/nullability_silgen.swift index a56ef8177530a..550757103ab4d 100644 --- a/test/ClangModules/nullability_silgen.swift +++ b/test/ClangModules/nullability_silgen.swift @@ -2,7 +2,7 @@ // REQUIRES: objc_interop -import nullability; +import nullability // null_resettable properties. // CHECK-LABEL: sil hidden @_TF18nullability_silgen18testNullResettable diff --git a/test/ClangModules/objc_dynamic_lookup.swift b/test/ClangModules/objc_dynamic_lookup.swift index 9ab7118390a51..54e2f5484d1f9 100644 --- a/test/ClangModules/objc_dynamic_lookup.swift +++ b/test/ClangModules/objc_dynamic_lookup.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse -enable-swift-name-lookup-tables %s -verify +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse %s -verify // REQUIRES: objc_interop diff --git a/test/ClangModules/objc_factory_method.swift b/test/ClangModules/objc_factory_method.swift index 29ae9e896c4b6..afe8d7f88e1f6 100644 --- a/test/ClangModules/objc_factory_method.swift +++ b/test/ClangModules/objc_factory_method.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -target x86_64-apple-macosx10.10 -parse %s -verify +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -target x86_64-apple-macosx10.51 -parse %s -verify // REQUIRES: OS=macosx // REQUIRES: objc_interop @@ -38,30 +38,30 @@ func testFactoryWithLaterIntroducedInit() { // Don't prefer more available convenience factory initializer over less // available designated initializer - _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.11 or newer}} + _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.52 or newer}} // expected-note @-1 {{add 'if #available' version check}} // expected-note @-2 {{add @available attribute to enclosing global function}} - _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.11 or newer}} - // expected-note @-1 {{add 'if #available' version check}} {{3-63=if #available(OSX 10.11, *) {\n _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5)\n \} else {\n // Fallback on earlier versions\n \}}} - // expected-note @-2 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.11, *)\n}} + _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.52 or newer}} + // expected-note @-1 {{add 'if #available' version check}} {{3-63=if #available(OSX 10.52, *) {\n _ = NSHavingConvenienceFactoryAndLaterDesignatedInit(flam:5)\n \} else {\n // Fallback on earlier versions\n \}}} + // expected-note @-2 {{add @available attribute to enclosing global function}} {{1-1=@available(OSX 10.52, *)\n}} // Don't prefer more available factory initializer over less // available designated initializer - _ = NSHavingFactoryAndLaterConvenienceInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.11 or newer}} + _ = NSHavingFactoryAndLaterConvenienceInit(flim:5) // expected-error {{'init(flim:)' is only available on OS X 10.52 or newer}} // expected-note @-1 {{add 'if #available' version check}} // expected-note @-2 {{add @available attribute to enclosing global function}} - _ = NSHavingFactoryAndLaterConvenienceInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.11 or newer}} + _ = NSHavingFactoryAndLaterConvenienceInit(flam:5) // expected-error {{'init(flam:)' is only available on OS X 10.52 or newer}} // expected-note @-1 {{add 'if #available' version check}} // expected-note @-2 {{add @available attribute to enclosing global function}} // When both a convenience factory and a convenience initializer have the // same availability, choose the convenience initializer. - _ = NSHavingConvenienceFactoryAndSameConvenienceInit(flim:5) // expected-warning {{'init(flim:)' was deprecated in OS X 10.10: ConvenienceInit}} - _ = NSHavingConvenienceFactoryAndSameConvenienceInit(flam:5) // expected-warning {{'init(flam:)' was deprecated in OS X 10.10: ConvenienceInit}} + _ = NSHavingConvenienceFactoryAndSameConvenienceInit(flim:5) // expected-warning {{'init(flim:)' was deprecated in OS X 10.51: ConvenienceInit}} + _ = NSHavingConvenienceFactoryAndSameConvenienceInit(flam:5) // expected-warning {{'init(flam:)' was deprecated in OS X 10.51: ConvenienceInit}} _ = NSHavingConvenienceFactoryAndSameConvenienceInit(flotsam:5) // expected-warning {{'init(flotsam:)' is deprecated: ConvenienceInit}} _ = NSHavingConvenienceFactoryAndSameConvenienceInit(jetsam:5) // expected-warning {{'init(jetsam:)' is deprecated: ConvenienceInit}} diff --git a/test/ClangModules/objc_ir.swift b/test/ClangModules/objc_ir.swift index 72c7ca7af69a8..d96ca248edbd3 100644 --- a/test/ClangModules/objc_ir.swift +++ b/test/ClangModules/objc_ir.swift @@ -11,9 +11,9 @@ import objc_ext import TestProtocols import ObjCIRExtras -// CHECK: @"\01L_selector_data(method:withFloat:)" = internal constant [18 x i8] c"method:withFloat:\00" -// CHECK: @"\01L_selector_data(method:withDouble:)" = internal constant [19 x i8] c"method:withDouble:\00" -// CHECK: @"\01L_selector_data(method:separateExtMethod:)" = internal constant [26 x i8] c"method:separateExtMethod:\00", section "__TEXT,__objc_methname,cstring_literals" +// CHECK: @"\01L_selector_data(method:withFloat:)" = private global [18 x i8] c"method:withFloat:\00" +// CHECK: @"\01L_selector_data(method:withDouble:)" = private global [19 x i8] c"method:withDouble:\00" +// CHECK: @"\01L_selector_data(method:separateExtMethod:)" = private global [26 x i8] c"method:separateExtMethod:\00", section "__TEXT,__objc_methname,cstring_literals" // Instance method invocation // CHECK: define hidden void @_TF7objc_ir15instanceMethodsFCSo1BT_([[B]]* diff --git a/test/ClangModules/objc_parse.swift b/test/ClangModules/objc_parse.swift index 87858a7ecb758..b9003bca3e4ad 100644 --- a/test/ClangModules/objc_parse.swift +++ b/test/ClangModules/objc_parse.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -I %S/Inputs/custom-modules %s -verify -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -enable-swift-name-lookup-tables -I %S/Inputs/custom-modules %s -verify // REQUIRES: objc_interop @@ -38,8 +37,8 @@ func instanceMethods(b: B) { b.setEnabled(true) // SEL - b.performSelector("isEqual:", withObject:b) - if let result = b.performSelector("getAsProto", withObject:nil) { + b.performSelector(#selector(NSObject.isEqual(_:)), withObject:b) + if let result = b.performSelector(#selector(B.getAsProto), withObject:nil) { _ = result.takeUnretainedValue() } @@ -58,7 +57,7 @@ func instanceMethods(b: B) { var obj = NSObject() var prot = NSObjectProtocol.self b.`protocol`(prot, hasThing:obj) - b.doThing(obj, `protocol`: prot) + b.doThing(obj, protocol: prot) } // Class method invocation @@ -86,22 +85,21 @@ func instanceMethodsInExtensions(b: B) { b.method(1, onExtB:2.5) b.method(1, separateExtMethod:3.5) - let m1 = b.method:onCat1: + let m1 = b.method(_:onCat1:) m1(1, onCat1: 2.5) - let m2 = b.method:onExtA: + let m2 = b.method(_:onExtA:) m2(1, onExtA: 2.5) - let m3 = b.method:onExtB: + let m3 = b.method(_:onExtB:) m3(1, onExtB: 2.5) - let m4 = b.method:separateExtMethod: + let m4 = b.method(_:separateExtMethod:) m4(1, separateExtMethod: 2.5) } func dynamicLookupMethod(b: AnyObject) { - // FIXME: Syntax will be replaced. - if let m5 = b.method:separateExtMethod: { + if let m5 = b.method(_:separateExtMethod:) { m5(1, separateExtMethod: 2.5) } } @@ -210,7 +208,7 @@ func testProtocolMethods(b: B, p2m: P2.Type) { } func testId(x: AnyObject) { - x.performSelector!("foo:", withObject: x) + x.performSelector!("foo:", withObject: x) // expected-warning{{no method declared with Objective-C selector 'foo:'}} x.performAdd(1, withValue: 2, withValue: 3, withValue2: 4) x.performAdd!(1, withValue: 2, withValue: 3, withValue2: 4) @@ -379,10 +377,10 @@ func testPreferClassMethodToCurriedInstanceMethod(obj: NSObject) { func testPropertyAndMethodCollision(obj: PropertyAndMethodCollision, rev: PropertyAndMethodReverseCollision) { obj.object = nil - obj.object(obj, doSomething:"action") + obj.object(obj, doSomething:Selector("action")) rev.object = nil - rev.object(rev, doSomething:"action") + rev.object(rev, doSomething:Selector("action")) var value: AnyObject = obj.protoProp() value = obj.protoPropRO() diff --git a/test/ClangModules/objc_subscript.swift b/test/ClangModules/objc_subscript.swift index 63d4ac993c76f..89f9a3ad9944c 100644 --- a/test/ClangModules/objc_subscript.swift +++ b/test/ClangModules/objc_subscript.swift @@ -6,7 +6,6 @@ // FIXME: END -enable-source-import hackaround // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -I %S/Inputs/custom-modules %s -verify -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -enable-swift-name-lookup-tables -I %S/Inputs/custom-modules %s -verify // REQUIRES: objc_interop diff --git a/test/Constraints/assignment.swift b/test/Constraints/assignment.swift index e06abf7b47d07..e162628626076 100644 --- a/test/Constraints/assignment.swift +++ b/test/Constraints/assignment.swift @@ -49,3 +49,11 @@ func value2(inout x: Int) {} value2(&_) // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}} value(_) // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}} + +// = vs. == in Swift if string character count statement causes segmentation fault +func f23798944() { + let s = "" + if s.characters.count = 0 { // expected-error {{cannot assign to property: 'count' is a get-only property}} + } +} + diff --git a/test/Constraints/associated_types.swift b/test/Constraints/associated_types.swift index 0fa820f588b96..89b9129eb2b3d 100644 --- a/test/Constraints/associated_types.swift +++ b/test/Constraints/associated_types.swift @@ -1,7 +1,7 @@ // RUN: %target-parse-verify-swift protocol Runcible { - typealias Runcee + associatedtype Runcee } class Mince { diff --git a/test/Constraints/bridging.swift b/test/Constraints/bridging.swift index b1cfc891fca71..34525bab5c709 100644 --- a/test/Constraints/bridging.swift +++ b/test/Constraints/bridging.swift @@ -186,16 +186,13 @@ func rdar19551164b(s: NSString, _ a: NSArray) { } // rdar://problem/19695671 -func takesSet(p: Set) {} -func takesDictionary(p: Dictionary) {} -func takesArray(t: Array) {} +func takesSet(p: Set) {} // expected-note {{in call to function 'takesSet'}} +func takesDictionary(p: Dictionary) {} // expected-note {{in call to function 'takesDictionary'}} +func takesArray(t: Array) {} // expected-note {{in call to function 'takesArray'}} func rdar19695671() { - takesSet(NSSet() as! Set) // expected-error{{cannot invoke 'takesSet' with an argument list of type '(Set<_>)'}} - // expected-note @-1 {{expected an argument list of type '(Set)'}} - takesDictionary(NSDictionary() as! Dictionary) // expected-error{{cannot invoke 'takesDictionary' with an argument list of type '(Dictionary<_, _>)'}} - // expected-note @-1 {{expected an argument list of type '(Dictionary)'}} - takesArray(NSArray() as! Array) // expected-error{{cannot invoke 'takesArray' with an argument list of type '(Array<_>)'}} - // expected-note @-1 {{expected an argument list of type '(Array)'}} + takesSet(NSSet() as! Set) // expected-error{{generic parameter 'T' could not be inferred}} + takesDictionary(NSDictionary() as! Dictionary) // expected-error{{generic parameter 'K' could not be inferred}} + takesArray(NSArray() as! Array) // expected-error{{generic parameter 'T' could not be inferred}} } @@ -272,7 +269,7 @@ func rdar20029786(ns: NSString?) { // QoI: Using as! instead of as in this case produces really bad diagnostic func rdar19813772(nsma: NSMutableArray) { - var a1 = nsma as! Array // expected-error{{generic parameter 'Element' could not be inferred}} + var a1 = nsma as! Array // expected-error{{generic parameter 'Element' could not be inferred in cast to 'Array<_>'}} // FIXME: The following diagnostic is misleading and should not happen: expected-warning@-1{{cast from 'NSMutableArray' to unrelated type 'Array<_>' always fails}} var a2 = nsma as! Array // expected-warning{{forced cast from 'NSMutableArray' to 'Array' always succeeds; did you mean to use 'as'?}} {{17-20=as}} var a3 = nsma as Array diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 7d94e4f59b5d5..b4e374e588467 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -19,7 +19,7 @@ mySort(strings, { x, y in x < y }) // Closures with inout arguments. func f0(t: T, _ f: (inout T) -> U) -> U { - var t2 = t; + var t2 = t return f(&t2) } @@ -45,7 +45,7 @@ func foo() { // struct X3 { - init(_: (T)->()) {} + init(_: (T) -> ()) {} } func testX3(x: Int) { @@ -104,40 +104,40 @@ func testMap() { // QoI: improve diagnostic when contextual type of closure disagrees with arguments -var _: ()-> Int = {0} +var _: () -> Int = {0} -// expected-error @+1 {{contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored}} {{23-23=_ in }} -var _: (Int)-> Int = {0} +// expected-error @+1 {{contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored}} {{24-24=_ in }} +var _: (Int) -> Int = {0} -// expected-error @+1 {{contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored}} {{23-23= _ in}} -var _: (Int)-> Int = { 0 } +// expected-error @+1 {{contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored}} {{24-24= _ in}} +var _: (Int) -> Int = { 0 } -// expected-error @+1 {{contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored}} {{28-28=_,_ in }} -var _: (Int, Int)-> Int = {0} +// expected-error @+1 {{contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored}} {{29-29=_,_ in }} +var _: (Int, Int) -> Int = {0} // expected-error @+1 {{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 3 were used in closure body}} -var _: (Int,Int)-> Int = {$0+$1+$2} +var _: (Int,Int) -> Int = {$0+$1+$2} // expected-error @+1 {{contextual closure type '(Int, Int, Int) -> Int' expects 3 arguments, but 2 were used in closure body}} -var _: (Int, Int, Int)-> Int = {$0+$1} +var _: (Int, Int, Int) -> Int = {$0+$1} -var _: ()-> Int = {a in 0} +var _: () -> Int = {a in 0} // expected-error @+1 {{contextual closure type '(Int) -> Int' expects 1 argument, but 2 were used in closure body}} -var _: (Int)-> Int = {a,b in 0} +var _: (Int) -> Int = {a,b in 0} // expected-error @+1 {{contextual closure type '(Int) -> Int' expects 1 argument, but 3 were used in closure body}} -var _: (Int)-> Int = {a,b,c in 0} +var _: (Int) -> Int = {a,b,c in 0} -var _: (Int, Int)-> Int = {a in 0} +var _: (Int, Int) -> Int = {a in 0} // expected-error @+1 {{contextual closure type '(Int, Int, Int) -> Int' expects 3 arguments, but 2 were used in closure body}} -var _: (Int, Int, Int)-> Int = {a, b in a+b} +var _: (Int, Int, Int) -> Int = {a, b in a+b} // Fail to infer types for closure that takes an inout argument func r15998821() { - func take_closure(x : (inout Int)-> ()) { } + func take_closure(x : (inout Int) -> ()) { } func test1() { take_closure { (inout a : Int) in @@ -159,17 +159,18 @@ func r15998821() { } // better diagnostics for closures w/o "in" clause -var _: (Int,Int)-> Int = {$0+$1+$2} // expected-error {{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 3 were used in closure body}} +var _: (Int,Int) -> Int = {$0+$1+$2} // expected-error {{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 3 were used in closure body}} // Crash when re-typechecking bodies of non-single expression closures struct CC {} +// expected-note @+1 {{in call to function 'callCC'}} func callCC(f: CC -> U) -> () {} func typeCheckMultiStmtClosureCrash() { - callCC { // expected-error {{cannot invoke 'callCC' with an argument list of type '((CC) -> _)'}} - _ = $0 // expected-note@-1 {{expected an argument list of type '(CC -> U)'}} + callCC { // expected-error {{generic parameter 'U' could not be inferred}} + _ = $0 return 1 } } diff --git a/test/Constraints/construction.swift b/test/Constraints/construction.swift index 66064049d60e8..dde883dfc8719 100644 --- a/test/Constraints/construction.swift +++ b/test/Constraints/construction.swift @@ -20,7 +20,7 @@ enum Z { init(_ x: Int, _ y: Int) { self = .point(x, y) } } -enum Optional { +enum Optional { // expected-note {{'T' declared as parameter to type 'Optional'}} case none case value(T) @@ -57,7 +57,7 @@ acceptString("\(hello), \(world) #\(i)!") Optional(1) // expected-warning{{unused}} Optional(1) // expected-warning{{unused}} _ = .none as Optional -Optional(.none) // expected-error{{type of expression is ambiguous without more context}} +Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}} // Interpolation "\(hello), \(world) #\(i)!" diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 1a677cdb08734..ddf1c6d12b960 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -1,7 +1,7 @@ // RUN: %target-parse-verify-swift protocol P { - typealias SomeType + associatedtype SomeType } protocol P2 { @@ -47,8 +47,7 @@ f0(i, i, // Position mismatch -f5(f4) // expected-error {{cannot invoke 'f5' with an argument list of type '((Int) -> Int)'}} -// expected-note @-1 {{expected an argument list of type '(T)'}} +f5(f4) // expected-error {{argument type '(Int) -> Int' does not conform to expected type 'P2'}} // Tuple element not convertible. f0(i, @@ -69,14 +68,27 @@ f4(i, d) // expected-error {{extra argument in call}} // Missing member. i.wobble() // expected-error{{value of type 'Int' has no member 'wobble'}} +// Generic member does not conform. +extension Int { + func wibble(x: T, _ y: T) -> T { return x } +} +i.wibble(3, 4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} + +// Generic member args correct, but return type doesn't match. +struct A : P2 { + func wonka() {} +} +let a = A() +for j in i.wibble(a, a) { // expected-error {{type 'A' does not conform to protocol 'SequenceType'}} +} + // QoI: Incorrect diagnostic for calling nonexistent members on literals 1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}} [1, 2, 3].doesntExist(0) // expected-error {{value of type '[Int]' has no member 'doesntExist'}} "awfawf".doesntExist(0) // expected-error {{value of type 'String' has no member 'doesntExist'}} // Does not conform to protocol. -f5(i) // expected-error {{cannot invoke 'f5' with an argument list of type '(Int)'}} -// expected-note @-1 {{expected an argument list of type '(T)'}} +f5(i) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} // Make sure we don't leave open existentials when diagnosing. // @@ -114,8 +126,7 @@ i ***~ i // expected-error{{cannot convert value of type 'Int' to expected argum // FIXME: poor diagnostic, to be fixed in 20142462. For now, we just want to // make sure that it doesn't crash. func rdar20142523() { - map(0..<10, { x in // expected-error{{cannot invoke 'map' with an argument list of type '(Range, (_) -> _)'}} - // expected-note @-1 {{overloads for 'map' exist with these partially matching parameter lists: (C, (C.Generator.Element) -> T), (T?, @noescape (T) -> U)}} + map(0..<10, { x in // expected-error{{ambiguous reference to member '..<'}} () return x }) @@ -242,7 +253,7 @@ func r18800223(i : Int) { var buttonTextColor: String? - _ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{unable to infer closure return type in current context}} + _ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{result values in '? :' expression have mismatching types 'Int' and '(_) -> _'}} } // Bogus "'_' can only appear in a pattern or on the left side of an assignment" is back @@ -261,9 +272,9 @@ func rdar21784170() { } // BOGUS: unexpected trailing closure -func expect(_: T)(_: U.Type) {} // expected-note {{found this candidate}} expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -func expect(_: T, _: Int = 1)(_: U.Type) {} // expected-note {{found this candidate}} expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -expect(Optional(3))(Optional.self) // expected-error {{ambiguous use of 'expect'}} +func expect(_: T) -> (U.Type) -> () { return { ty in () } } // expected-note{{found this candidate}} +func expect(_: T, _: Int = 1) -> (U.Type) -> () { return { ty in () } } // expected-note{{found this candidate}} +expect(Optional(3))(Optional.self) // expected-error{{ambiguous use of 'expect'}} // Swift Enum Scoping Oddity func rdar19804707() { @@ -278,8 +289,8 @@ func rdar19804707() { knownOps = .BinaryOperator({$1 - $0}) // FIXME: rdar://19804707 - These two statements should be accepted by the type checker. - knownOps = .BinaryOperator(){$1 - $0} // expected-error {{type of expression is ambiguous without more context}} - knownOps = .BinaryOperator{$1 - $0} // expected-error {{type of expression is ambiguous without more context}} + knownOps = .BinaryOperator(){$1 - $0} // expected-error {{reference to member 'BinaryOperator' cannot be resolved without a contextual type}} + knownOps = .BinaryOperator{$1 - $0} // expected-error {{reference to member 'BinaryOperator' cannot be resolved without a contextual type}} } @@ -301,8 +312,8 @@ func r20789423() { -func f7(a: Int)(b : Int) -> Int { // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} - return a+b +func f7(a: Int) -> (b: Int) -> Int { + return { b in a+b } } f7(1)(b: 1) @@ -320,7 +331,7 @@ f8(b: 1.0) // expected-error {{cannot convert value of type 'Double' to class CurriedClass { func method1() {} - func method2(a: Int)(b : Int) {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} + func method2(a: Int) -> (b : Int) -> () { return { b in () } } func method3(a: Int, b : Int) {} } @@ -424,8 +435,7 @@ func f20371273() { // Swift fails to compile: [0].map() { _ in let r = (1,2).0; return r } // FIXME: Should complain about not having a return type annotation in the closure. [0].map { _ in let r = (1,2).0; return r } -// expected-error @-1 {{cannot invoke 'map' with an argument list of type '(@noescape (Int) throws -> _)'}} -// expected-note @-2 {{expected an argument list of type '(@noescape Int throws -> T)'}} +// expected-error @-1 {{expression type '[_]' is ambiguous without more context}} // Less than useful error message when using map on optional dictionary type func rdar21078316() { @@ -600,7 +610,7 @@ func r22470302(c: r22470302Class) { // QoI: Pointfree reference to generic initializer in generic context does not compile extension String { @available(*, unavailable, message="calling this is unwise") - func unavail // expected-note {{'unavail' has been explicitly marked unavailable here}} + func unavail // expected-note 2 {{'unavail' has been explicitly marked unavailable here}} (a : T) -> String {} } extension Array { @@ -609,18 +619,19 @@ extension Array { } func h() -> String { - return "foo".unavail([0]) // expected-error {{value of type 'String' has no member 'Element'}} + return "foo".unavail([0]) // expected-error {{'unavail' is unavailable: calling this is unwise}} } } // QoI: Weird error when failing to infer archetype -func safeAssign(inout lhs: T) -> Bool {} // expected-note {{in call to function 'safeAssign'}} +func safeAssign(inout lhs: T) -> Bool {} +// expected-note @-1 {{in call to function 'safeAssign'}} let a = safeAssign // expected-error {{generic parameter 'T' could not be inferred}} // QoI: Incorrect 'add ()' fixit with trailing closure func foo() -> [Int] { - return Array (count: 1) { // expected-error {{cannot invoke initializer for type 'Array' with an argument list of type '(count: Int, () -> Int)'}} + return Array (count: 1) { // expected-error {{cannot invoke initializer for type 'Array' with an argument list of type '(count: Int, () -> _)'}} // expected-note @-1 {{expected an argument list of type '(count: Int, repeatedValue: Element)'}} return 1 } @@ -652,7 +663,7 @@ example21890157.property = "confusing" // expected-error {{value of optional ty struct UnaryOp {} _ = -UnaryOp() // expected-error {{unary operator '-' cannot be applied to an operand of type 'UnaryOp'}} -// expected-note @-1 {{overloads for '-' exist with these partially matching parameter lists: (Float), (Double),}} +// expected-note @-1 {{overloads for '-' exist with these partially matching parameter lists: (Float), (Double)}} // Swift compiler segfault in failure diagnosis @@ -675,4 +686,24 @@ func r23272739(contentType: String) { return actualAcceptableContentTypes.contains(contentType) // expected-error {{unexpected non-void return value in void function}} } +// QoI: Strings in Swift cannot be indexed directly with integer offsets +func r23641896() { + var g = "Hello World" + g.replaceRange(0...2, with: "ce") // expected-error {{String may not be indexed with 'Int', it has variable size elements}} + // expected-note @-1 {{consider using an existing high level algorithm, str.startIndex.advancedBy(n), or a projection like str.utf8}} + + _ = g[12] // expected-error {{'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion}} + +} + + +// QoI: Incorrectly flattening ((Int,Int)) argument list to (Int,Int) when printing note +func test17875634() { + var match: [(Int, Int)] = [] + var row = 1 + var col = 2 + + match.append(row, col) // expected-error {{extra argument in call}} +} + diff --git a/test/Constraints/dictionary_literal.swift b/test/Constraints/dictionary_literal.swift index 6c3b6c4c8950b..579f7ffa25196 100644 --- a/test/Constraints/dictionary_literal.swift +++ b/test/Constraints/dictionary_literal.swift @@ -59,3 +59,6 @@ var _: Dictionary? = ["foo", 1.0, 2] // expected-error {{contextua var _: Dictionary? = ["foo" : 1.0] // expected-error {{cannot convert value of type 'Double' to expected dictionary value type 'Int'}} +// QoI: Should handle [] in dictionary contexts better +var _: [Int: Int] = [] // expected-error {{use [:] to get an empty dictionary literal}} {{22-22=:}} + diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index fba21c068a02c..3662618993d12 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -37,7 +37,7 @@ func forgotCall() { f6(f4, f2) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{8-8=()}} // With overloading: only one succeeds. - a = createB // expected-error{{ambiguous reference to member 'createB'}} + a = createB // expected-error{{ambiguous reference to member 'createB()'}} // With overloading, pick the fewest number of fixes. var b = f7(f4, f1) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}} diff --git a/test/Constraints/function.swift b/test/Constraints/function.swift index 1ddc44c40f351..8187c95b699ac 100644 --- a/test/Constraints/function.swift +++ b/test/Constraints/function.swift @@ -12,7 +12,7 @@ f1(f1(f)) f2(f) f2(1.0) -func call_lvalue(@autoclosure rhs: ()->Bool) -> Bool { +func call_lvalue(@autoclosure rhs: () -> Bool) -> Bool { return rhs() } @@ -75,3 +75,8 @@ A().a(text:"sometext") // expected-error {{argument labels '(text:)' do not matc func r22451001() -> AnyObject {} print(r22451001(5)) // expected-error {{argument passed to call that takes no arguments}} + +// SR-590 Passing two parameters to a function that takes one argument of type Any crashes the compiler +func sr590(x: Any) {} +sr590(3,4) // expected-error {{extra argument in call}} + diff --git a/test/Constraints/generic_overload.swift b/test/Constraints/generic_overload.swift index 980382d069104..f5b376b30c6df 100644 --- a/test/Constraints/generic_overload.swift +++ b/test/Constraints/generic_overload.swift @@ -1,7 +1,7 @@ // RUN: %target-parse-verify-swift -protocol P1 { typealias Assoc } -protocol P2 : P1 { typealias Assoc } +protocol P1 { associatedtype Assoc } +protocol P2 : P1 { associatedtype Assoc } protocol P3 { } struct X1 : P1 { typealias Assoc = X3 } diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index 457867539050c..c4ac9057ad43f 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -43,7 +43,7 @@ func foo(arg: T) -> T { // Associated types and metatypes protocol SomeProtocol { - typealias SomeAssociated + associatedtype SomeAssociated } func generic_metatypes(x: T) @@ -101,7 +101,7 @@ func foo2(p1: P1) -> P2 { // protocol BinaryMethodWorkaround { - typealias MySelf + associatedtype MySelf } protocol Squigglable : BinaryMethodWorkaround { @@ -142,12 +142,12 @@ func test16078944 (lhs: T, args: T) -> Int { class r22409190ManagedBuffer { final var value: Value { get {} set {}} func withUnsafeMutablePointerToElements( - body: (UnsafeMutablePointer)->R) -> R { + body: (UnsafeMutablePointer) -> R) -> R { } } class MyArrayBuffer: r22409190ManagedBuffer { deinit { - self.withUnsafeMutablePointerToElements { elems->Void in + self.withUnsafeMutablePointerToElements { elems -> Void in elems.destroy(self.value) // expected-error {{cannot convert value of type 'UInt' to expected argument type 'Int'}} } } @@ -171,3 +171,43 @@ func r22459135() { } } } + + +// QoI: Friendlier error message for "[] as Set" +// QoI: "argument for generic parameter 'Element' could not be inferred" lacks context +_ = [] as Set // expected-error {{generic parameter 'Element' could not be inferred in cast to 'Set<_>}} + + +// QoI: Error when unable to infer generic archetype lacks greatness +func r22509125(a : T?) { // expected-note {{in call to function 'r22509125'}} + r22509125(nil) // expected-error {{generic parameter 'T' could not be inferred}} +} + + +// QoI: error: cannot convert value of type 'Int' to specified type 'Int' +struct R24267414 { // expected-note {{'T' declared as parameter to type 'R24267414'}} + static func foo() -> Int {} +} +var _ : Int = R24267414.foo() // expected-error {{generic parameter 'T' could not be inferred}} + + +// https://bugs.swift.org/browse/SR-599 +func SR599() -> T.Type { return T.self } // expected-note {{in call to function 'SR599'}} +_ = SR599() // expected-error {{generic parameter 'T' could not be inferred}} + + + + +// QoI: Poor diagnostic when we are unable to infer type +protocol Q19215114 {} +protocol P19215114 {} + +// expected-note @+1 {{in call to function 'body9215114'}} +func body9215114(t: T) -> (u: U) -> () {} + +func test9215114(t: T) -> (U) -> () { + //Should complain about not being able to infer type of U. + let f = body9215114(t) // expected-error {{generic parameter 'T' could not be inferred}} + return f +} + diff --git a/test/Constraints/incomplete_function_ref.swift b/test/Constraints/incomplete_function_ref.swift index 1428ff78108f5..bc5d4c1c07ada 100644 --- a/test/Constraints/incomplete_function_ref.swift +++ b/test/Constraints/incomplete_function_ref.swift @@ -1,6 +1,6 @@ // RUN: %target-parse-verify-swift -struct MyCollection { +struct MyCollection { // expected-note {{'Element' declared as parameter to type 'MyCollection'}} func map(transform: (Element) -> T) -> MyCollection { fatalError("implement") } diff --git a/test/Constraints/invalid_archetype_constraint.swift b/test/Constraints/invalid_archetype_constraint.swift index ed86f4043a9b8..ae04b03297d93 100644 --- a/test/Constraints/invalid_archetype_constraint.swift +++ b/test/Constraints/invalid_archetype_constraint.swift @@ -3,7 +3,7 @@ protocol Empty {} protocol P { - typealias Element + associatedtype Element init() } diff --git a/test/Constraints/invalid_constraint_lookup.swift b/test/Constraints/invalid_constraint_lookup.swift index e2eb8c60bda6c..35f98996ed061 100644 --- a/test/Constraints/invalid_constraint_lookup.swift +++ b/test/Constraints/invalid_constraint_lookup.swift @@ -1,17 +1,17 @@ // RUN: %target-parse-verify-swift protocol P { - typealias A + associatedtype A func generate() -> Int } func f(rhs: U) -> X { // expected-error {{use of undeclared type 'X'}} // FIXME: This diagnostic isn't great, it happens because the generic constraint // 'U' from the invalid type signature never gets resolved. - let g = rhs.generate() // expected-error {{type of expression is ambiguous without more context}} + let g = rhs.generate() // expected-error {{cannot invoke 'generate' with no arguments}} } struct Zzz { - subscript (a: Foo) -> Zzz { // expected-error 2 {{use of undeclared type 'Foo'}} + subscript (a: Foo) -> Zzz { // expected-error {{use of undeclared type 'Foo'}} get: // expected-error {{expected '{' to start getter definition}} set: for i in value {} @@ -19,8 +19,8 @@ struct Zzz { } protocol _CollectionType { - typealias Index - typealias _Element + associatedtype Index + associatedtype _Element subscript(i: Index) -> _Element {get} } diff --git a/test/Constraints/invalid_logicvalue_coercion.swift b/test/Constraints/invalid_logicvalue_coercion.swift index e5418cb21eb07..426f4586071b7 100644 --- a/test/Constraints/invalid_logicvalue_coercion.swift +++ b/test/Constraints/invalid_logicvalue_coercion.swift @@ -5,5 +5,5 @@ var c = C() if c as C { // expected-error{{type 'C' does not conform to protocol 'BooleanType'}} } -if ({1} as ()->Int) { // expected-error{{type '() -> Int' does not conform to protocol 'BooleanType'}} +if ({1} as () -> Int) { // expected-error{{type '() -> Int' does not conform to protocol 'BooleanType'}} } diff --git a/test/Constraints/keyword_arguments.swift b/test/Constraints/keyword_arguments.swift index 6dbf5a7246823..ea8d6f0e3698f 100644 --- a/test/Constraints/keyword_arguments.swift +++ b/test/Constraints/keyword_arguments.swift @@ -51,7 +51,7 @@ allkeywords1(1, y: 2) // expected-error{{missing argument label 'x:' in call}} { // If keyword is reserved, make sure to quote it. rdar://problem/21392294 func reservedLabel(x: Int, `repeat`: Bool) {} -reservedLabel(1, true) // expected-error{{missing argument label 'repeat:' in call}}{{18-18=`repeat`: }} +reservedLabel(1, true) // expected-error{{missing argument label 'repeat:' in call}}{{18-18=repeat: }} // Insert missing keyword before initial backtick. rdar://problem/21392294 part 2 func reservedExpr(x: Int, y: Int) {} diff --git a/test/Constraints/lvalues.swift b/test/Constraints/lvalues.swift index 2e64cfd6eef2c..b586296b459a8 100644 --- a/test/Constraints/lvalues.swift +++ b/test/Constraints/lvalues.swift @@ -106,7 +106,7 @@ fref().property = 0.0 f2(&fref().property) f1(&fref().property) fref().property += 0.0 -++fref().property +fref().property += 1 // settable property of a non-settable value type is non-settable: z.non_settable_x.property = 1.0 // expected-error{{cannot assign to property: 'non_settable_x' is a get-only property}} @@ -120,7 +120,7 @@ z.non_settable_reftype.property = 1.0 f2(&z.non_settable_reftype.property) f1(&z.non_settable_reftype.property) z.non_settable_reftype.property += 1.0 -++z.non_settable_reftype.property +z.non_settable_reftype.property += 1 // regressions with non-settable subscripts in value contexts _ = z[0] == 0 diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 0fea005c95214..47321da32585f 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -41,7 +41,7 @@ struct Z { func getI() -> Int { return i } mutating func incI() {} - func curried(x: Int)(y: Int) -> Int { return x + y } // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} + func curried(x: Int) -> (Int) -> Int { return { y in x + y } } subscript (k : Int) -> Int { get { @@ -78,7 +78,7 @@ var incI = z.incI // expected-error{{partial application of 'mutating'}} var zi = z.getI() var zcurried1 = z.curried var zcurried2 = z.curried(0) -var zcurriedFull = z.curried(0)(y: 1) +var zcurriedFull = z.curried(0)(1) //// // Members of modules @@ -110,7 +110,7 @@ enum W { case Omega func foo(x: Int) {} - func curried(x: Int)(y: Int) {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} + func curried(x: Int) -> (Int) -> () {} } var w = W.Omega @@ -118,7 +118,7 @@ var foo = w.foo var fooFull : () = w.foo(0) var wcurried1 = w.curried var wcurried2 = w.curried(0) -var wcurriedFull : () = w.curried(0)(y: 1) +var wcurriedFull : () = w.curried(0)(1) // Member of enum Type func enumMetatypeMember(opt: Int?) { @@ -328,7 +328,7 @@ protocol Functional { func apply(v: Vector) -> Scalar } protocol Coalgebra { - func coproduct(f: Functional)(v1: Vector, v2: Vector) -> Scalar // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} + func coproduct(f: Functional) -> (v1: Vector, v2: Vector) -> Scalar } // Make sure existential is closed early when we partially apply @@ -533,6 +533,10 @@ func f22490787() { } } - +// [QoI] Bad diagnostic when errors inside enum constructor +enum r23942743 { + case Tomato(cloud: String) +} +let _ = .Tomato(cloud: .None) // expected-error {{reference to member 'Tomato' cannot be resolved without a contextual type}} diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index c7a0c3ef6f0ef..d32995531fcae 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -140,7 +140,7 @@ default: break // QoI: Binary operator '~=' cannot be applied to operands of type 'String' and 'String?' switch ("foo" as String?) { -case "what": break // expected-error{{expression pattern of type 'String' cannot match values of type 'String?'}} +case "what": break // expected-error{{value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?}} default: break } @@ -167,8 +167,8 @@ default: break // FIXME: rdar://problem/23378003 // These will eventually become errors. -for (var x) in 0...100 {} // expected-warning {{Use of 'var' binding here is deprecated and will be removed in a future version of Swift}} {{6-9=}} -for var x in 0...100 {} // expected-warning {{Use of 'var' binding here is deprecated and will be removed in a future version of Swift}} {{5-9=}} +for (var x) in 0...100 {} // expected-error {{Use of 'var' binding here is not allowed}} {{6-9=}} +for var x in 0...100 {} // expected-error {{Use of 'var' binding here is not allowed}} {{5-9=}} for (let x) in 0...100 {} // expected-error {{'let' pattern is already in an immutable context}} @@ -181,7 +181,7 @@ let (var z) = 42 // expected-error {{'var' cannot appear nested inside another // at least we don't crash anymore. protocol PP { - typealias E + associatedtype E } struct A : PP { @@ -209,16 +209,14 @@ func good(a: A) -> Int { } func bad(a: A) { - a.map { // expected-error {{cannot invoke 'map' with an argument list of type '((EE) -> _)'}} - // expected-note@-1 {{expected an argument list of type '(EE -> T)'}} + a.map { // expected-error {{generic parameter 'T' could not be inferred}} let _: EE = $0 return 1 } } func ugly(a: A) { - a.map { // expected-error {{cannot invoke 'map' with an argument list of type '((EE) -> _)'}} - // expected-note@-1 {{expected an argument list of type '(EE -> T)'}} + a.map { // expected-error {{generic parameter 'T' could not be inferred}} switch $0 { case .A: return 1 diff --git a/test/Constraints/protocols.swift b/test/Constraints/protocols.swift index bdc3b3b2ce501..7351b1772708c 100644 --- a/test/Constraints/protocols.swift +++ b/test/Constraints/protocols.swift @@ -32,9 +32,9 @@ var i : Int var f : Float var b : Barable -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Conversion to and among existential types -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// f0(i) f0(f) @@ -44,9 +44,9 @@ f1(i) f1(f) // expected-error{{argument type 'Float' does not conform to expected type 'protocol'}} f1(b) // expected-error{{argument type 'Barable' does not conform to expected type 'protocol'}} -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Subtyping -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// g(f0) // okay (subtype) g(f1) // okay (exact match) @@ -93,9 +93,9 @@ let _: () -> Int = { return "" } -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Dynamic self -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// protocol Clonable { func maybeClone() -> Self? func badMaybeClone() -> Self?? diff --git a/test/Constraints/same_types.swift b/test/Constraints/same_types.swift index 9f181ad6a7838..8fb8039861ade 100644 --- a/test/Constraints/same_types.swift +++ b/test/Constraints/same_types.swift @@ -1,13 +1,13 @@ // RUN: %target-parse-verify-swift protocol Fooable { - typealias Foo + associatedtype Foo var foo: Foo { get } } protocol Barrable { - typealias Bar: Fooable + associatedtype Bar: Fooable var bar: Bar { get } } diff --git a/test/Constraints/subscript.swift b/test/Constraints/subscript.swift index 0dd8afcc8af05..a04c62d0568a2 100644 --- a/test/Constraints/subscript.swift +++ b/test/Constraints/subscript.swift @@ -72,8 +72,7 @@ let _ = 1["1"] // expected-error {{ambiguous use of 'subscript'}} // rdar://17687826 - QoI: error message when reducing to an untyped dictionary isn't helpful -let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in // expected-error {{cannot invoke 'reduce' with an argument list of type '([_ : _], @noescape (_, Int) throws -> _)'}} - // expected-note @-1 {{expected an argument list of type '(T, combine: @noescape (T, Int) throws -> T)'}} +let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in // expected-error {{expression type '[_ : _]' is ambiguous without more context}} var dict = dict dict[n] = n * n diff --git a/test/Constraints/tuple.swift b/test/Constraints/tuple.swift index e40631c459022..b52fb97b70ca7 100644 --- a/test/Constraints/tuple.swift +++ b/test/Constraints/tuple.swift @@ -24,9 +24,9 @@ func f5(x: (Int, Int)) {} func f6(_: (i: Int, j: Int), k: Int = 15) {} -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Conversions and shuffles -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // Variadic functions. f4() @@ -72,11 +72,13 @@ extension Int : PosixErrorReturn { } func posixCantFail> - (f:(A) -> T)(args:A) -> T // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} + (f:(A) -> T) -> (args:A) -> T { - let result = f(args) - assert(result != T.errorReturnValue()) - return result + return { args in + let result = f(args) + assert(result != T.errorReturnValue()) + return result + } } func open(name: String, oflag: Int) -> Int { } @@ -151,4 +153,30 @@ func gcd_23700031(a: T, b: T) { // expected-note @-1 {{overloads for '%' exist with these partially matching parameter lists: (UInt8, UInt8), (Int8, Int8), (UInt16, UInt16), (Int16, Int16), (UInt32, UInt32), (Int32, Int32), (UInt64, UInt64), (Int64, Int64), (UInt, UInt), (Int, Int), (Float, Float)}} } +// +// Don't ignore tuple labels in same-type constraints or stronger. +protocol Kingdom { + associatedtype King +} +struct Victory { + init(_ king: K) {} +} +struct MagicKingdom : Kingdom { + typealias King = K +} +func magify(t: T) -> MagicKingdom { return MagicKingdom() } +func foo(pair: (Int,Int)) -> Victory<(x:Int, y:Int)> { + return Victory(magify(pair)) // expected-error {{cannot convert return expression of type 'Victory<(Int, Int)>' to return type 'Victory<(x: Int, y: Int)>'}} +} + + +// https://bugs.swift.org/browse/SR-596 +// Compiler crashes when accessing a non-existent property of a closure parameter +func call(f: C -> Void) {} +func makeRequest() { + call { obj in + print(obj.invalidProperty) // expected-error {{value of type 'C' has no member 'invalidProperty'}} + } +} + diff --git a/test/DebugInfo/ASTSection_ObjC.swift b/test/DebugInfo/ASTSection_ObjC.swift index 705932dec06de..d4e9a9566f606 100644 --- a/test/DebugInfo/ASTSection_ObjC.swift +++ b/test/DebugInfo/ASTSection_ObjC.swift @@ -11,7 +11,7 @@ // RUN: %lldb-moduleimport-test %t/ASTSection | FileCheck %s --allow-empty --check-prefix=LINETABLE-CHECK // REQUIRES: executable_test -// UNSUPPORTED: OS=linux-gnu +// REQUIRES: objc_interop // CHECK: Loaded module ASTSection from // CHECK: - Target: {{.+}}-{{.+}}-{{.+}} diff --git a/test/DebugInfo/Destructors.swift b/test/DebugInfo/Destructors.swift index 278822be9e7ea..277aae6fbdc6c 100644 --- a/test/DebugInfo/Destructors.swift +++ b/test/DebugInfo/Destructors.swift @@ -1,15 +1,9 @@ // RUN: %target-swift-frontend %s -emit-ir -g -o - | FileCheck %s -func markUsed(t: T) {} - -class Foo { +public class Foo { // CHECK: !DISubprogram(name: "deinit", linkageName: "_TFC11Destructors3FooD" // CHECK-SAME: line: [[@LINE-2]] // CHECK-SAME: isDefinition: true var x : Int64 init(x: Int64) { self.x = x } - func bar() -> (() -> ()) { return { markUsed(self.x) } } } - -var f = Foo(x: 1) -f.bar()() diff --git a/test/DebugInfo/DoubleCapture.swift b/test/DebugInfo/DoubleCapture.swift new file mode 100644 index 0000000000000..5f34ae4f28cd2 --- /dev/null +++ b/test/DebugInfo/DoubleCapture.swift @@ -0,0 +1,12 @@ +// RUN: %target-swift-frontend %s -emit-ir -g -o - | FileCheck %s +class C { + func foo() { + func bar() { + self.foo() + } + // Yes, there are really two arguments called self in this example! + // CHECK: (name: "self", arg: 1, scope: ![[SCOPE:[0-9]+]], {{.*}}line: 10, + // CHECK: (name: "self", arg: 2, scope: ![[SCOPE]], {{.*}}line: 3, + {[weak self] in _ = self!; bar() }() + } +} diff --git a/test/DebugInfo/ImportClangSubmodule.swift b/test/DebugInfo/ImportClangSubmodule.swift new file mode 100644 index 0000000000000..87c44836da25e --- /dev/null +++ b/test/DebugInfo/ImportClangSubmodule.swift @@ -0,0 +1,13 @@ +// RUN: rm -rf %t && mkdir -p %t +// REQUIRES: OS=macosx + +// RUN: %target-swift-frontend -emit-ir %s -g -o - | FileCheck %s + +// CHECK: !DIImportedEntity( +// CHECK: tag: DW_TAG_imported_module{{.*}}entity: ![[C:.*]], line: [[@LINE+1]]) +import Darwin.C + +let irrational = sqrt(2 as Double) + +// CHECK: ![[C]] = !DIModule(scope: ![[Darwin:.*]], name: "C", +// CHECK: ![[Darwin]] = !DIModule(scope: null, name: "Darwin", diff --git a/test/DebugInfo/ProtocolContainer.swift b/test/DebugInfo/ProtocolContainer.swift index 66a82093dd804..7077cee6eedbd 100644 --- a/test/DebugInfo/ProtocolContainer.swift +++ b/test/DebugInfo/ProtocolContainer.swift @@ -14,7 +14,6 @@ class AClass : AProtocol { // CHECK: define hidden void @_TF17ProtocolContainer3foo // CHECK-NEXT: entry: // CHECK: [[XADDR:[%].*]] = alloca %P17ProtocolContainer9AProtocol_*, align {{(4|8)}} -// CHECK: %.metadata1 = alloca %swift.type*, align {{(4|8)}} // CHECK: store %P17ProtocolContainer9AProtocol_* %0, %P17ProtocolContainer9AProtocol_** [[XADDR]], align {{(4|8)}} // CHECK: call void @llvm.dbg.declare(metadata %P17ProtocolContainer9AProtocol_** [[XADDR]], metadata ![[XMD:.*]], metadata !{{[0-9]+}}) // CHECK-NOT: !DILocalVariable({{.*}} name: "x" diff --git a/test/DebugInfo/WeakCapture.swift b/test/DebugInfo/WeakCapture.swift new file mode 100644 index 0000000000000..e275b3193021e --- /dev/null +++ b/test/DebugInfo/WeakCapture.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend %s -emit-ir -g -o - | FileCheck %s +class A { + init(handler: (() -> ())) { } +} + +class B { } + +// CHECK: define {{.*}} @_TF11WeakCapture8functionFT_T_() +func function() { + let b = B() + + // Ensure that the local b and its weak copy are distinct local variables. + // CHECK: %[[B:.*]] = alloca %C11WeakCapture1B* + // CHECK: %[[BWEAK:.*]] = alloca %swift.weak* + // CHECK: call void @llvm.dbg.declare({{.*}}[[B]] + // CHECK: call void @llvm.dbg.declare({{.*}}[[BWEAK]] + A(handler: { [weak b] _ in + if b != nil { } + }) +} + +function() diff --git a/test/DebugInfo/anonymous.swift b/test/DebugInfo/anonymous.swift index a0d2ae12a250b..7e94b1a7e5a13 100644 --- a/test/DebugInfo/anonymous.swift +++ b/test/DebugInfo/anonymous.swift @@ -1,22 +1,10 @@ // RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | FileCheck %s -// Don't crash when emitting debug info for anonymous variables. -// CHECK: !DILocalVariable(name: "_" +// CHECK: !DILocalVariable(name: "_0", arg: 1 +// CHECK: !DILocalVariable(name: "_1", arg: 2 +// CHECK: !DILocalVariable(name: "_2", arg: 3 +// CHECK: !DILocalVariable(name: "x4", arg: 4 -func markUsed(t: T) {} - -protocol F_ { - func successor() -> Self -} - -protocol F : F_ { - func ~> (_: Self, _: (_Distance, (Self))) -> Int64 -} - -struct _Distance {} - -func ~> (self_:I, _: (_Distance, (I))) -> Int64 { - self_.successor() - markUsed("F") - return 0 +public func fourth(_: T, _: T, _: T, x4 : T) -> T { + return x4 } diff --git a/test/DebugInfo/arg-debug_value.swift b/test/DebugInfo/arg-debug_value.swift index b93de74330360..989cd6c138669 100644 --- a/test/DebugInfo/arg-debug_value.swift +++ b/test/DebugInfo/arg-debug_value.swift @@ -5,11 +5,11 @@ var g: Int64 = 1 class Foo { - var x: Int64 + var x: Int64 // CHECK: define {{.*}}_TFC4main3FoocfT_S0_ // CHECK: entry: // CHECK-NEXT: %[[SELF:.*]] = alloca // CHECK-NEXT: store %C4main3Foo* %0, %C4main3Foo** %[[SELF]] // CHECK-NEXT: call void @llvm.dbg.declare({{.*}}%[[SELF]] - init () { x = g++ } + init () { x = g; g += 1 } } diff --git a/test/DebugInfo/argument.swift b/test/DebugInfo/argument.swift index d9cb85318472d..a1a7803f5c9b7 100644 --- a/test/DebugInfo/argument.swift +++ b/test/DebugInfo/argument.swift @@ -54,15 +54,8 @@ class A { } -// Curried functions have their arguments backwards. -// CHECK: !DILocalVariable(name: "b", arg: 1,{{.*}} line: [[@LINE+2]] -// CHECK: !DILocalVariable(name: "a", arg: 2,{{.*}} line: [[@LINE+1]] -func uncurry (a: Int64) (b: Int64) -> (Int64, Int64) { - return (a, b) -} - // CHECK: !DILocalVariable(name: "x", arg: 1,{{.*}} line: [[@LINE+2]] // CHECK: !DILocalVariable(name: "y", arg: 2,{{.*}} line: [[@LINE+1]] func tuple(x: Int64, y: (Int64, Float, String)) -> Int64 { - return x+y.0; + return x+y.0 } diff --git a/test/DebugInfo/autoclosure.swift b/test/DebugInfo/autoclosure.swift index d9c3d2f7aa59b..4ca64d7bd109d 100644 --- a/test/DebugInfo/autoclosure.swift +++ b/test/DebugInfo/autoclosure.swift @@ -17,7 +17,7 @@ infix operator &&&&& { precedence 120 } -func &&&&&(lhs: BooleanType, @autoclosure rhs: ()->BooleanType) -> Bool { +func &&&&&(lhs: BooleanType, @autoclosure rhs: () -> BooleanType) -> Bool { return lhs.boolValue ? rhs().boolValue : false } diff --git a/test/DebugInfo/bound-namealiastype.swift b/test/DebugInfo/bound-namealiastype.swift index a80ea431e2b6a..2e13e3f903a1d 100644 --- a/test/DebugInfo/bound-namealiastype.swift +++ b/test/DebugInfo/bound-namealiastype.swift @@ -1,13 +1,15 @@ // RUN: %target-swift-frontend -emit-ir -g %s -o - | FileCheck %s -// REQUIRES: objc_interop - -import Dispatch - -func markUsed(t: T) {} - -// CHECK-DAG: !DICompositeType(tag: DW_TAG_union_type, {{.*}}identifier: "_TtGSQaSC16dispatch_queue_t_" -// CHECK-DAG: !DIGlobalVariable(name: "queue",{{.*}} line: [[@LINE+1]], type: !"_TtGSQaSC16dispatch_queue_t_" -var queue = dispatch_queue_create("queue", nil) - -dispatch_sync(queue) { markUsed("Hello world"); } +public protocol OS_dispatch_queue { +} +public typealias dispatch_queue_t = OS_dispatch_queue + +func dispatch_queue_create() -> dispatch_queue_t! { + return nil +} + +// CHECK: !DICompositeType(tag: DW_TAG_union_type, +// CHECK-SAME: identifier: "_TtGSQa4main16dispatch_queue_t_" +// CHECK: !DIGlobalVariable(name: "queue", +// CHECK-SAME: line: [[@LINE+1]], type: !"_TtGSQa4main16dispatch_queue_t_" +public var queue = dispatch_queue_create() diff --git a/test/DebugInfo/byref-capture.swift b/test/DebugInfo/byref-capture.swift index b35f0471dee3f..8d97581b55c4b 100644 --- a/test/DebugInfo/byref-capture.swift +++ b/test/DebugInfo/byref-capture.swift @@ -7,10 +7,11 @@ func makeIncrementor(inc : Int64) -> () -> Int64 func inner() -> Int64 { // CHECK: call void @llvm.dbg.declare(metadata %Vs5Int64** // CHECK-SAME: metadata ![[SUM_CAPTURE:[0-9]+]], - // CHECK-SAME: metadata ![[DEREF:[0-9]+]]) - // CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref) - // CHECK: ![[SUM_CAPTURE]] = !DILocalVariable(name: "sum", - // CHECK-SAME: line: [[@LINE-8]] + // CHECK-SAME: metadata ![[EMPTY:.*]]) + // CHECK: ![[EMPTY]] = !DIExpression() + // CHECK: ![[SUM_CAPTURE]] = !DILocalVariable(name: "sum", arg: 1, + // CHECK-SAME: line: [[@LINE-8]], type: !"_TtRVs5Int64" + // ^ inout type. sum += inc return sum } diff --git a/test/DebugInfo/closure.swift b/test/DebugInfo/closure.swift index e175948b8fb19..73380d0da2574 100644 --- a/test/DebugInfo/closure.swift +++ b/test/DebugInfo/closure.swift @@ -5,7 +5,7 @@ func markUsed(t: T) {} func foldl1(list: [T], _ function: (a: T, b: T) -> T) -> T { assert(list.count > 1) var accumulator = list[0] - for var i = 1; i < list.count; ++i { + for var i = 1; i < list.count; i += 1 { accumulator = function(a: accumulator, b: list[i]) } return accumulator diff --git a/test/DebugInfo/for.swift b/test/DebugInfo/for.swift index 69926ebdfcc04..5a2bf3709831b 100644 --- a/test/DebugInfo/for.swift +++ b/test/DebugInfo/for.swift @@ -2,11 +2,11 @@ // Verify that variables bound in the for statements are in distinct scopes. -for var i = 0; i < 3; ++i { +for var i = 0; i < 3; i += 1 { // CHECK: !DILocalVariable(name: "i", scope: ![[SCOPE1:[0-9]+]] // CHECK: ![[SCOPE1]] = distinct !DILexicalBlock(scope: ![[MAIN:[0-9]+]] } -for var i = 0; i < 3; ++i { +for var i = 0; i < 3; i += 1 { // CHECK: !DILocalVariable(name: "i", scope: ![[SCOPE2:[0-9]+]] // CHECK: ![[SCOPE2]] = distinct !DILexicalBlock(scope: ![[MAIN]] } diff --git a/test/DebugInfo/generic_args.swift b/test/DebugInfo/generic_args.swift index 1eeeefbc587d1..bd07b059d9fdd 100644 --- a/test/DebugInfo/generic_args.swift +++ b/test/DebugInfo/generic_args.swift @@ -3,7 +3,7 @@ func markUsed(t: T) {} protocol AProtocol { - func f() -> String; + func f() -> String } class AClass : AProtocol { func f() -> String { return "A" } @@ -45,7 +45,7 @@ struct Wrapper { } // CHECK: !DILocalVariable(name: "f", {{.*}}, line: [[@LINE+1]], type: !"_TtFQq_F12generic_args5applyu0_rFTx1fFxq__q_Qq0_F12generic_args5applyu0_rFTx1fFxq__q_") -func apply (x: T, f: (T)->(U)) -> U { +func apply (x: T, f: (T) -> (U)) -> U { return f(x) } diff --git a/test/DebugInfo/inlinescopes.swift b/test/DebugInfo/inlinescopes.swift index ac8685687c371..66cf4921e9f2c 100644 --- a/test/DebugInfo/inlinescopes.swift +++ b/test/DebugInfo/inlinescopes.swift @@ -5,7 +5,7 @@ // RUN: FileCheck %s < %t.ll // RUN: FileCheck %s -check-prefix=TRANSPARENT-CHECK < %t.ll -// CHECK: define i32 @main +// CHECK: define{{( signext)?}} i32 @main // CHECK: tail call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %[[C:.*]], i64 %[[C]]), !dbg ![[MULSCOPE:.*]] // CHECK-DAG: ![[TOPLEVEL:.*]] = !DIFile(filename: "inlinescopes.swift" diff --git a/test/DebugInfo/linetable-cleanups.swift b/test/DebugInfo/linetable-cleanups.swift index 3e6c589b687d7..1c31fc846959d 100644 --- a/test/DebugInfo/linetable-cleanups.swift +++ b/test/DebugInfo/linetable-cleanups.swift @@ -23,6 +23,12 @@ func main() { // The cleanups should share the line number with the ret stmt. // CHECK: call void {{.*}}elease({{.*}}) {{#[0-9]+}}, !dbg ![[CLEANUPS:.*]] // CHECK-NEXT: !dbg ![[CLEANUPS]] +// CHECK-NEXT: bitcast +// CHECK-NEXT: llvm.lifetime.end +// CHECK-NEXT: bitcast +// CHECK-NEXT: llvm.lifetime.end +// CHECK-NEXT: bitcast +// CHECK-NEXT: llvm.lifetime.end // CHECK-NEXT: ret void, !dbg ![[CLEANUPS]] // CHECK: ![[CLEANUPS]] = !DILocation(line: [[@LINE+1]], column: 1, } diff --git a/test/DebugInfo/linetable.swift b/test/DebugInfo/linetable.swift index 821b12fc1b93b..e89548ac50b2b 100644 --- a/test/DebugInfo/linetable.swift +++ b/test/DebugInfo/linetable.swift @@ -12,7 +12,7 @@ class MyClass init(input: Int64) { x = input } func do_something(input: Int64) -> Int64 { - return x * input; + return x * input } } @@ -35,6 +35,8 @@ func main(x: Int64) -> Void markUsed(result) // CHECK: call {{.*}} @swift_release {{.*}} // CHECK: call {{.*}} @swift_release {{.*}}, !dbg ![[CLOSURE_END:.*]] +// CHECK-NEXT: bitcast +// CHECK-NEXT: llvm.lifetime.end // CHECK-NEXT: ret void, !dbg ![[CLOSURE_END]] // CHECK: ![[CLOSURE_END]] = !DILocation(line: [[@LINE+1]], } diff --git a/test/DebugInfo/nested_functions.swift b/test/DebugInfo/nested_functions.swift index 34e3376166adf..6b9063a90e911 100644 --- a/test/DebugInfo/nested_functions.swift +++ b/test/DebugInfo/nested_functions.swift @@ -1,10 +1,13 @@ // RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | FileCheck %s +// CHECK: ![[OUTER:.*]] = distinct !DISubprogram(name: "outer", +// CHECK-SAME: line: [[@LINE+1]] func outer(a: Int64) -> Int64 { // Inner functions have a linkage name of "closure[0-9]+", but // their DW_AT_name is preserved. - // CHECK: !DISubprogram(name: "inner", linkageName: "_TFF16nested_functions5outerFVs5Int64S0_L_5innerfS0_S0_" + // CHECK: !DISubprogram(name: "inner", + // CHECK-SAME: scope: ![[OUTER]] // CHECK-SAME: line: [[@LINE+1]] func inner(b: Int64) -> Int64 { return a+b diff --git a/test/DebugInfo/patternmatching.swift b/test/DebugInfo/patternmatching.swift index 920bd8915dcbd..a9dc292f8731d 100644 --- a/test/DebugInfo/patternmatching.swift +++ b/test/DebugInfo/patternmatching.swift @@ -8,7 +8,7 @@ func markUsed(t: T) {} func classifyPoint2(p: (Double, Double)) { func return_same (input : Double) -> Double { var input = input - return input; + return input } switch p { diff --git a/test/DebugInfo/protocol.swift b/test/DebugInfo/protocol.swift index 2633470156f42..2134915a91ef5 100644 --- a/test/DebugInfo/protocol.swift +++ b/test/DebugInfo/protocol.swift @@ -9,8 +9,8 @@ class Point : PointUtils { var x : Float var y : Float init (_x : Float, _y : Float) { - x = _x; - y = _y; + x = _x + y = _y } func distanceFromOrigin() -> Float { diff --git a/test/DebugInfo/protocolarg.swift b/test/DebugInfo/protocolarg.swift index 0da94ab48fcfe..9920a82bf0b28 100644 --- a/test/DebugInfo/protocolarg.swift +++ b/test/DebugInfo/protocolarg.swift @@ -2,27 +2,27 @@ func markUsed(t: T) {} -// FIXME: Should be DW_TAG_interface_type -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "IGiveOutInts" -// CHECK-SAME: identifier: [[PT:"[^"]+"]] -protocol IGiveOutInts { +public protocol IGiveOutInts { func callMe() -> Int64 } -class SomeImplementor : IGiveOutInts { - init() {} - func callMe() -> Int64 { return 1 } -} +// CHECK: define {{.*}}@_TF11protocolarg16printSomeNumbersFPS_12IGiveOutInts_T_ +// CHECK: @llvm.dbg.declare(metadata %P11protocolarg12IGiveOutInts_* % +// CHECK-SAME: metadata ![[VAR:.*]], metadata ![[EMPTY:.*]]) +// CHECK: @llvm.dbg.declare(metadata %P11protocolarg12IGiveOutInts_** % +// CHECK-SAME: metadata ![[ARG:.*]], metadata ![[DEREF:.*]]) + +// FIXME: Should be DW_TAG_interface_type +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "IGiveOutInts" +// CHECK-SAME: identifier: [[PT:"[^"]+"]] -func printSomeNumbers(gen: IGiveOutInts) { +public func printSomeNumbers(gen: IGiveOutInts) { var gen = gen - // CHECK: !DILocalVariable(name: "gen", scope{{.*}} line: [[@LINE-1]] - // CHECK: !DILocalVariable(name: "gen", arg: 1{{.*}} line: [[@LINE-3]] - // CHECK-SAME: type: ![[PT]] + // CHECK: ![[EMPTY]] = !DIExpression() + // CHECK: ![[VAR]] = !DILocalVariable(name: "gen", {{.*}} line: [[@LINE-2]] + // CHECK: ![[ARG]] = !DILocalVariable(name: "gen", arg: 1, + // CHECK-SAME: line: [[@LINE-5]], type: ![[PT]] + // CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref) markUsed(gen.callMe()) } -var i1 : IGiveOutInts = SomeImplementor() - -printSomeNumbers(i1) - diff --git a/test/DebugInfo/return.swift b/test/DebugInfo/return.swift index d59aecbeb6bf7..1554959dd5898 100644 --- a/test/DebugInfo/return.swift +++ b/test/DebugInfo/return.swift @@ -7,15 +7,15 @@ class X { // CHECK: define {{.*}}ifelseexpr public func ifelseexpr() -> Int64 { - var x = X(i:0); + var x = X(i:0) // CHECK: [[META:%.*]] = call %swift.type* @_TMaC6return1X() // CHECK: [[X:%.*]] = call %C6return1X* @_TFC6return1XCfT1iVs5Int64_S0_( // CHECK-SAME: i64 0, %swift.type* [[META]]) // CHECK: @swift_release to void (%C6return1X*)*)(%C6return1X* [[X]]) if true { - x.x++; + x.x += 1 } else { - x.x--; + x.x -= 1 } // CHECK: @swift_release to void (%C6return1X*)*)(%C6return1X* [[X]]) // CHECK: @swift_release to void (%C6return1X*)*)(%C6return1X* [[X]]) @@ -23,6 +23,6 @@ public func ifelseexpr() -> Int64 { // The ret instruction should be in the same scope as the return expression. // CHECK: ret{{.*}}, !dbg ![[RELEASE]] - return x.x; // CHECK: ![[RELEASE]] = !DILocation(line: [[@LINE]], column: 3 + return x.x // CHECK: ![[RELEASE]] = !DILocation(line: [[@LINE]], column: 3 } diff --git a/test/DebugInfo/returnlocation.swift b/test/DebugInfo/returnlocation.swift index 44e856410b72e..b7f62d6f580bb 100644 --- a/test/DebugInfo/returnlocation.swift +++ b/test/DebugInfo/returnlocation.swift @@ -13,7 +13,7 @@ import Foundation public func none(inout a: Int64) { // CHECK_NONE: call void @llvm.dbg{{.*}}, !dbg // CHECK_NONE: !dbg ![[NONE_INIT:.*]] - a -= 2; + a -= 2 // CHECK_NONE: ret {{.*}}, !dbg ![[NONE_RET:.*]] // CHECK_NONE: ![[NONE_INIT]] = !DILocation(line: [[@LINE-2]], column: // CHECK_NONE: ![[NONE_RET]] = !DILocation(line: [[@LINE+1]], column: 1, @@ -28,7 +28,7 @@ public func empty(inout a: Int64) { return } - a -= 2; + a -= 2 // CHECK-DAG_EMPTY: br {{.*}}, !dbg ![[EMPTY_RET2:.*]] // CHECK-DAG_EMPTY_RET2: ![[EMPTY_RET]] = !DILocation(line: [[@LINE+1]], column: 3, return @@ -40,10 +40,10 @@ public func empty(inout a: Int64) { // CHECK_EMPTY_NONE: define {{.*}}empty_none public func empty_none(inout a: Int64) { if a > 24 { - return; + return } - a -= 2; + a -= 2 // CHECK_EMPTY_NONE: ret {{.*}}, !dbg ![[EMPTY_NONE_RET:.*]] // CHECK_EMPTY_NONE: ![[EMPTY_NONE_RET]] = !DILocation(line: [[@LINE+1]], column: 1, } @@ -52,7 +52,7 @@ public func empty_none(inout a: Int64) { // CHECK_SIMPLE_RET: define {{.*}}simple public func simple(a: Int64) -> Int64 { if a > 24 { - return 0; + return 0 } return 1 // CHECK_SIMPLE_RET: ret i{{.*}}, !dbg ![[SIMPLE_RET:.*]] @@ -108,7 +108,7 @@ public func cleanup_none(inout a: NSString) { // CHECK_CLEANUP_EMPTY: define {{.*}}cleanup_empty public func cleanup_empty(inout a: NSString) { if a.length > 24 { - return; + return } a = "empty" @@ -121,7 +121,7 @@ public func cleanup_empty(inout a: NSString) { // CHECK_CLEANUP_EMPTY_NONE: define {{.*}}cleanup_empty_none public func cleanup_empty_none(inout a: NSString) { if a.length > 24 { - return; + return } a = "empty" diff --git a/test/DebugInfo/specialization.swift b/test/DebugInfo/specialization.swift new file mode 100644 index 0000000000000..42ae73e19766a --- /dev/null +++ b/test/DebugInfo/specialization.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-frontend -O %s -disable-llvm-optzns -emit-sil -g -o - | FileCheck %s + +// CHECK: sil shared [noinline] @_TTSg5SiSis21IntegerArithmeticTypes__ +// CHECK-SAME: _TF14specialization3sumuRxs21IntegerArithmeticTyperFTxx_x +// CHECK-SAME: $@convention(thin) (@out Int, @in Int, @in Int) -> () { +// CHECK: bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int): +// CHECK: debug_value_addr %1 : $*Int, let, name "i", argno 1 +// CHECK: debug_value_addr %2 : $*Int, let, name "j", argno 2 + +@inline(never) +public func sum(i : T, _ j : T) -> T { + let result = i + j + return result +} + +public func inc(inout i : Int) { + i = sum(i, 1) +} diff --git a/test/DebugInfo/trap-optimized.swift b/test/DebugInfo/trap-optimized.swift index a05a38d904b6c..22663aaf96e1a 100644 --- a/test/DebugInfo/trap-optimized.swift +++ b/test/DebugInfo/trap-optimized.swift @@ -1,13 +1,14 @@ // RUN: %target-swift-frontend -O -primary-file %s -emit-ir -g -o - | FileCheck %s - +import StdlibUnittest // CHECK-LABEL: define{{.*}}2fn -func fn() { - print("two") -// CHECK-DAG: ![[LOC:.*]] = !DILocation(line: [[@LINE+1]], column: 11, - print(0 - UInt(Process.arguments.count)) -// CHECK-DAG: ![[LOC2:.*]] = !DILocation(line: [[@LINE+1]], column: 11, - print(1 - UInt(Process.arguments.count)) - print("three") +public var i : UInt32 = 1 +public func fn() { + _blackHole(i) +// CHECK-DAG: ![[LOC:.*]] = !DILocation(line: [[@LINE+1]], column: 16, + _blackHole(0 - i) +// CHECK-DAG: ![[LOC2:.*]] = !DILocation(line: [[@LINE+1]], column: 16, + _blackHole(0 - i) + _blackHole(i) } // CHECK-DAG: call void @llvm.trap(), !dbg ![[LOC]] diff --git a/test/DebugInfo/typearg.swift b/test/DebugInfo/typearg.swift index d6a6ea4d1f7e3..e533a250098ee 100644 --- a/test/DebugInfo/typearg.swift +++ b/test/DebugInfo/typearg.swift @@ -1,7 +1,7 @@ // RUN: %target-swift-frontend %s -emit-ir -g -o - | FileCheck %s protocol AProtocol { - func f() -> String; + func f() -> String } class AClass : AProtocol { func f() -> String { return "A" } diff --git a/test/DebugInfo/value-update.sil b/test/DebugInfo/value-update.sil new file mode 100644 index 0000000000000..af6b1cf34475a --- /dev/null +++ b/test/DebugInfo/value-update.sil @@ -0,0 +1,47 @@ +// RUN: %target-swift-frontend %s -emit-ir -module-name test -g -o - | FileCheck %s +// REQUIRES: CPU=x86_64 +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +// test.foo () -> () +sil @_TF4test3fooFT_T_ : $@convention(thin) () -> () { +bb0: + %1 = integer_literal $Builtin.Int64, 23 + %2 = struct $Int (%1 : $Builtin.Int64) + debug_value %2 : $Int, var, name "v" + // CHECK: store i64 23, i64* %[[ALLOCA:.*]], align 8, !dbg + // CHECK: dbg.declare + // function_ref StdlibUnittest._blackHole (A) -> () + %5 = function_ref @_TF14StdlibUnittest10_blackHoleurFxT_ : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () // user: %8 + %6 = tuple () + %7 = alloc_stack $() // users: %8, %9 + %8 = apply %5<()>(%7) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + dealloc_stack %7 : $*() // id: %9 + + // CHECK: store i64 42, i64* %[[ALLOCA]], align 8, !dbg + // CHECK-NOT: dbg.declare + %9 = integer_literal $Builtin.Int64, 42 // user: %10 + %10 = struct $Int (%9 : $Builtin.Int64) // user: %11 + debug_value %10 : $Int, var, name "v" + + // function_ref StdlibUnittest._blackHole (A) -> () + %13 = function_ref @_TF14StdlibUnittest10_blackHoleurFxT_ : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () // user: %16 + %14 = tuple () + %15 = alloc_stack $() // users: %16, %17 + %16 = apply %13<()>(%15) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + dealloc_stack %15 : $*() // id: %17 + + %18 = tuple () // user: %21 + return %18 : $() // id: %21 + // CHECK: {{^}}} +} + +// Swift.Int.init (_builtinIntegerLiteral : Builtin.Int2048) -> Swift.Int +sil [transparent] [fragile] @_TFSiCfT22_builtinIntegerLiteralBi2048__Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int + +// StdlibUnittest._blackHole (A) -> () +sil @_TF14StdlibUnittest10_blackHoleurFxT_ : $@convention(thin) <τ_0_0> (@in τ_0_0) -> () + diff --git a/test/DebugInfo/variables.swift b/test/DebugInfo/variables.swift index 760d07fb041bf..f4d22b420a48a 100644 --- a/test/DebugInfo/variables.swift +++ b/test/DebugInfo/variables.swift @@ -3,7 +3,7 @@ // Ensure that the debug info we're emitting passes the back end verifier. // RUN: %target-swift-frontend %s -g -S -o - | FileCheck %s --check-prefix ASM-%target-object-format // ASM-macho: .section __DWARF,__debug_info -// ASM-elf: .section .debug_info,"",@progbits +// ASM-elf: .section .debug_info,"",{{[@%]}}progbits // Test variables-interpreter.swift runs this code with `swift -g -i`. // Test variables-repl.swift runs this code with `swift -g < variables.swift`. @@ -11,17 +11,17 @@ // CHECK-DAG: ![[TLC:.*]] = !DIModule({{.*}}, name: "variables" // Global variables. -var glob_i8: Int8 = 8; +var glob_i8: Int8 = 8 // CHECK-DAG: !DIGlobalVariable(name: "glob_i8",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[I8:[^,]+]] -var glob_i16: Int16 = 16; +var glob_i16: Int16 = 16 // CHECK-DAG: !DIGlobalVariable(name: "glob_i16",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[I16:[^,]+]] -var glob_i32: Int32 = 32; +var glob_i32: Int32 = 32 // CHECK-DAG: !DIGlobalVariable(name: "glob_i32",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[I32:[^,]+]] -var glob_i64: Int64 = 64; +var glob_i64: Int64 = 64 // CHECK-DAG: !DIGlobalVariable(name: "glob_i64",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[I64:[^,]+]] -var glob_f: Float = 2.89; +var glob_f: Float = 2.89 // CHECK-DAG: !DIGlobalVariable(name: "glob_f",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[F:[^,]+]] -var glob_d: Double = 3.14; +var glob_d: Double = 3.14 // CHECK-DAG: !DIGlobalVariable(name: "glob_d",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[D:[^,]+]] var glob_b: Bool = true // CHECK-DAG: !DIGlobalVariable(name: "glob_b",{{.*}} scope: ![[TLC]],{{.*}} line: [[@LINE-1]],{{.*}} type: ![[B:[^,]+]] @@ -47,10 +47,10 @@ var unused: Int32 = -1 func foo(dt: Float) -> Float { // CHECK-DAG: call void @llvm.dbg.declare // CHECK-DAG: !DILocalVariable(name: "f" - var f: Float = 9.78; + var f: Float = 9.78 // CHECK-DAG: !DILocalVariable(name: "r" - var r: Float = f*dt; - return r; + var r: Float = f*dt + return r } var g = foo(1.0); diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 36efbf6ed64e9..31d320954ee75 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -100,8 +100,10 @@ _TWPC3foo3barS_8barrables ---> protocol witness table for foo.bar : foo.barrable _TWaC3foo3barS_8barrableS_ ---> protocol witness table accessor for foo.bar : foo.barrable in foo _TWlC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table accessor for type foo.bar and conformance foo.bar : foo.barrable in foo _TWLC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table cache variable for type foo.bar and conformance foo.bar : foo.barrable in foo -_TWDC3foo3barS_8barrableS_ ---> dependent protocol witness table generator for foo.bar : foo.barrable in foo -_TWdC3foo3barS_8barrableS_ ---> dependent protocol witness table template for foo.bar : foo.barrable in foo +_TWGC3foo3barS_8barrableS_ ---> generic protocol witness table for foo.bar : foo.barrable in foo +_TWIC3foo3barS_8barrableS_ ---> instantiation function for generic protocol witness table for foo.bar : foo.barrable in foo +_TWtC3foo3barS_8barrableS_4fred ---> associated type metadata accessor for fred in foo.bar : foo.barrable in foo +_TWTC3foo3barS_8barrableS_4fredS_6thomas ---> associated type witness table accessor for fred : foo.thomas in foo.bar : foo.barrable in foo _TFSCg5greenVSC5Color ---> __C.green.getter : __C.Color _TIF1t1fFT1iSi1sSS_T_A_ ---> t.(f (i : Swift.Int, s : Swift.String) -> ()).(default argument 0) _TIF1t1fFT1iSi1sSS_T_A0_ ---> t.(f (i : Swift.Int, s : Swift.String) -> ()).(default argument 1) @@ -175,7 +177,7 @@ _TF8manglingX27ihqwctvzcJBfGFJdrssDxIboAybFT_T_ ---> mangling.他們爲什麽不 _TF8manglingX30Proprostnemluvesky_uybCEdmaEBaFT_T_ ---> mangling.Pročprostěnemluvíčesky () -> () _TF8manglingXoi7p_qcaDcFTSiSi_Si ---> mangling.«+» infix (Swift.Int, Swift.Int) -> Swift.Int _TF8manglingoi2qqFTSiSi_T_ ---> mangling.?? infix (Swift.Int, Swift.Int) -> () -_TFE11ext_structAV11def_structA1A4testfT_T_ ---> ext.ext_structA.def_structA.A.test () -> () +_TFE11ext_structAV11def_structA1A4testfT_T_ ---> (extension in ext_structA):def_structA.A.test () -> () _TF13devirt_accessP5_DISC15getPrivateClassFT_CS_P5_DISC12PrivateClass ---> devirt_access.(getPrivateClass in _DISC) () -> devirt_access.(PrivateClass in _DISC) _TF4mainP5_mainX3wxaFT_T_ ---> main.(λ in _main) () -> () _TtPMP_ ---> protocol<>.Type @@ -200,8 +202,8 @@ _TTWurGV23interface_type_mangling18GenericTypeContextx_S_18GenericWitnessTestS_F _TTWurGV23interface_type_mangling18GenericTypeContextx_S_18GenericWitnessTestS_FS1_g31closureInGenericPropertyContextwx3Tee ---> protocol witness for interface_type_mangling.GenericWitnessTest.closureInGenericPropertyContext.getter : A.Tee in conformance interface_type_mangling.GenericTypeContext : interface_type_mangling.GenericWitnessTest in interface_type_mangling _TTWurGV23interface_type_mangling18GenericTypeContextx_S_18GenericWitnessTestS_FS1_16twoParamsAtDepthu0_RxS1_rfTqd__1yqd_0__T_ ---> protocol witness for interface_type_mangling.GenericWitnessTest.twoParamsAtDepth (A1, y : B1) -> () in conformance interface_type_mangling.GenericTypeContext : interface_type_mangling.GenericWitnessTest in interface_type_mangling _TFC3red11BaseClassEHcfzT1aSi_S0_ ---> red.BaseClassEH.init (a : Swift.Int) throws -> red.BaseClassEH -_TFe27mangling_generic_extensionsRxS_8RunciblerVS_3Foog1aSi ---> ext.mangling_generic_extensions.mangling_generic_extensions.Foo.a.getter : Swift.Int -_TFe27mangling_generic_extensionsRxS_8RunciblerVS_3Foog1bx ---> ext.mangling_generic_extensions.mangling_generic_extensions.Foo.b.getter : A +_TFe27mangling_generic_extensionsRxS_8RunciblerVS_3Foog1aSi ---> (extension in mangling_generic_extensions):mangling_generic_extensions.Foo.a.getter : Swift.Int +_TFe27mangling_generic_extensionsRxS_8RunciblerVS_3Foog1bx ---> (extension in mangling_generic_extensions):mangling_generic_extensions.Foo.b.getter : A _TTRXFo_iT__iT_zoPs9ErrorType__XFo__dT_zoPS___ ---> reabstraction thunk helper from @callee_owned (@in ()) -> (@out (), @error @owned Swift.ErrorType) to @callee_owned () -> (@unowned (), @error @owned Swift.ErrorType) _TFE1a ---> _TFE1a _TF21$__lldb_module_for_E0au3$E0Ps9ErrorType_ ---> $__lldb_module_for_E0.$E0.unsafeMutableAddressor : Swift.ErrorType diff --git a/test/Demangle/Inputs/simplified-manglings.txt b/test/Demangle/Inputs/simplified-manglings.txt index 19b59ab33881c..5d9aa6e52cd82 100644 --- a/test/Demangle/Inputs/simplified-manglings.txt +++ b/test/Demangle/Inputs/simplified-manglings.txt @@ -93,8 +93,8 @@ _TWPC3foo3barS_8barrables ---> protocol witness table for bar _TWaC3foo3barS_8barrableS_ ---> protocol witness table accessor for bar _TWlC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table accessor for type bar and conformance bar _TWLC3foo3barS0_S_8barrableS_ ---> lazy protocol witness table cache variable for type bar and conformance bar -_TWDC3foo3barS_8barrableS_ ---> dependent protocol witness table generator for bar -_TWdC3foo3barS_8barrableS_ ---> dependent protocol witness table template for bar +_TWGC3foo3barS_8barrableS_ ---> generic protocol witness table for bar +_TWIC3foo3barS_8barrableS_ ---> instantiation function for generic protocol witness table for bar _TFSCg5greenVSC5Color ---> green.getter _TIF1t1fFT1iSi1sSS_T_A_ ---> (f(i : Int, s : String) -> ()).(default argument 0) _TIF1t1fFT1iSi1sSS_T_A0_ ---> (f(i : Int, s : String) -> ()).(default argument 1) diff --git a/test/Driver/Dependencies/Inputs/fail.py b/test/Driver/Dependencies/Inputs/fail.py index 95c72f8c19a10..3f312013f8b9a 100755 --- a/test/Driver/Dependencies/Inputs/fail.py +++ b/test/Driver/Dependencies/Inputs/fail.py @@ -1,3 +1,13 @@ #!/usr/bin/env python +# fail.py - Just exits with an error code -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -exit(1) +import sys +sys.exit(1) diff --git a/test/Driver/Dependencies/Inputs/fake-build-for-bitcode.py b/test/Driver/Dependencies/Inputs/fake-build-for-bitcode.py index 24855b144601b..5e14ed8d148ff 100755 --- a/test/Driver/Dependencies/Inputs/fake-build-for-bitcode.py +++ b/test/Driver/Dependencies/Inputs/fake-build-for-bitcode.py @@ -1,10 +1,24 @@ #!/usr/bin/env python - +# fake-build-for-bitcode.py - Fake build with -embed-bitcode -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# # Emulates the frontend of an -embed-bitcode job. That means we have to handle # -emit-bc and -c actions. +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function import os -import shutil import sys assert sys.argv[1] == '-frontend' @@ -18,8 +32,8 @@ os.utime(outputFile, None) if '-emit-bc' in sys.argv: - print "Handled", os.path.basename(primaryFile) + print("Handled", os.path.basename(primaryFile)) elif '-c' in sys.argv: - print "Produced", os.path.basename(outputFile) + print("Produced", os.path.basename(outputFile)) else: assert False, "unknown action" diff --git a/test/Driver/Dependencies/Inputs/fake-build-whole-module.py b/test/Driver/Dependencies/Inputs/fake-build-whole-module.py index 3b176a2846ee4..d84348f98804a 100755 --- a/test/Driver/Dependencies/Inputs/fake-build-whole-module.py +++ b/test/Driver/Dependencies/Inputs/fake-build-whole-module.py @@ -1,9 +1,23 @@ #!/usr/bin/env python - +# fake-build-for-whole-module.py - Optimized fake build -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# # Emulates the frontend of a -whole-module-optimization compilation. +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function import os -import shutil import sys assert sys.argv[1] == '-frontend' @@ -16,4 +30,4 @@ with open(outputFile, 'a'): os.utime(outputFile, None) -print "Produced", os.path.basename(outputFile) +print("Produced", os.path.basename(outputFile)) diff --git a/test/Driver/Dependencies/Inputs/modify-non-primary-files.py b/test/Driver/Dependencies/Inputs/modify-non-primary-files.py index a131a72067f43..760d13d2456ae 100755 --- a/test/Driver/Dependencies/Inputs/modify-non-primary-files.py +++ b/test/Driver/Dependencies/Inputs/modify-non-primary-files.py @@ -1,10 +1,24 @@ #!/usr/bin/env python - +# modify-non-primary-files.py - Fake build while modifying files -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# # modify-non-primary-files.py simulates a build where the user is modifying the # source files during compilation. +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function import os -import shutil import sys assert sys.argv[1] == '-frontend' @@ -16,7 +30,7 @@ # Modify all files after the primary file. # Ideally this would modify every non-primary file, but that's harder to # infer without actually parsing the arguments. - for file in sys.argv[primaryFileIndex+1:]: + for file in sys.argv[primaryFileIndex + 1:]: if file.startswith('-'): break os.utime(file, None) @@ -32,6 +46,6 @@ os.utime(outputFile, None) if primaryFile: - print "Handled", os.path.basename(primaryFile) + print("Handled", os.path.basename(primaryFile)) else: - print "Produced", os.path.basename(outputFile) + print("Produced", os.path.basename(outputFile)) diff --git a/test/Driver/Dependencies/Inputs/touch.py b/test/Driver/Dependencies/Inputs/touch.py index cf750c3402073..df02b1ccca6b3 100755 --- a/test/Driver/Dependencies/Inputs/touch.py +++ b/test/Driver/Dependencies/Inputs/touch.py @@ -1,6 +1,19 @@ #!/usr/bin/env python - +# touch.py - /bin/touch that writes the LLVM epoch -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# # Like /bin/touch, but takes a time using the LLVM epoch. +# +# ---------------------------------------------------------------------------- import os import sys @@ -8,7 +21,8 @@ assert len(sys.argv) >= 2 timeVal = int(sys.argv[1]) -timeVal += 946684800 # offset between Unix and LLVM epochs +# offset between Unix and LLVM epochs +timeVal += 946684800 # Update the output file mtime, or create it if necessary. # From http://stackoverflow.com/a/1160227. diff --git a/test/Driver/Dependencies/Inputs/update-dependencies-bad.py b/test/Driver/Dependencies/Inputs/update-dependencies-bad.py index 1c2c9f8d98f5e..058428df7f65f 100755 --- a/test/Driver/Dependencies/Inputs/update-dependencies-bad.py +++ b/test/Driver/Dependencies/Inputs/update-dependencies-bad.py @@ -1,7 +1,22 @@ #!/usr/bin/env python - +# update-dependencies-bad.py - Fails on bad.swift -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# # Fails if the input file is named "bad.swift"; otherwise dispatches to # update-dependencies.py. +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function import os import sys @@ -11,8 +26,8 @@ primaryFile = sys.argv[sys.argv.index('-primary-file') + 1] if os.path.basename(primaryFile) == 'bad.swift': - print "Handled", os.path.basename(primaryFile) - exit(1) + print("Handled", os.path.basename(primaryFile)) + sys.exit(1) dir = os.path.dirname(os.path.abspath(__file__)) execfile(os.path.join(dir, "update-dependencies.py")) diff --git a/test/Driver/Dependencies/Inputs/update-dependencies.py b/test/Driver/Dependencies/Inputs/update-dependencies.py index aac77698ff47c..d8768c7fa66fd 100755 --- a/test/Driver/Dependencies/Inputs/update-dependencies.py +++ b/test/Driver/Dependencies/Inputs/update-dependencies.py @@ -1,7 +1,18 @@ #!/usr/bin/env python - -# update-dependencies.py simulates a Swift compilation for the purposes of -# dependency analysis. That means it has two tasks: +# update-dependencies.py - Fake build for dependency analysis -*- python -*- +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- +# +# Simulates a Swift compilation for the purposes of dependency analysis. +# That means this has two tasks: # # 1. Update the main output of the compilation job. # 2. Update the associated dependencies file, in case anything changed. @@ -13,6 +24,10 @@ # the old dependencies (if present). # # If invoked in non-primary-file mode, it only creates the output file. +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function import os import shutil @@ -37,6 +52,6 @@ os.utime(outputFile, None) if primaryFile: - print "Handled", os.path.basename(primaryFile) + print("Handled", os.path.basename(primaryFile)) else: - print "Produced", os.path.basename(outputFile) + print("Produced", os.path.basename(outputFile)) diff --git a/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_iossim.a b/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_iossim.a new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_tvossim.a b/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_tvossim.a new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_watchossim.a b/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.profile_watchossim.a new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/Driver/Inputs/filelists/check-filelist-abc.py b/test/Driver/Inputs/filelists/check-filelist-abc.py new file mode 100755 index 0000000000000..f5487763bfac4 --- /dev/null +++ b/test/Driver/Inputs/filelists/check-filelist-abc.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# check-filelist-abc.py - Fake build to test driver-produced -filelists. +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function + +import os +import sys + +assert sys.argv[1] == '-frontend' + +if '-primary-file' in sys.argv: + primaryFile = sys.argv[sys.argv.index('-primary-file') + 1] +else: + primaryFile = None + +if primaryFile and primaryFile.endswith(".bc"): + sys.exit() + +filelistFile = sys.argv[sys.argv.index('-filelist') + 1] + +with open(filelistFile, 'r') as f: + lines = f.readlines() + assert lines[0].endswith("/a.swift\n") or lines[0].endswith("/a.swiftmodule\n") + assert lines[1].endswith("/b.swift\n") or lines[1].endswith("/b.swiftmodule\n") + assert lines[2].endswith("/c.swift\n") or lines[2].endswith("/c.swiftmodule\n") + +if primaryFile: + print("Handled", os.path.basename(primaryFile)) +elif lines[0].endswith(".swiftmodule\n"): + print("Handled modules") +else: + print("Handled all") + +if '-num-threads' in sys.argv: + outputListFile = sys.argv[sys.argv.index('-output-filelist') + 1] + with open(outputListFile, 'r') as f: + lines = f.readlines() + assert lines[0].endswith("/a.o\n") or lines[0].endswith("/a.bc\n") + assert lines[1].endswith("/b.o\n") or lines[1].endswith("/b.bc\n") + assert lines[2].endswith("/c.o\n") or lines[2].endswith("/c.bc\n") + print("...with output!") diff --git a/test/Driver/Inputs/filelists/ld b/test/Driver/Inputs/filelists/ld new file mode 100755 index 0000000000000..ed1cb356b5719 --- /dev/null +++ b/test/Driver/Inputs/filelists/ld @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# ld - Fake Darwin linker to test driver-produced -filelists. +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function + +import sys + +filelistFile = sys.argv[sys.argv.index('-filelist') + 1] + +with open(filelistFile, 'r') as f: + lines = f.readlines() + assert lines[0].endswith("/a.o\n") + assert lines[1].endswith("/b.o\n") + assert lines[2].endswith("/c.o\n") + +print("Handled link") diff --git a/test/Driver/Inputs/filelists/output.json b/test/Driver/Inputs/filelists/output.json new file mode 100644 index 0000000000000..0619693309c78 --- /dev/null +++ b/test/Driver/Inputs/filelists/output.json @@ -0,0 +1,17 @@ +{ + "./a.swift": { + "object": "./a.o", + "swiftmodule": "./a.swiftmodule", + "llvm-bc": "./a.bc", + }, + "./b.swift": { + "object": "./b.o", + "swiftmodule": "./b.swiftmodule", + "llvm-bc": "./b.bc", + }, + "./c.swift": { + "object": "./c.o", + "swiftmodule": "./c.swiftmodule", + "llvm-bc": "./c.bc", + } +} diff --git a/test/Driver/Inputs/print-var.sh b/test/Driver/Inputs/print-var.sh index 2bdd799b57fa3..b8426087043cb 100755 --- a/test/Driver/Inputs/print-var.sh +++ b/test/Driver/Inputs/print-var.sh @@ -1,3 +1,3 @@ -#!/bin/bash +#!/usr/bin/env bash last_arg=${@: -1} echo ${!last_arg} diff --git a/test/Driver/actions.swift b/test/Driver/actions.swift index 96325d21945b9..bf33e60c1547b 100644 --- a/test/Driver/actions.swift +++ b/test/Driver/actions.swift @@ -100,6 +100,13 @@ // DEBUG-LINK-ONLY: 5: link, {0, 1, 4}, image // DEBUG-LINK-ONLY: 6: generate-dSYM, {5}, dSYM +// RUN: touch %t/a.o %t/b.o +// RUN: %swiftc_driver -driver-print-actions %t/a.o %s -o main 2>&1 | FileCheck %s -check-prefix=COMPILE-PLUS-OBJECT +// COMPILE-PLUS-OBJECT: 0: input, "{{.*}}/a.o", object +// COMPILE-PLUS-OBJECT: 1: input, "{{.*}}actions.swift", swift +// COMPILE-PLUS-OBJECT: 2: compile, {1}, object +// COMPILE-PLUS-OBJECT: 3: link, {0, 2}, image + // RUN: %swiftc_driver -driver-print-actions %S/Inputs/main.swift %S/../Inputs/empty.swift %s -module-name actions -force-single-frontend-invocation 2>&1 | FileCheck %s -check-prefix=WHOLE-MODULE // WHOLE-MODULE: 0: input, "{{.*}}Inputs/main.swift", swift diff --git a/test/Driver/driver-compile.swift b/test/Driver/driver-compile.swift index caf76c6a309be..5e41897c79a03 100644 --- a/test/Driver/driver-compile.swift +++ b/test/Driver/driver-compile.swift @@ -35,6 +35,8 @@ // RUN: cp %s %t // RUN: not %swiftc_driver -driver-print-jobs -c -target x86_64-apple-macosx10.9 %s %t/driver-compile.swift 2>&1 | FileCheck -check-prefix DUPLICATE-NAME %s +// RUN: %swiftc_driver -driver-print-jobs -c -target x86_64-apple-macosx10.9 %s %S/../Inputs/empty.swift -module-name main -driver-use-filelists 2>&1 | FileCheck -check-prefix=FILELIST %s + // RUN: rm -rf %t && mkdir -p %t/DISTINCTIVE-PATH/usr/bin/ // RUN: ln %swift_driver_plain %t/DISTINCTIVE-PATH/usr/bin/swiftc // RUN: ln -s "swiftc" %t/DISTINCTIVE-PATH/usr/bin/swift-update @@ -102,6 +104,15 @@ // DUPLICATE-NAME: error: filename "driver-compile.swift" used twice: '{{.*}}test/Driver/driver-compile.swift' and '{{.*}}driver-compile.swift' // DUPLICATE-NAME: note: filenames are used to distinguish private declarations with the same name +// FILELIST: bin/swift +// FILELIST: -filelist [[SOURCES:(["][^"]+|[^ ]+)sources([^"]+["]|[^ ]+)]] +// FILELIST: -primary-file {{.*/(driver-compile.swift|empty.swift)}} +// FILELIST: -output-filelist {{[^-]}} +// FILELIST-NEXT: bin/swift +// FILELIST: -filelist [[SOURCES]] +// FILELIST: -primary-file {{.*/(driver-compile.swift|empty.swift)}} +// FILELIST: -output-filelist {{[^-]}} + // UPDATE-CODE: DISTINCTIVE-PATH/usr/bin/swift-update // UPDATE-CODE: -c{{ }} // UPDATE-CODE: -o {{.+}}.remap diff --git a/test/Driver/filelists.swift b/test/Driver/filelists.swift new file mode 100644 index 0000000000000..7422c5a9366bb --- /dev/null +++ b/test/Driver/filelists.swift @@ -0,0 +1,36 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: touch %t/a.swift %t/b.swift %t/c.swift + +// RUN: (cd %t && %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-module ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json 2>&1 | FileCheck %s) + +// CHECK-NOT: Handled +// CHECK: Handled a.swift +// CHECK-NEXT: Handled b.swift +// CHECK-NEXT: Handled c.swift +// CHECK-NEXT: Handled modules +// CHECK-NOT: Handled + +// RUN: %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -c %t/a.swift %t/b.swift %t/c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -force-single-frontend-invocation 2>&1 | FileCheck -check-prefix=CHECK-WMO %s + +// CHECK-NOT: Handled +// CHECK-WMO: Handled all +// CHECK-NOT: output +// CHECK-NOT: Handled + + +// RUN: (cd %t && %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1 2>&1 | FileCheck -check-prefix=CHECK-WMO-THREADED %s) +// RUN: (cd %t && %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1 -embed-bitcode 2>&1 | FileCheck -check-prefix=CHECK-WMO-THREADED %s) +// RUN: mkdir %t/tmp/ +// RUN: (cd %t && env TMPDIR="%t/tmp/" %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -c ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1 -save-temps 2>&1 | FileCheck -check-prefix=CHECK-WMO-THREADED %s) +// RUN: ls %t/tmp/sources-* %t/tmp/outputs-* + +// CHECK-NOT: Handled +// CHECK-WMO-THREADED: Handled all +// CHECK-WMO-THREADED-NEXT: ...with output! +// CHECK-NOT: Handled + +// RUN: (cd %t && env PATH=%S/Inputs/filelists/:$PATH %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json 2>&1 | FileCheck -check-prefix=CHECK-LINK %s) +// RUN: (cd %t && env PATH=%S/Inputs/filelists/:$PATH %swiftc_driver_plain -driver-use-frontend-path %S/Inputs/filelists/check-filelist-abc.py -emit-library ./a.swift ./b.swift ./c.swift -module-name main -target x86_64-apple-macosx10.9 -driver-use-filelists -output-file-map=%S/Inputs/filelists/output.json -force-single-frontend-invocation -num-threads 1 2>&1 | FileCheck -check-prefix=CHECK-LINK %s) + +// CHECK-LINK: Handled link + diff --git a/test/Driver/linker.swift b/test/Driver/linker.swift index 0bae408b09c96..a2ee97dd12a75 100644 --- a/test/Driver/linker.swift +++ b/test/Driver/linker.swift @@ -14,6 +14,9 @@ // RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-linux-gnu -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.linux.txt // RUN: FileCheck -check-prefix LINUX-x86_64 %s < %t.linux.txt +// RUN: %swiftc_driver -driver-print-jobs -target armv6-unknown-linux-gnueabihf -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.linux.txt +// RUN: FileCheck -check-prefix LINUX-armv6 %s < %t.linux.txt + // RUN: %swiftc_driver -driver-print-jobs -target armv7-unknown-linux-gnueabihf -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.linux.txt // RUN: FileCheck -check-prefix LINUX-armv7 %s < %t.linux.txt @@ -25,6 +28,11 @@ // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.10 %s | FileCheck -check-prefix NO_ARCLITE %s // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-ios8.0 %s | FileCheck -check-prefix NO_ARCLITE %s +// RUN: rm -rf %t && mkdir %t +// RUN: touch %t/a.o +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 %s %t/a.o -o linker 2>&1 | FileCheck -check-prefix COMPILE_AND_LINK %s +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 %s %t/a.o -driver-use-filelists -o linker 2>&1 | FileCheck -check-prefix FILELIST %s + // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -emit-library %s -module-name LINKER | FileCheck -check-prefix INFERRED_NAME %s // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -emit-library %s -o libLINKER.dylib | FileCheck -check-prefix INFERRED_NAME %s @@ -108,6 +116,23 @@ // LINUX-x86_64-DAG: -Xlinker -undefined // LINUX-x86_64: -o linker +// LINUX-armv6: swift +// LINUX-armv6: -o [[OBJECTFILE:.*]] + +// LINUX-armv6: clang++{{"? }} +// LINUX-armv6-DAG: [[OBJECTFILE]] +// LINUX-armv6-DAG: -lswiftCore +// LINUX-armv6-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] +// LINUX-armv6-DAG: --target=armv6-unknown-linux-gnueabihf +// LINUX-armv6-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] +// LINUX-armv6-DAG: -Xlinker -T /{{[^ ]+}}/linux/armv6/swift.ld +// LINUX-armv6-DAG: -F foo +// LINUX-armv6-DAG: -framework bar +// LINUX-armv6-DAG: -L baz +// LINUX-armv6-DAG: -lboo +// LINUX-armv6-DAG: -Xlinker -undefined +// LINUX-armv6: -o linker + // LINUX-armv7: swift // LINUX-armv7: -o [[OBJECTFILE:.*]] @@ -115,6 +140,7 @@ // LINUX-armv7-DAG: [[OBJECTFILE]] // LINUX-armv7-DAG: -lswiftCore // LINUX-armv7-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] +// LINUX-armv7-DAG: --target=armv7-unknown-linux-gnueabihf // LINUX-armv7-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] // LINUX-armv7-DAG: -Xlinker -T /{{[^ ]+}}/linux/armv7/swift.ld // LINUX-armv7-DAG: -F foo @@ -150,6 +176,25 @@ // NO_ARCLITE: -o {{[^ ]+}} +// COMPILE_AND_LINK: bin/swift +// COMPILE_AND_LINK-NOT: /a.o +// COMPILE_AND_LINK: linker.swift +// COMPILE_AND_LINK-NOT: /a.o +// COMPILE_AND_LINK-NEXT: bin/ld{{"? }} +// COMPILE_AND_LINK-DAG: /a.o +// COMPILE_AND_LINK-DAG: .o +// COMPILE_AND_LINK: -o linker + + +// FILELIST: bin/ld{{"? }} +// FILELIST-NOT: .o +// FILELIST: -filelist {{"?[^-]}} +// FILELIST-NOT: .o +// FILELIST: /a.o +// FILELIST-NOT: .o +// FILELIST: -o linker + + // INFERRED_NAME: bin/swift // INFERRED_NAME: -module-name LINKER // INFERRED_NAME: bin/ld{{"? }} diff --git a/test/Driver/merge-module.swift b/test/Driver/merge-module.swift index 9ad3fe7153404..2b806f1024c9e 100644 --- a/test/Driver/merge-module.swift +++ b/test/Driver/merge-module.swift @@ -14,6 +14,8 @@ // RUN: FileCheck %s < %t.complex.txt // RUN: FileCheck -check-prefix THREE-OUTPUTS %s < %t.complex.txt +// RUN: %swiftc_driver -emit-module -driver-print-jobs -driver-use-filelists %s %S/../Inputs/empty.swift -module-name main 2>&1 | FileCheck -check-prefix FILELISTS %s + // CHECK: bin/swift{{c?}} -frontend // CHECK: -module-name {{[^ ]+}} // CHECK: -o [[OBJECTFILE:.*]] @@ -67,6 +69,16 @@ // THREE-OUTPUTS: -emit-objc-header-path sdk.foo.h // THREE-OUTPUTS: -o sdk.foo.out + +// FILELISTS: bin/swift{{c?}} -frontend +// FILELISTS-NEXT: bin/swift{{c?}} -frontend +// FILELISTS-NEXT: bin/swift{{c?}} -frontend +// FILELISTS-NOT: .swiftmodule +// FILELISTS: -filelist {{[^ ]+}} +// FILELISTS-NOT: .swiftmodule +// FILELISTS: -o {{[^ ]+}} + + // RUN: %swiftc_driver -driver-print-jobs -emit-module %S/Inputs/main.swift %S/Inputs/lib.swift -module-name merge -o /tmp/modules > %t.complex.txt // RUN: FileCheck %s < %t.complex.txt // RUN: FileCheck -check-prefix MERGE_1 %s < %t.complex.txt diff --git a/test/Driver/options.swift b/test/Driver/options.swift index acdc4a44333ec..fa3181b5317f0 100644 --- a/test/Driver/options.swift +++ b/test/Driver/options.swift @@ -55,7 +55,7 @@ // ASSERTCONFIG6: -assert-config DisableReplacement // RUN: not %swiftc_driver -import-objc-header fake.h -import-underlying-module -c %s 2>&1 | FileCheck -check-prefix=FRAMEWORK_BRIDGING_HEADER %s -// FRAMEWORK_BRIDGING_HEADER: error: using bridging headers with framework targets is unsupported +// FRAMEWORK_BRIDGING_HEADER: error: using bridging headers with framework targets is unsupported // RUN: %swift_driver -### | FileCheck -check-prefix=DEFAULT_REPL %s // DEFAULT_REPL: -repl diff --git a/test/Driver/profiling.swift b/test/Driver/profiling.swift index 7c09d439dbfaa..97051e6d94557 100644 --- a/test/Driver/profiling.swift +++ b/test/Driver/profiling.swift @@ -1,10 +1,21 @@ // RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-macosx10.9 %s | FileCheck -check-prefix=CHECK -check-prefix=OSX %s -// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-ios7.1 %s | FileCheck -check-prefix=CHECK -check-prefix=IOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-ios7.1 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=IOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target arm64-apple-ios7.1 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=IOS %s -// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-tvos9.0 %s | FileCheck -check-prefix=CHECK -check-prefix=tvOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-ios7.1 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=IOSSIM %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target arm64-apple-ios7.1 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=IOS %s -// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-watchos2.0 %s | FileCheck -check-prefix=CHECK -check-prefix=watchOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-tvos9.0 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=tvOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target arm64-apple-tvos9.0 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=tvOS %s + +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-apple-tvos9.0 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=tvOS_SIM %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target arm64-apple-tvos9.0 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=tvOS %s + +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target i386-apple-watchos2.0 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=watchOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target armv7k-apple-watchos2.0 -resource-dir %S/Inputs/fake-resource-dir-old/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=watchOS %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target i386-apple-watchos2.0 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=watchOS_SIM %s +// RUN: %swiftc_driver -driver-print-jobs -profile-generate -target armv7k-apple-watchos2.0 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | FileCheck -check-prefix=CHECK -check-prefix=watchOS %s // RUN: %swiftc_driver -driver-print-jobs -profile-generate -target x86_64-unknown-linux-gnu %s | FileCheck -check-prefix=CHECK -check-prefix=LINUX %s @@ -12,17 +23,26 @@ // CHECK: -profile-generate // OSX: bin/ld{{"? }} -// OSX: lib/swift/clang/{{[^ ]*}}/lib/darwin/libclang_rt.profile_osx.a +// OSX: lib/swift/clang/lib/darwin/libclang_rt.profile_osx.a // IOS: bin/ld{{"? }} -// IOS: lib/swift/clang/{{[^ ]*}}/lib/darwin/libclang_rt.profile_ios.a +// IOS: lib/swift/clang/lib/darwin/libclang_rt.profile_ios.a + +// IOSSIM: bin/ld{{"? }} +// IOSSIM: lib/swift/clang/lib/darwin/libclang_rt.profile_iossim.a // tvOS: bin/ld{{"? }} -// tvOS: lib/swift/clang/{{[^ ]*}}/lib/darwin/libclang_rt.profile_tvos.a +// tvOS: lib/swift/clang/lib/darwin/libclang_rt.profile_tvos.a + +// tvOS_SIM: bin/ld{{"? }} +// tvOS_SIM: lib/swift/clang/lib/darwin/libclang_rt.profile_tvossim.a // watchOS: bin/ld{{"? }} -// watchOS: lib/swift/clang/{{[^ ]*}}/lib/darwin/libclang_rt.profile_watchos.a +// watchOS: lib/swift/clang/lib/darwin/libclang_rt.profile_watchos.a + +// watchOS_SIM: bin/ld{{"? }} +// watchOS_SIM: lib/swift/clang/lib/darwin/libclang_rt.profile_watchossim.a // LINUX: clang++{{"? }} -// LINUX: lib/swift/clang/{{[^ ]*}}/lib/linux/libclang_rt.profile-x86_64.a +// LINUX: lib/swift/clang/lib/linux/libclang_rt.profile-x86_64.a diff --git a/test/Driver/subcommands.swift b/test/Driver/subcommands.swift index 521d3ebbdc569..bc63dddbc6d03 100644 --- a/test/Driver/subcommands.swift +++ b/test/Driver/subcommands.swift @@ -1,5 +1,7 @@ // Check that each of 'swift', 'swift repl', 'swift run' invoke the REPL. // +// REQUIRES: swift_interpreter +// // RUN: %swift_driver_plain -### 2>&1 | FileCheck -check-prefix=CHECK-SWIFT-INVOKES-REPL %s // RUN: %swift_driver_plain run -### 2>&1 | FileCheck -check-prefix=CHECK-SWIFT-INVOKES-REPL %s // RUN: %swift_driver_plain repl -### 2>&1 | FileCheck -check-prefix=CHECK-SWIFT-INVOKES-REPL %s diff --git a/test/Driver/warnings-control.swift b/test/Driver/warnings-control.swift new file mode 100644 index 0000000000000..d512aa395a285 --- /dev/null +++ b/test/Driver/warnings-control.swift @@ -0,0 +1,24 @@ +// RUN: not %target-swiftc_driver %s 2>&1 | FileCheck -check-prefix=DEFAULT %s +// RUN: not %target-swiftc_driver -warnings-as-errors %s 2>&1 | FileCheck -check-prefix=WERR %s +// RUN: not %target-swiftc_driver -suppress-warnings %s 2>&1 | FileCheck -check-prefix=NOWARN %s + +// RUN: not %target-swiftc_driver -suppress-warnings -warnings-as-errors %s 2>&1 | FileCheck -check-prefix=FLAGS_CONFLICT %s +// FLAGS_CONFLICT: error: conflicting options '-warnings-as-errors' and '-suppress-warnings' + +func foo() -> Int { + let x = 1 + var y = 2 +// DEFAULT: warning: variable 'y' was never mutated; consider changing to 'let' constant +// WERR: error: variable 'y' was never mutated; consider changing to 'let' constant +// NOWARN-NOT: variable 'y' was never mutated + return x + y +} + +func bar() { + foo() +// To help anchor the checks, have an error. Put it inside a later function, to help make sure it comes after + xyz +// DEFAULT: error: use of unresolved identifier 'xyz' +// WERR: error: use of unresolved identifier 'xyz' +// NOWARN: error: use of unresolved identifier 'xyz' +} diff --git a/test/FixCode/fixits-apply.swift b/test/FixCode/fixits-apply.swift index 502684b181e55..4d512bfd1e441 100644 --- a/test/FixCode/fixits-apply.swift +++ b/test/FixCode/fixits-apply.swift @@ -13,7 +13,7 @@ b as! Base var opti : Int? // Don't add bang. var i : Int = opti -// But remove unecessary bang. +// But remove unnecessary bang. var i2 : Int = i! struct MyMask : OptionSetType { @@ -45,10 +45,6 @@ struct Test1 : RawOptionSetType { var rawValue: Int { return 0 } } -print("", appendNewline: false) -Swift.print("", appendNewline: false) -print("", appendNewline: true) -print("", false, appendNewline: false) print("", false) func ftest1() { diff --git a/test/FixCode/fixits-apply.swift.result b/test/FixCode/fixits-apply.swift.result index 8afd86dccf359..06bd81101b12a 100644 --- a/test/FixCode/fixits-apply.swift.result +++ b/test/FixCode/fixits-apply.swift.result @@ -13,7 +13,7 @@ b var opti : Int? // Don't add bang. var i : Int = opti -// But remove unecessary bang. +// But remove unnecessary bang. var i2 : Int = i struct MyMask : OptionSetType { @@ -45,10 +45,6 @@ struct Test1 : OptionSetType { var rawValue: Int { return 0 } } -print("", terminator: "") -Swift.print("", terminator: "") -print("", terminator: "\n") -print("", false, appendNewline: false) print("", false) func ftest1() { diff --git a/test/Frontend/Inputs/filelist-other.swift b/test/Frontend/Inputs/filelist-other.swift new file mode 100644 index 0000000000000..590d2e099a1c0 --- /dev/null +++ b/test/Frontend/Inputs/filelist-other.swift @@ -0,0 +1,4 @@ +struct Foo {} +struct Bar {} + +func other() -> Bar { return Bar() } diff --git a/test/Frontend/embed-bitcode.swift b/test/Frontend/embed-bitcode.swift index f9e33533ab709..bdd3c2f546f4d 100644 --- a/test/Frontend/embed-bitcode.swift +++ b/test/Frontend/embed-bitcode.swift @@ -4,7 +4,11 @@ // RUN: llvm-objdump -macho -section="__LLVM,__bitcode" %t.o | FileCheck -check-prefix=MARKER %s // RUN: llvm-objdump -macho -section="__LLVM,__swift_cmdline" %t.o | FileCheck -check-prefix=MARKER-CMD %s +// This file tests Mach-O file output, but Linux variants do not produce Mach-O +// files. // UNSUPPORTED: OS=linux-gnu +// UNSUPPORTED: OS=linux-gnueabihf +// UNSUPPORTED: OS=freebsd // MARKER: Contents of (__LLVM,__bitcode) section // MARKER-NEXT: 00 diff --git a/test/Frontend/filelist.swift b/test/Frontend/filelist.swift new file mode 100644 index 0000000000000..aeb78c036e2f7 --- /dev/null +++ b/test/Frontend/filelist.swift @@ -0,0 +1,21 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: echo '%S/Inputs/filelist-other.swift' >> %t/input.txt +// RUN: echo '%s' >> %t/input.txt +// RUN: echo '%S/../Inputs/empty.swift' >> %t/input.txt +// RUN: not %target-swift-frontend -parse -filelist %t/input.txt -primary-file %s 2>&1 | FileCheck %s +// RUN: not %target-swift-frontend -parse -filelist %t/input.txt 2>&1 | FileCheck %s + +// RUN: echo '%t/filelist-other.bc' >> %t/output.txt +// RUN: echo '%t/filelist.bc' >> %t/output.txt +// RUN: echo '%t/filelist-other.bc' >> %t/output.txt +// RUN: %target-swift-frontend -emit-bc -filelist %t/input.txt -output-filelist %t/output.txt -num-threads 1 -DWORKING -module-name main +// RUN: ls %t/filelist-other.bc %t/filelist.bc %t/filelist-other.bc + +func test() { +#if !WORKING + // Check with FileCheck because we want to see that this file is being + // compiled. + // CHECK: error: cannot convert value of type 'Bar' to specified type 'Foo' + let x: Foo = other() +#endif +} diff --git a/test/Generics/Inputs/associated_types_multi_file_helper.swift b/test/Generics/Inputs/associated_types_multi_file_helper.swift index f5d3fa05a2eb8..c1a8b149f1557 100644 --- a/test/Generics/Inputs/associated_types_multi_file_helper.swift +++ b/test/Generics/Inputs/associated_types_multi_file_helper.swift @@ -1,5 +1,5 @@ protocol Fooable { - typealias AssocType + associatedtype AssocType func foo(x : AssocType) } diff --git a/test/Generics/algorithms.swift b/test/Generics/algorithms.swift index 1979befecf0ae..2a36cdddf4be5 100644 --- a/test/Generics/algorithms.swift +++ b/test/Generics/algorithms.swift @@ -80,7 +80,7 @@ func equal (range1 : R1, range2 : R2, - predicate : (R1.Element, R2.Element)-> Bool) -> Bool { + predicate : (R1.Element, R2.Element) -> Bool) -> Bool { var range1 = range1 var range2 = range2 var e1 = range1.next() diff --git a/test/Generics/associated_self_constraints.swift b/test/Generics/associated_self_constraints.swift index a0af58d5653d3..95a5b2cee4ff9 100644 --- a/test/Generics/associated_self_constraints.swift +++ b/test/Generics/associated_self_constraints.swift @@ -1,7 +1,7 @@ // RUN: %target-parse-verify-swift protocol Observer { - typealias Value + associatedtype Value func onNext(item: Value) -> Void func onCompleted() -> Void @@ -9,7 +9,7 @@ protocol Observer { } protocol Observable { - typealias Value + associatedtype Value func subscribe(observer: O) -> Any } @@ -50,7 +50,7 @@ class Subject: Observer, Observable { observer.onError(error) } - return self; + return self } } @@ -64,7 +64,7 @@ struct X { } protocol P { - typealias A + associatedtype A func onNext(item: A) -> Void } @@ -78,5 +78,5 @@ struct IP : P { func onNext(item: A) { _onNext(item) } - var _onNext: (A)->() + var _onNext: (A) -> () } diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift index 6a35107325c18..5f16d0b268ab4 100644 --- a/test/Generics/associated_type_typo.swift +++ b/test/Generics/associated_type_typo.swift @@ -4,11 +4,11 @@ // RUN: FileCheck -check-prefix CHECK-GENERIC %s < %t.dump protocol P1 { - typealias Assoc + associatedtype Assoc } protocol P2 { - typealias AssocP2 : P1 + associatedtype AssocP2 : P1 } protocol P3 { } diff --git a/test/Generics/associated_types.swift b/test/Generics/associated_types.swift index ae5f5b2defc15..d65226862b5c1 100644 --- a/test/Generics/associated_types.swift +++ b/test/Generics/associated_types.swift @@ -2,7 +2,7 @@ // Deduction of associated types. protocol Fooable { - typealias AssocType + associatedtype AssocType func foo(x : AssocType) } @@ -39,7 +39,7 @@ var d : Double d = yd protocol P1 { - typealias Assoc1 + associatedtype Assoc1 func foo() -> Assoc1 } @@ -50,7 +50,7 @@ struct S1 : P1 { prefix operator % {} protocol P2 { - typealias Assoc2 + associatedtype Assoc2 prefix func %(target: Self) -> Assoc2 } @@ -63,12 +63,12 @@ extension S1 : P2 { // protocol P3 { - typealias Assoc3 + associatedtype Assoc3 func foo() -> Assoc3 } protocol P4 : P3 { - typealias Assoc4 + associatedtype Assoc4 func bar() -> Assoc4 } @@ -93,7 +93,7 @@ protocol P6 { } protocol P7 : P6 { - typealias Assoc : P6 + associatedtype Assoc : P6 func ~> (x: Self, _: S7a) -> Assoc } @@ -116,12 +116,12 @@ struct zip : GeneratorType, SequenceType { protocol P8 { } protocol P9 { - typealias A1 : P8 + associatedtype A1 : P8 } protocol P10 { - typealias A1b : P8 - typealias A2 : P9 + associatedtype A1b : P8 + associatedtype A2 : P9 func f() func g(a: A1b) @@ -151,3 +151,29 @@ struct V : Fooable { // FIXME: Inferred associated types can't be used in expression contexts var w = W.AssocType() var v = V.AssocType() + +// +// SR-427 +protocol A { + func c() // expected-note {{protocol requires function 'c()' with type '() -> ()'}} +} + +protocol B : A { + associatedtype e : A = C // expected-note {{default type 'C>' for associated type 'e' (from protocol 'B') does not conform to 'A'}} +} + +extension B { + func c() { // expected-note {{candidate has non-matching type ' () -> ()' (aka '<τ_0_0> () -> ()')}} + } +} + +struct C : B { // expected-error {{type 'C' does not conform to protocol 'B'}} expected-error {{type 'C' does not conform to protocol 'A'}} +} + +// SR-511 +protocol sr511 { + typealias Foo // expected-warning {{use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead}} {{3-12=associatedtype}} +} + +associatedtype Foo = Int // expected-error {{associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement}} + diff --git a/test/Generics/associated_types_inherit.swift b/test/Generics/associated_types_inherit.swift index bfb2e614cdb40..c37bae5116f3b 100644 --- a/test/Generics/associated_types_inherit.swift +++ b/test/Generics/associated_types_inherit.swift @@ -10,7 +10,7 @@ class D : C { class E { } protocol P { // expected-note{{requirement specified as 'Self.Assoc' : 'C' [with Self = X2]}} - typealias Assoc : C + associatedtype Assoc : C func getAssoc() -> Assoc } diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index 234aad7ea0951..cafa808731511 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -38,7 +38,7 @@ func useTwoIdentical(xi: Int, yi: Float) { y = twoIdentical(1.0, y) y = twoIdentical(y, 1.0) - twoIdentical(x, y) // expected-error{{cannot invoke 'twoIdentical' with an argument list of type '(Int, Float)'}} expected-note{{expected an argument list of type '(T, T)'}} + twoIdentical(x, y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}} } func mySwap(inout x: T, @@ -78,11 +78,10 @@ func passFunction(f: (Int) -> Float, x: Int, y: Float) { acceptFunction(f, y, y) // expected-error{{cannot convert value of type '(Int) -> Float' to expected argument type '(_) -> _'}} } -func returnTuple(_: T) -> (T, U) { } +func returnTuple(_: T) -> (T, U) { } // expected-note {{in call to function 'returnTuple'}} func testReturnTuple(x: Int, y: Float) { - returnTuple(x) // expected-error{{cannot invoke 'returnTuple' with an argument list of type '(Int)'}} - // expected-note @-1 {{expected an argument list of type '(T)'}} + returnTuple(x) // expected-error{{generic parameter 'T' could not be inferred}} var _ : (Int, Float) = returnTuple(x) var _ : (Float, Float) = returnTuple(y) @@ -206,17 +205,17 @@ extension Int : IsBefore { func callMin(x: Int, y: Int, a: Float, b: Float) { min2(x, y) - min2(a, b) // expected-error{{cannot invoke 'min2' with an argument list of type '(Float, Float)'}} expected-note {{expected an argument list of type '(T, T)'}} + min2(a, b) // expected-error{{argument type 'Float' does not conform to expected type 'IsBefore'}} } -func rangeOfIsBefore< +func rangeOfIsBefore< // expected-note {{in call to function 'rangeOfIsBefore'}} R : GeneratorType where R.Element : IsBefore >(range : R) { } func callRangeOfIsBefore(ia: [Int], da: [Double]) { rangeOfIsBefore(ia.generate()) - rangeOfIsBefore(da.generate()) // expected-error{{cannot invoke 'rangeOfIsBefore' with an argument list of type '(IndexingGenerator<[Double]>)'}} expected-note{{expected an argument list of type '(R)'}} + rangeOfIsBefore(da.generate()) // expected-error{{generic parameter 'R' could not be inferred}} } //===----------------------------------------------------------------------===// @@ -266,7 +265,7 @@ func testGetVectorSize(vi: MyVector, vf: MyVector) { postfix operator <*> {} protocol MetaFunction { - typealias Result + associatedtype Result postfix func <*> (_: Self) -> Result? } @@ -288,3 +287,15 @@ var iy2 : Inty = "hello" // expected-error{{cannot convert value of type 'String class DeducePropertyParams { let badSet: Set = ["Hello"] } + +// SR-69 +struct A {} +func foo() { + for i in min(1,2) { // expected-error{{type 'Int' does not conform to protocol 'SequenceType'}} + } + let j = min(Int(3), Float(2.5)) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}} + let k = min(A(), A()) // expected-error{{argument type 'A' does not conform to expected type 'Comparable'}} + let oi : Int? = 5 + let l = min(3, oi) // expected-error{{value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?}} +} + diff --git a/test/Generics/function_defs.swift b/test/Generics/function_defs.swift index 19f2c6ad30ac9..8f68c5b560d24 100644 --- a/test/Generics/function_defs.swift +++ b/test/Generics/function_defs.swift @@ -14,11 +14,12 @@ protocol EqualComparable { func doCompare(t1: T, t2: T, u: U) -> Bool { var b1 = t1.isEqual(t2) if b1 { - return true; + return true } - return t1.isEqual(u) // expected-error {{cannot invoke 'isEqual' with an argument list of type '(U)'}} - // expected-note @-1 {{expected an argument list of type '(T)'}} + // FIXME: This is not ambiguous, the actual problem is that 'u' has the wrong + // type - "U" is not the same as "T". + return t1.isEqual(u) // expected-error {{type of expression is ambiguous without more context}} } protocol MethodLessComparable { @@ -72,12 +73,12 @@ func testRuncible(x: Runcible) { // expected-error{{protocol 'Runcible' can only //===----------------------------------------------------------------------===// protocol Overload { - typealias A - typealias B + associatedtype A + associatedtype B func getA() -> A func getB() -> B - func f1(_: A) -> A - func f1(_: B) -> B + func f1(_: A) -> A // expected-note{{found this candidate}} + func f1(_: B) -> B // expected-note{{found this candidate}} func f2(_: Int) -> A // expected-note{{found this candidate}} func f2(_: Int) -> B // expected-note{{found this candidate}} func f3(_: Int) -> Int // expected-note {{found this candidate}} @@ -107,8 +108,7 @@ func testOverload(ovl: Ovl, ovl2: Ovl, a = ovl2.f2(17) a = ovl2.f1(a) - other.f1(a) // expected-error{{cannot invoke 'f1' with an argument list of type '(Ovl.A)'}} - // expected-note @-1 {{overloads for 'f1' exist with these partially matching parameter lists: (Self.A), (Self.B)}} + other.f1(a) // expected-error{{ambiguous reference to member 'f1'}} // Overloading based on context var f3i : (Int) -> Int = ovl.f3 @@ -128,21 +128,21 @@ func testOverload(ovl: Ovl, ovl2: Ovl, // Subscripting //===----------------------------------------------------------------------===// protocol Subscriptable { - typealias Index - typealias Value + associatedtype Index + associatedtype Value func getIndex() -> Index func getValue() -> Value - subscript (index : Index) -> Value { get set } + subscript (index : Index) -> Value { get set } // expected-note{{found this candidate}} } protocol IntSubscriptable { - typealias ElementType + associatedtype ElementType func getElement() -> ElementType - subscript (index : Int) -> ElementType { get } + subscript (index : Int) -> ElementType { get } // expected-note{{found this candidate}} } func subscripting>(t: T) { @@ -155,8 +155,7 @@ func subscripting>(t: T) { element = t[17] t[42] = element // expected-error{{cannot assign through subscript: subscript is get-only}} - t[value] = 17 // expected-error{{cannot subscript a value of type 'T' with an index of type 'T.Value'}} - // expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (Self.Index), (Int)}} + t[value] = 17 // expected-error{{ambiguous reference to member 'subscript'}} } //===----------------------------------------------------------------------===// @@ -171,8 +170,10 @@ func staticEqCheck(t: T, u: U) { if T.isEqual(t, y: t) { return } if U.isEqual(u, y: u) { return } - T.isEqual(t, y: u) // expected-error{{cannot invoke 'isEqual' with an argument list of type '(T, y: U)'}} - // expected-note @-1 {{expected an argument list of type '(T, y: T)'}} + + // FIXME: This is not ambiguous, the actual problem is that 'u' has the wrong + // type - "U" is not the same as "T". + T.isEqual(t, y: u) // expected-error{{type of expression is ambiguous without more context}} } //===----------------------------------------------------------------------===// @@ -195,17 +196,17 @@ func conformanceViaRequires(t1: T, t2: T) -> Bool { let b1 = t1.isEqual(t2) if b1 || t1.isLess(t2) { - return true; + return true } } protocol GeneratesAnElement { - typealias Element : EqualComparable + associatedtype Element : EqualComparable func generate() -> Element } protocol AcceptsAnElement { - typealias Element : MethodLessComparable + associatedtype Element : MethodLessComparable func accept(e : Element) } @@ -218,12 +219,12 @@ func impliedSameType(t: T) { } protocol GeneratesAssoc1 { - typealias Assoc1 : EqualComparable + associatedtype Assoc1 : EqualComparable func get() -> Assoc1 } protocol GeneratesAssoc2 { - typealias Assoc2 : MethodLessComparable + associatedtype Assoc2 : MethodLessComparable func get() -> Assoc2 } @@ -235,12 +236,12 @@ func simpleSameType } protocol GeneratesMetaAssoc1 { - typealias MetaAssoc1 : GeneratesAnElement + associatedtype MetaAssoc1 : GeneratesAnElement func get() -> MetaAssoc1 } protocol GeneratesMetaAssoc2 { - typealias MetaAssoc2 : AcceptsAnElement + associatedtype MetaAssoc2 : AcceptsAnElement func get() -> MetaAssoc2 } @@ -258,11 +259,11 @@ func recursiveSameType // protocol P1 { - typealias Element + associatedtype Element } protocol P2 { - typealias AssocP1 : P1 + associatedtype AssocP1 : P1 func getAssocP1() -> AssocP1 } diff --git a/test/Generics/generic_types.swift b/test/Generics/generic_types.swift index 43e96b97fc9a4..a8d95efd251e5 100644 --- a/test/Generics/generic_types.swift +++ b/test/Generics/generic_types.swift @@ -211,7 +211,7 @@ func useNested(ii: Int, hni: HasNested, } var dfail : Dictionary // expected-error{{generic type 'Dictionary' specialized with too few type parameters (got 1, but expected 2)}} -var notgeneric : Int // expected-error{{cannot specialize non-generic type 'Int'}} +var notgeneric : Int // expected-error{{cannot specialize non-generic type 'Int'}}{{21-28=}} // Check unqualified lookup of inherited types. class Foo { @@ -247,7 +247,7 @@ extension Bar { struct Inner2 { func f(x: Int) -> Nested { return x - } + } } */ } @@ -263,7 +263,7 @@ class XArray : ArrayLiteralConvertible { class YArray : XArray { typealias Element = Int - required init(arrayLiteral elements: Int...) { + required init(arrayLiteral elements: Int...) { super.init() } } @@ -292,11 +292,11 @@ class X3 { } var x2 : X2 // expected-error{{'X2' requires that 'X3' inherit from 'X1'}} protocol P { - typealias AssocP + associatedtype AssocP } protocol Q { - typealias AssocQ + associatedtype AssocQ } struct X4 : P, Q { @@ -317,7 +317,7 @@ class Bottom> {} // expected-error 2{{type may not reference its class X6 { let d: D init(_ value: T) { - d = D(value) // expected-error{{cannot invoke initializer for type 'X6.D<_, _>' with an argument list of type '(T)'}} expected-note{{expected an argument list of type '(T2)'}} + d = D(value) } class D { // expected-error{{generic type 'D' nested in type 'X6' is not allowed}} init(_ value: T2) {} diff --git a/test/Generics/materializable_restrictions.swift b/test/Generics/materializable_restrictions.swift index 2196601d91f85..1b161e9dbb7a1 100644 --- a/test/Generics/materializable_restrictions.swift +++ b/test/Generics/materializable_restrictions.swift @@ -2,8 +2,8 @@ func test15921520() { var x: Int = 0 - func f(x: T) {} - f(&x) // expected-error{{cannot invoke 'f' with an argument list of type '(inout Int)'}} expected-note{{expected an argument list of type '(T)'}} + func f(x: T) {} // expected-note{{in call to function 'f'}} + f(&x) // expected-error{{generic parameter 'T' could not be inferred}} } func test20807269() { @@ -15,10 +15,10 @@ func test20807269() { func test15921530() { struct X {} - func makef() -> (T)->() { // expected-note {{in call to function 'makef'}} + func makef() -> (T) -> () { // expected-note {{in call to function 'makef'}} return { x in () } } - var _: (inout X)->() = makef() // expected-error{{generic parameter 'T' could not be inferred}} + var _: (inout X) -> () = makef() // expected-error{{generic parameter 'T' could not be inferred}} } diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index ef08c5156f076..b4cebfca94a0f 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -91,23 +91,23 @@ func inferSuperclassRequirement2(v: U) {} // ---------------------------------------------------------------------------- protocol P3 { - typealias P3Assoc : P2 + associatedtype P3Assoc : P2 } protocol P4 { - typealias P4Assoc : P1 + associatedtype P4Assoc : P1 } protocol PCommonAssoc1 { - typealias CommonAssoc + associatedtype CommonAssoc } protocol PCommonAssoc2 { - typealias CommonAssoc + associatedtype CommonAssoc } protocol PAssoc { - typealias Assoc + associatedtype Assoc } struct Model_P3_P4_Eq { } @@ -115,13 +115,13 @@ struct Model_P3_P4_Eq { } // CHECK-LABEL: .inferSameType1@ // CHECK-NEXT: Requirements: // CHECK-NEXT: T witness marker -// CHECK-NEXT: T : P3 [inferred @ {{.*}}:26] +// CHECK-NEXT: T : P3 [inferred @ {{.*}}:30] // CHECK-NEXT: U witness marker -// CHECK-NEXT: U : P4 [inferred @ {{.*}}:26] +// CHECK-NEXT: U : P4 [inferred @ {{.*}}:30] // CHECK-NEXT: T[.P3].P3Assoc witness marker -// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}:13] -// CHECK-NEXT: T[.P3].P3Assoc : P2 [protocol @ {{.*}}:13] -// CHECK-NEXT: U[.P4].P4Assoc == T[.P3].P3Assoc [inferred @ {{.*}}26] +// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}:18] +// CHECK-NEXT: T[.P3].P3Assoc : P2 [protocol @ {{.*}}:18] +// CHECK-NEXT: U[.P4].P4Assoc == T[.P3].P3Assoc [inferred @ {{.*}}30] func inferSameType1(x: Model_P3_P4_Eq) { } // CHECK-LABEL: .inferSameType2@ @@ -131,7 +131,7 @@ func inferSameType1(x: Model_P3_P4_Eq) { } // CHECK-NEXT: U witness marker // CHECK-NEXT: U : P4 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:33] // CHECK-NEXT: T[.P3].P3Assoc witness marker -// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:13] +// CHECK-NEXT: T[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18] // CHECK-NEXT: T[.P3].P3Assoc : P2 [redundant @ {{.*}}requirement_inference.swift:{{.*}}:54] // CHECK-NEXT: U[.P4].P4Assoc == T[.P3].P3Assoc [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68] func inferSameType2(_: T) { } @@ -148,15 +148,15 @@ func inferSameType2 func inferSameType3(_: T) { } protocol P5 { - typealias Element + associatedtype Element } protocol P6 { - typealias AssocP6 : P5 + associatedtype AssocP6 : P5 } protocol P7 : P6 { - typealias AssocP7: P6 + associatedtype AssocP7: P6 } // CHECK-LABEL: P7.nestedSameType1()@ diff --git a/test/Generics/same_type_constraints.swift b/test/Generics/same_type_constraints.swift index 754582b618686..e5537a747a528 100644 --- a/test/Generics/same_type_constraints.swift +++ b/test/Generics/same_type_constraints.swift @@ -1,13 +1,13 @@ // RUN: %target-parse-verify-swift protocol Fooable { - typealias Foo + associatedtype Foo var foo: Foo { get } } protocol Barrable { - typealias Bar: Fooable + associatedtype Bar: Fooable var bar: Bar { get } } @@ -29,7 +29,7 @@ struct SatisfySameTypeRequirement : TestSameTypeRequirement { } protocol TestSameTypeAssocTypeRequirement { - typealias Assoc + associatedtype Assoc func foo(f: F1) } struct SatisfySameTypeAssocTypeRequirement : TestSameTypeAssocTypeRequirement { @@ -48,7 +48,7 @@ struct SatisfySameTypeAssocTypeRequirementDependent public struct GeneratorOf : GeneratorType, SequenceType { /// Construct an instance whose `next()` method calls `nextElement`. - public init(_ nextElement: ()->T?) { + public init(_ nextElement: () -> T?) { self._next = nextElement } @@ -74,7 +74,7 @@ public struct GeneratorOf : GeneratorType, SequenceType { public func generate() -> GeneratorOf { return self } - let _next: ()->T? + let _next: () -> T? } // rdar://problem/19009056 @@ -85,8 +85,8 @@ public struct LazySequenceOf public subscript(i : A) -> A { return i } } -public func iterate(f : A -> A)(x : A) -> LazySequenceOf, A>? { // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} - return nil +public func iterate(f : A -> A) -> (x : A) -> LazySequenceOf, A>? { + return { x in nil } } public final class Iterate : SequenceType { @@ -104,12 +104,12 @@ public final class IterateGenerator : GeneratorType { // rdar://problem/18475138 public protocol Observable : class { - typealias Output - func addObserver(obj : Output->Void) + associatedtype Output + func addObserver(obj : Output -> Void) } public protocol Bindable : class { - typealias Input + associatedtype Input func foo() } @@ -135,7 +135,7 @@ struct Pair { } protocol Seq { - typealias Element + associatedtype Element func zip.Type_> (otherSeq: OtherSeq) -> ResultSeq } @@ -153,7 +153,7 @@ extension Dictionary { // rdar://problem/19245317 protocol P { - typealias T: P // expected-error{{type may not reference itself as a requirement}} + associatedtype T: P // expected-error{{type may not reference itself as a requirement}} } struct S { @@ -165,7 +165,7 @@ protocol Food { } class Grass : Food { } protocol Animal { - typealias EdibleFood:Food + associatedtype EdibleFood:Food func eat(f:EdibleFood) } class Cow : Animal { @@ -174,7 +174,7 @@ class Cow : Animal { struct SpecificAnimal : Animal { typealias EdibleFood=F - let _eat:(f:F)->() + let _eat:(f:F) -> () init(_ selfie:A) { _eat = { selfie.eat($0) } @@ -226,12 +226,12 @@ func testSameTypeTuple(a: Array<(Int,Int)>, s: ArraySlice<(Int,Int)>) { // rdar://problem/20256475 protocol FooType { - typealias Element + associatedtype Element func getElement() -> Element } protocol BarType { - typealias Foo : FooType + associatedtype Foo : FooType func getFoo() -> Foo @@ -248,7 +248,7 @@ protocol P1 { } protocol P2Base { } protocol P2 : P2Base { - typealias Q : P1 + associatedtype Q : P1 func getQ() -> Q } @@ -263,11 +263,11 @@ func sameTypeParameterizedConcrete>(c: C) { // rdar://problem/21621421 protocol P3 { - typealias AssocP3 : P1 + associatedtype AssocP3 : P1 } protocol P4 { - typealias AssocP4 : P3 + associatedtype AssocP4 : P3 } struct X1 : P1 { } @@ -292,12 +292,12 @@ struct X6 { } protocol P6 { } protocol P7 { - typealias AssocP7 + associatedtype AssocP7 } protocol P8 { - typealias AssocP8 : P7 - typealias AssocOther + associatedtype AssocP8 : P7 + associatedtype AssocOther } func testP8>(c: C) { } @@ -306,7 +306,7 @@ func testP8>(c: C) { } struct Ghost {} protocol Timewarp { - typealias Wormhole + associatedtype Wormhole } struct Teleporter> {} diff --git a/test/IDE/Inputs/dumped_api.swift b/test/IDE/Inputs/dumped_api.swift deleted file mode 100644 index e908803f65ca8..0000000000000 --- a/test/IDE/Inputs/dumped_api.swift +++ /dev/null @@ -1,588 +0,0 @@ -//===--- dump_api.swift ---------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// RUN: %target-swift-ide-test -dump-api -source-filename %s > %t.swift -// RUN: diff -du %S/Inputs/dumped_api.swift %t.swift - -//===--- Definitions needed only while experimental -----------------------===// -public struct _Distance {} -public struct _InitializeTo {} -extension _InitializeTo { } -extension _ContiguousArrayBuffer { -} - -//===----------------------------------------------------------------------===// - - - -//===--- Generator --------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -public class _AnyGeneratorBase {} - -/// An abstract `GeneratorType` base class over `T` elements. -/// -/// Use this as a `Sequence`'s associated `Generator` type when you -/// don't want to expose details of the concrete generator, a subclass. -/// -/// It is an error to create instances of `AnyGenerator` that are not -/// also instances of an `AnyGenerator` subclass. -/// -/// See also: -/// -/// struct AnySequence -/// func anyGenerator(base: G) -> AnyGenerator -/// func anyGenerator(nextImplementation: ()->T?) -> AnyGenerator -public class AnyGenerator : _AnyGeneratorBase, GeneratorType { - /// Initialize the instance. May only be called from a subclass - /// initializer. - override public init() - - /// Advance to the next element and return it, or `nil` if no next - /// element exists. - /// - /// Note: subclasses must override this method. - public func next() -> T? -} - -/// Every `GeneratorType` can also be a `SequenceType`. Note that -/// traversing the sequence consumes the generator. -extension AnyGenerator : SequenceType { - /// Returns `self`. - public func generate() -> AnyGenerator -} - -/// Return a `GeneratorType` instance that wraps `base` but whose type -/// depends only on the type of `G.Element`. -/// -/// Example: -/// -/// func countStrings() -> AnyGenerator { -/// let lazyStrings = lazy(0..<10).map { String($0) } -/// -/// // This is a really complicated type of no interest to our -/// // clients. -/// let g: MapSequenceGenerator, String> -/// = lazyStrings.generate() -/// return anyGenerator(g) -/// } -public func anyGenerator(base: G) -> AnyGenerator - - -/// Return a `GeneratorType` instance whose `next` method invokes -/// `nextImplementation` and returns the result. -/// -/// Example: -/// -/// var x = 7 -/// let g = anyGenerator { x < 15 ? x++ : nil } -/// let a = Array(g) // [ 7, 8, 9, 10, 11, 12, 13, 14 ] -public func anyGenerator(nextImplementation: ()->T?) -> AnyGenerator - - - -//===--- Sequence ---------------------------------------------------------===// -//===----------------------------------------------------------------------===// - - - -// FIXME: can't make this a protocol due to -// FIXME: can't make this a protocol due to - -/// A type-erased sequence. -/// -/// Forwards operations to an arbitrary underlying sequence having the -/// same `Element` type, hiding the specifics of the underlying -/// `SequenceType`. -/// -/// See also: `AnyGenerator`. -public struct AnySequence : SequenceType { - - /// Wrap and forward operations to to `base` - public init(_ base: S) - - /// Return a *generator* over the elements of this *sequence*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator - -} - -public func ~> ( - source: AnySequence, - ptr: (_InitializeTo, UnsafeMutablePointer) -) - -extension AnySequence { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer -} - -public func ~> ( - source: AnyForwardCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) - -extension AnyForwardCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer -} - -public func ~> ( - source: AnyBidirectionalCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) - -extension AnyBidirectionalCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer -} - -public func ~> ( - source: AnyRandomAccessCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) - -extension AnyRandomAccessCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer -} - -//===--- ForwardIndex -----------------------------------------------------===// -//===----------------------------------------------------------------------===// - - - -//===--- BidirectionalIndex -----------------------------------------------===// -//===----------------------------------------------------------------------===// - - - -//===--- RandomAccessIndex -----------------------------------------------===// -//===----------------------------------------------------------------------===// - - - -//===--- All Index Protocols ----------------------------------------------===// -//===----------------------------------------------------------------------===// - - -/// A wrapper over an underlying `ForwardIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyForwardCollection` -public struct AnyForwardIndex : ForwardIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) - - /// Return the next consecutive value in a discrete sequence of - /// `AnyForwardIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyForwardIndex - - - - //===--- private --------------------------------------------------------===// - - - -} - -public func ~> ( - start: AnyForwardIndex, other : (_Distance, AnyForwardIndex) -) -> AnyForwardIndex.Distance - -public func ~> ( - start: AnyForwardIndex, distance : (_Advance, AnyForwardIndex.Distance) -) -> AnyForwardIndex - -public func ~> ( - start: AnyForwardIndex, - args: (_Advance, (AnyForwardIndex.Distance, AnyForwardIndex)) -) -> AnyForwardIndex - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyForwardIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyForwardIndex, rhs: AnyForwardIndex) -> Bool - -/// A wrapper over an underlying `BidirectionalIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyBidirectionalCollection` -public struct AnyBidirectionalIndex : BidirectionalIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) - - /// Return the next consecutive value in a discrete sequence of - /// `AnyBidirectionalIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyBidirectionalIndex - - /// Return the previous consecutive value in a discrete sequence of - /// `AnyBidirectionalIndex` values. - /// - /// Requires: `self` has a well-defined predecessor. - public func predecessor() -> AnyBidirectionalIndex - - - //===--- private --------------------------------------------------------===// - - - -} - -public func ~> ( - start: AnyBidirectionalIndex, other : (_Distance, AnyBidirectionalIndex) -) -> AnyBidirectionalIndex.Distance - -public func ~> ( - start: AnyBidirectionalIndex, distance : (_Advance, AnyBidirectionalIndex.Distance) -) -> AnyBidirectionalIndex - -public func ~> ( - start: AnyBidirectionalIndex, - args: (_Advance, (AnyBidirectionalIndex.Distance, AnyBidirectionalIndex)) -) -> AnyBidirectionalIndex - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyBidirectionalIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyBidirectionalIndex, rhs: AnyBidirectionalIndex) -> Bool - -/// A wrapper over an underlying `RandomAccessIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyRandomAccessCollection` -public struct AnyRandomAccessIndex : RandomAccessIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) - - /// Return the next consecutive value in a discrete sequence of - /// `AnyRandomAccessIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyRandomAccessIndex - - /// Return the previous consecutive value in a discrete sequence of - /// `AnyRandomAccessIndex` values. - /// - /// Requires: `self` has a well-defined predecessor. - public func predecessor() -> AnyRandomAccessIndex - - /// Return the minimum number of applications of `successor` or - /// `predecessor` required to reach `other` from `self`. - /// - /// Requires: `self` and `other` wrap instances of the same type. - public func distanceTo(other: AnyRandomAccessIndex) -> Distance - - /// Return `self` offset by `n` steps. - /// - /// - Returns: If `n > 0`, the result of applying `successor` to - /// `self` `n` times. If `n < 0`, the result of applying - /// `predecessor` to `self` `n` times. Otherwise, `self`. - public func advancedBy(amount: Distance) -> AnyRandomAccessIndex - - //===--- private --------------------------------------------------------===// - - - -} - -public func ~> ( - start: AnyRandomAccessIndex, other : (_Distance, AnyRandomAccessIndex) -) -> AnyRandomAccessIndex.Distance - -public func ~> ( - start: AnyRandomAccessIndex, distance : (_Advance, AnyRandomAccessIndex.Distance) -) -> AnyRandomAccessIndex - -public func ~> ( - start: AnyRandomAccessIndex, - args: (_Advance, (AnyRandomAccessIndex.Distance, AnyRandomAccessIndex)) -) -> AnyRandomAccessIndex - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyRandomAccessIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyRandomAccessIndex, rhs: AnyRandomAccessIndex) -> Bool - -//===--- Collections ------------------------------------------------------===// -//===----------------------------------------------------------------------===// - - -/// A protocol for `AnyForwardCollection`, -/// `AnyBidirectionalCollection`, and -/// `AnyRandomAccessCollection`. -/// -/// This protocol can be considered an implementation detail of the -/// `===` and `!==` implementations for these types. -public protocol AnyCollectionType : CollectionType { - /// Identifies the underlying collection stored by `self`. Instances - /// copied from one another have the same `underlyingCollectionID`. - var underlyingCollectionID: ObjectIdentifier {get} -} - -/// Return true iff `lhs` and `rhs` store the same underlying collection. -public func === < - L: AnyCollectionType, R: AnyCollectionType ->(lhs: L, rhs: R) -> Bool - -/// Return false iff `lhs` and `rhs` store the same underlying collection. -public func !== < - L: AnyCollectionType, R: AnyCollectionType ->(lhs: L, rhs: R) -> Bool - -/// A type-erased wrapper over any collection with at least -/// forward indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyBidirectionalType`, `AnyRandomAccessType` -public struct AnyForwardCollection : AnyCollectionType { - - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: ForwardIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyForwardCollection) - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: BidirectionalIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyBidirectionalCollection) - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) - - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyForwardIndex - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyForwardIndex - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyForwardIndex) -> Element - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier - -} -/// A type-erased wrapper over any collection with at least -/// bidirectional indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyRandomAccessType`, `AnyForwardType` -public struct AnyBidirectionalCollection : AnyCollectionType { - - /// Create an `AnyBidirectionalCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: BidirectionalIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyBidirectionalCollection) - /// Create an `AnyBidirectionalCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) - - /// If the indices of the underlying collection stored by `other` - /// satisfy `BidirectionalIndexType`, create an - /// `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyForwardCollection) - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyBidirectionalIndex - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyBidirectionalIndex - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyBidirectionalIndex) -> Element - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier - -} -/// A type-erased wrapper over any collection with at least -/// randomaccess indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyForwardType`, `AnyBidirectionalType` -public struct AnyRandomAccessCollection : AnyCollectionType { - - /// Create an `AnyRandomAccessCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) - - /// Create an `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) - - /// If the indices of the underlying collection stored by `other` - /// satisfy `RandomAccessIndexType`, create an - /// `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyForwardCollection) - /// If the indices of the underlying collection stored by `other` - /// satisfy `RandomAccessIndexType`, create an - /// `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyBidirectionalCollection) - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyRandomAccessIndex - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyRandomAccessIndex - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyRandomAccessIndex) -> Element - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier - -} - diff --git a/test/IDE/Inputs/mock-sdk/Foo.annotated.txt b/test/IDE/Inputs/mock-sdk/Foo.annotated.txt index c0b4caa8b10e7..02dc2fdde746d 100644 --- a/test/IDE/Inputs/mock-sdk/Foo.annotated.txt +++ b/test/IDE/Inputs/mock-sdk/Foo.annotated.txt @@ -253,6 +253,8 @@ class FooClassDerived : FooClassBase, init!() convenience init!(float f: Float) } +class FooCFType { +} typealias FooCFTypeRef = FooCFType @available(*, unavailable, message="Core Foundation objects are automatically memory managed") func FooCFTypeRelease(_: FooCFType!) @@ -265,10 +267,10 @@ func FooCFTypeRelease(_: FooCFType!) extension FooRepeatedMembers { var repeatedPropertyInCategory: Int32 func repeatedMethodInCategory() - var repeatedPropertyFromCategory: Int32 - func repeatedMethodFromCategory() } extension FooRepeatedMembers { + var repeatedPropertyFromCategory: Int32 + func repeatedMethodFromCategory() } enum SCNFilterMode : Int { init?(rawValue: Int) diff --git a/test/IDE/Inputs/mock-sdk/Foo.printed.recursive.txt b/test/IDE/Inputs/mock-sdk/Foo.printed.recursive.txt index eddfb32e395bb..d353b924a6583 100644 --- a/test/IDE/Inputs/mock-sdk/Foo.printed.recursive.txt +++ b/test/IDE/Inputs/mock-sdk/Foo.printed.recursive.txt @@ -253,6 +253,8 @@ class FooUnavailableMembers : FooClassBase { init!() convenience init!(float f: Float) } +class FooCFType { +} typealias FooCFTypeRef = FooCFType @available(*, unavailable, message="Core Foundation objects are automatically memory managed") func FooCFTypeRelease(_: FooCFType!) @@ -265,10 +267,10 @@ class FooRepeatedMembers : FooClassBase { extension FooRepeatedMembers { var repeatedPropertyInCategory: Int32 func repeatedMethodInCategory() - var repeatedPropertyFromCategory: Int32 - func repeatedMethodFromCategory() } extension FooRepeatedMembers { + var repeatedPropertyFromCategory: Int32 + func repeatedMethodFromCategory() } enum SCNFilterMode : Int { init?(rawValue: Int) diff --git a/test/IDE/Inputs/mock-sdk/Foo.printed.txt b/test/IDE/Inputs/mock-sdk/Foo.printed.txt index 60f4d4872bc12..b2a28056777ea 100644 --- a/test/IDE/Inputs/mock-sdk/Foo.printed.txt +++ b/test/IDE/Inputs/mock-sdk/Foo.printed.txt @@ -307,6 +307,8 @@ class FooUnavailableMembers : FooClassBase { convenience init!(float f: Float) } +class FooCFType { +} typealias FooCFTypeRef = FooCFType @available(*, unavailable, message="Core Foundation objects are automatically memory managed") func FooCFTypeRelease(_: FooCFType!) @@ -321,12 +323,11 @@ class FooRepeatedMembers : FooClassBase { extension FooRepeatedMembers { var repeatedPropertyInCategory: Int32 func repeatedMethodInCategory() - - var repeatedPropertyFromCategory: Int32 - func repeatedMethodFromCategory() } extension FooRepeatedMembers { + var repeatedPropertyFromCategory: Int32 + func repeatedMethodFromCategory() } enum SCNFilterMode : Int { diff --git a/test/IDE/Inputs/print_clang_header_swift_name.h b/test/IDE/Inputs/print_clang_header_swift_name.h new file mode 100644 index 0000000000000..ec18c17477692 --- /dev/null +++ b/test/IDE/Inputs/print_clang_header_swift_name.h @@ -0,0 +1,31 @@ +@import Foundation; + +#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) + +#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type + +typedef SWIFT_ENUM(NSInteger, Normal) { + NormalOne = 0, + NormalTwo, + NormalThree +}; + +// FIXME (#618): Use SWIFT_ENUM_NAMED() when support for that lands +#undef SWIFT_ENUM +#define SWIFT_ENUM(_type, _name) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME); enum SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME) SWIFT_ENUM_EXTRA _name : _type + +#define SWIFT_ENUM_NAME "SwiftEnum" +typedef SWIFT_ENUM(NSInteger, ObjCEnum) { + ObjCEnumOne = 0, + ObjCEnumTwo, + ObjCEnumThree +}; + +#undef SWIFT_ENUM_NAME +#define SWIFT_ENUM_NAME "SwiftEnumTwo" +typedef SWIFT_ENUM(NSInteger, ObjCEnumTwo) { + // the following shouldn't have their prefixes stripped + SwiftEnumTwoA, + SwiftEnumTwoB, + SwiftEnumTwoC +}; diff --git a/test/IDE/Inputs/swift_name_objc.h b/test/IDE/Inputs/swift_name_objc.h index 4bf11b0d8951d..a9c42c4004471 100644 --- a/test/IDE/Inputs/swift_name_objc.h +++ b/test/IDE/Inputs/swift_name_objc.h @@ -1,4 +1,4 @@ -@import ObjectiveC; +@import Foundation; #define SWIFT_NAME(X) __attribute__((swift_name(#X))) @@ -45,6 +45,12 @@ SWIFT_NAME(SomeProtocol) @end @protocol SNCollision +@property (readonly,nonnull) id reqSetter; +- (void)setReqSetter:(nonnull id)bar; + +@property (readonly,nonnull) id optSetter; +@optional +- (void)setOptSetter:(nonnull id)bar; @end @protocol NSAccessibility diff --git a/test/IDE/annotation.swift b/test/IDE/annotation.swift index 63e5b4352b344..ce4c68baf152d 100644 --- a/test/IDE/annotation.swift +++ b/test/IDE/annotation.swift @@ -81,7 +81,7 @@ class SubCls : MyCls, Prot { var protocolProperty2 = 0 } -// CHECK: func genFn<T : Prot where T.Blarg : Prot2>(p : T) -> Int {}{{$}} +// CHECK: func genFn<T : Prot where T.Blarg : Prot2>(p : T) -> Int {}{{$}} func genFn(p : T) -> Int {} func test(x: Int) { diff --git a/test/IDE/coloring.swift b/test/IDE/coloring.swift index 34d782dccda70..ad803d4da57ee 100644 --- a/test/IDE/coloring.swift +++ b/test/IDE/coloring.swift @@ -204,7 +204,7 @@ protocol Prot2 : Prot {} // CHECK: class SubCls : MyCls, Prot {} class SubCls : MyCls, Prot {} -// CHECK: func genFnProt where T.Blarg : Prot2>(_: T) -> Int {}{{$}} +// CHECK: func genFnProt where T.Blarg : Prot2>(_: T) -> Int {}{{$}} func genFn(_: T) -> Int {} func f(x: Int) -> Int { @@ -429,10 +429,21 @@ func emptyDocBlockComment3() {} /**/ -func malformedBlockComment(f : ()throws->()) rethrows {} +func malformedBlockComment(f : () throws -> ()) rethrows {} // CHECK: /**/ -// CHECK: func malformedBlockComment(f : ()throws->()) rethrows {} +// CHECK: func malformedBlockComment(f : () throws -> ()) rethrows {} +//: playground doc comment line +func playgroundCommentLine(f : () throws -> ()) rethrows {} +// CHECK: //: playground doc comment line + +/*: + playground doc comment multi-line +*/ +func playgroundCommentMultiLine(f : () throws -> ()) rethrows {} +// CHECK: /*: +// CHECK: playground doc comment multi-line +// CHECK: */ "--\"\(x) --" // CHECK: "--\"\(x) --" diff --git a/test/IDE/coloring_playground.swift b/test/IDE/coloring_playground.swift new file mode 100644 index 0000000000000..412820aa2249a --- /dev/null +++ b/test/IDE/coloring_playground.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-ide-test -syntax-coloring -playground -source-filename %s | FileCheck %s +// RUN: %target-swift-ide-test -syntax-coloring -playground -typecheck -source-filename %s | FileCheck %s + +//: playground doc comment line +func playgroundCommentLine(f : () throws -> ()) rethrows {} +// CHECK: //: playground doc comment line + +/*: + playground doc comment multi-line +*/ +func playgroundCommentMultiLine(f : () throws -> ()) rethrows {} +// CHECK: /*: +// CHECK: playground doc comment multi-line +// CHECK: */ + +// Keep this as the last test +/** + Trailing off ... +func unterminatedBlockComment() {} +// CHECK: // Keep this as the last test +// CHECK: /** +// CHECK: Trailing off ... +// CHECK: func unterminatedBlockComment() {} +// CHECK: diff --git a/test/IDE/comment_attach.swift b/test/IDE/comment_attach.swift index 55452655bbf40..e3138dcbe4d94 100644 --- a/test/IDE/comment_attach.swift +++ b/test/IDE/comment_attach.swift @@ -149,7 +149,7 @@ struct decl_struct_1 { /// NestedEnum Aaa. enum NestedEnum {} - // Can not declare a nested protocol. + // Cannot declare a nested protocol. // protocol NestedProtocol {} /// NestedTypealias Aaa. @@ -277,7 +277,7 @@ func unterminatedBlockDocComment() {} // CHECK-NEXT: comment_attach.swift:135:8: Func/decl_struct_1.instanceFunc4 RawComment=[/// instanceFunc4 Aaa.\n] // CHECK-NEXT: comment_attach.swift:138:3: Constructor/decl_struct_1.init RawComment=[/// init(). Aaa.\n] BriefComment=[init(). Aaa.] // CHECK-NEXT: comment_attach.swift:141:3: Subscript/decl_struct_1.subscript RawComment=[/// subscript Aaa.\n] -// CHECK-NEXT: comment_attach.swift:141:13: Param/decl_struct_1.i RawComment=none +// CHECK-NEXT: comment_attach.swift:141:13: Param/i RawComment=none // CHECK-NEXT: comment_attach.swift:141:31: Func/decl_struct_1. RawComment=none // CHECK-NEXT: comment_attach.swift:144:10: Struct/decl_struct_1.NestedStruct RawComment=[/// NestedStruct Aaa.\n] // CHECK-NEXT: comment_attach.swift:147:9: Class/decl_struct_1.NestedClass RawComment=[/// NestedClass Aaa.\n] diff --git a/test/IDE/comment_extensions.swift b/test/IDE/comment_extensions.swift index 57e33f9f7485a..f5091520c1181 100644 --- a/test/IDE/comment_extensions.swift +++ b/test/IDE/comment_extensions.swift @@ -59,4 +59,3 @@ // CHECK: {{.*}}DocCommentAsXML=[urlWithQueryString()s:F14swift_ide_test18urlWithQueryStringFT_T_func urlWithQueryString()Brief.Test a link] // CHECK: {{.*}}DocCommentAsXML=[imageWithAmpersandsInTitleAndAlt()s:F14swift_ide_test32imageWithAmpersandsInTitleAndAltFT_T_func imageWithAmpersandsInTitleAndAlt()Brief.]]>] - diff --git a/test/IDE/complete_after_self.swift b/test/IDE/complete_after_self.swift index 78fc483e268a0..a7f84d095f3ac 100644 --- a/test/IDE/complete_after_self.swift +++ b/test/IDE/complete_after_self.swift @@ -96,7 +96,7 @@ class ThisDerived1 : ThisBase1 { } } - subscript(#s: String) -> Int { + subscript(s s: String) -> Int { get { return 0 } diff --git a/test/IDE/complete_associated_types.swift b/test/IDE/complete_associated_types.swift index 64f1157aa4c55..461c6e4cdcbb1 100644 --- a/test/IDE/complete_associated_types.swift +++ b/test/IDE/complete_associated_types.swift @@ -23,28 +23,28 @@ // FIXME: extensions that introduce conformances? protocol FooBaseProtocolWithAssociatedTypes { - typealias DefaultedTypeCommonA = Int - typealias DefaultedTypeCommonB = Int - typealias DefaultedTypeCommonC = Int - typealias DefaultedTypeCommonD = Int - - typealias FooBaseDefaultedTypeA = Int - typealias FooBaseDefaultedTypeB = Int - typealias FooBaseDefaultedTypeC = Int - - typealias DeducedTypeCommonA - typealias DeducedTypeCommonB - typealias DeducedTypeCommonC - typealias DeducedTypeCommonD + associatedtype DefaultedTypeCommonA = Int + associatedtype DefaultedTypeCommonB = Int + associatedtype DefaultedTypeCommonC = Int + associatedtype DefaultedTypeCommonD = Int + + associatedtype FooBaseDefaultedTypeA = Int + associatedtype FooBaseDefaultedTypeB = Int + associatedtype FooBaseDefaultedTypeC = Int + + associatedtype DeducedTypeCommonA + associatedtype DeducedTypeCommonB + associatedtype DeducedTypeCommonC + associatedtype DeducedTypeCommonD func deduceCommonA() -> DeducedTypeCommonA func deduceCommonB() -> DeducedTypeCommonB func deduceCommonC() -> DeducedTypeCommonC func deduceCommonD() -> DeducedTypeCommonD - typealias FooBaseDeducedTypeA - typealias FooBaseDeducedTypeB - typealias FooBaseDeducedTypeC - typealias FooBaseDeducedTypeD + associatedtype FooBaseDeducedTypeA + associatedtype FooBaseDeducedTypeB + associatedtype FooBaseDeducedTypeC + associatedtype FooBaseDeducedTypeD func deduceFooBaseA() -> FooBaseDeducedTypeA func deduceFooBaseB() -> FooBaseDeducedTypeB func deduceFooBaseC() -> FooBaseDeducedTypeC @@ -52,35 +52,35 @@ protocol FooBaseProtocolWithAssociatedTypes { } protocol FooProtocolWithAssociatedTypes : FooBaseProtocolWithAssociatedTypes { // From FooBase. - typealias DefaultedTypeCommonA = Int - typealias DefaultedTypeCommonB = Int + associatedtype DefaultedTypeCommonA = Int + associatedtype DefaultedTypeCommonB = Int - typealias FooBaseDefaultedTypeB = Double + associatedtype FooBaseDefaultedTypeB = Double - typealias DeducedTypeCommonA - typealias DeducedTypeCommonB + associatedtype DeducedTypeCommonA + associatedtype DeducedTypeCommonB func deduceCommonA() -> DeducedTypeCommonA func deduceCommonB() -> DeducedTypeCommonB func deduceFooBaseB() -> Int // New decls. - typealias FooDefaultedType = Int + associatedtype FooDefaultedType = Int - typealias FooDeducedTypeB - typealias FooDeducedTypeC - typealias FooDeducedTypeD + associatedtype FooDeducedTypeB + associatedtype FooDeducedTypeC + associatedtype FooDeducedTypeD func deduceFooB() -> FooDeducedTypeB func deduceFooC() -> FooDeducedTypeC func deduceFooD() -> FooDeducedTypeD } protocol BarBaseProtocolWithAssociatedTypes { // From FooBase. - typealias DefaultedTypeCommonA = Int - typealias DefaultedTypeCommonC = Int + associatedtype DefaultedTypeCommonA = Int + associatedtype DefaultedTypeCommonC = Int - typealias DeducedTypeCommonA - typealias DeducedTypeCommonC + associatedtype DeducedTypeCommonA + associatedtype DeducedTypeCommonC func deduceCommonA() -> DeducedTypeCommonA func deduceCommonC() -> DeducedTypeCommonC @@ -90,20 +90,20 @@ protocol BarBaseProtocolWithAssociatedTypes { func deduceFooC() -> Int // New decls. - typealias BarBaseDefaultedType = Int + associatedtype BarBaseDefaultedType = Int - typealias BarBaseDeducedTypeC - typealias BarBaseDeducedTypeD + associatedtype BarBaseDeducedTypeC + associatedtype BarBaseDeducedTypeD func deduceBarBaseC() -> BarBaseDeducedTypeC func deduceBarBaseD() -> BarBaseDeducedTypeD } protocol BarProtocolWithAssociatedTypes : BarBaseProtocolWithAssociatedTypes { // From FooBase. - typealias DefaultedTypeCommonA = Int - typealias DefaultedTypeCommonD = Int + associatedtype DefaultedTypeCommonA = Int + associatedtype DefaultedTypeCommonD = Int - typealias DeducedTypeCommonA - typealias DeducedTypeCommonD + associatedtype DeducedTypeCommonA + associatedtype DeducedTypeCommonD func deduceCommonA() -> DeducedTypeCommonA func deduceCommonD() -> DeducedTypeCommonD @@ -116,9 +116,9 @@ protocol BarProtocolWithAssociatedTypes : BarBaseProtocolWithAssociatedTypes { func deduceBarBaseD() -> Int // New decls. - typealias BarDefaultedTypeA = Int + associatedtype BarDefaultedTypeA = Int - typealias BarDeducedTypeD + associatedtype BarDeducedTypeD func deduceBarD() -> BarDeducedTypeD } @@ -234,30 +234,30 @@ class MoreDerivedFromClassWithAssociatedTypes : DerivedFromClassWithAssociatedTy } } // ASSOCIATED_TYPES_UNQUAL: Begin completions -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DefaultedTypeCommonA[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DefaultedTypeCommonD[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DeducedTypeCommonA[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DeducedTypeCommonD[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: BarDefaultedTypeA[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: BarDeducedTypeD[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DefaultedTypeCommonC[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DeducedTypeCommonC[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: BarBaseDefaultedType[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: BarBaseDeducedTypeC[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: BarBaseDeducedTypeD[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DefaultedTypeCommonB[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG-FIXME: Decl[TypeAlias]/Super: FooBaseDefaultedTypeB[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: DeducedTypeCommonB[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooDefaultedType[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooDeducedTypeB[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooDeducedTypeC[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooDeducedTypeD[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDefaultedTypeA[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDefaultedTypeC[#Double#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDeducedTypeA[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDeducedTypeB[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDeducedTypeC[#Int#]{{; name=.+$}} -// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[TypeAlias]/Super: FooBaseDeducedTypeD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DefaultedTypeCommonA[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DefaultedTypeCommonD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DeducedTypeCommonA[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DeducedTypeCommonD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: BarDefaultedTypeA[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: BarDeducedTypeD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DefaultedTypeCommonC[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DeducedTypeCommonC[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: BarBaseDefaultedType[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: BarBaseDeducedTypeC[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: BarBaseDeducedTypeD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DefaultedTypeCommonB[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG-FIXME: Decl[AssociatedType]/Super: FooBaseDefaultedTypeB[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: DeducedTypeCommonB[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooDefaultedType[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooDeducedTypeB[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooDeducedTypeC[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooDeducedTypeD[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDefaultedTypeA[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDefaultedTypeB[#Double#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDeducedTypeA[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDeducedTypeB[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDeducedTypeC[#Int#]{{; name=.+$}} +// ASSOCIATED_TYPES_UNQUAL-DAG: Decl[AssociatedType]/Super: FooBaseDeducedTypeD[#Int#]{{; name=.+$}} // ASSOCIATED_TYPES_UNQUAL: End completions struct StructWithBrokenConformance : FooProtocolWithAssociatedTypes { diff --git a/test/IDE/complete_crashes.swift b/test/IDE/complete_crashes.swift index 9c744bea9c2e6..a03f75c7f4c54 100644 --- a/test/IDE/complete_crashes.swift +++ b/test/IDE/complete_crashes.swift @@ -165,3 +165,26 @@ func rdar23173692() { return IndexingGenerator(#^RDAR_23173692^#) } // RDAR_23173692: Begin completions + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RDAR_22769393 | FileCheck %s -check-prefix=RDAR_22769393 +public enum PropertyListItem { + case PLString(String) + case PLDict([String:PropertyListItem]) +} +class Connection { + var handler: (Int32, [UInt8]) -> () = { _ in } +} +private let conn = Connection() +conn.handler = { (msgID, msg) in + // Otherwise, we should have a structured message. + let info = { () -> PropertyListItem in }() + guard case .PLDict(var infoItems) = info else { fatalError("invalid message") } + guard case .Some(.PLString(let command)) = infoItems["command"] else { fatalError("invalid message") } + switch command { + case "listSessions": + var items = #^RDAR_22769393^# + default: + break + } +} +// RDAR_22769393: Begin completions diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 115ca3bed1258..ecd9f4942603b 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -43,9 +43,10 @@ func method(@#^KEYWORD1^#) {} @#^KEYWORD2^# func method(){} -// KEYWORD2: Begin completions, 9 items +// KEYWORD2: Begin completions, 10 items // KEYWORD2-NEXT: Keyword/None: available[#Func Attribute#]; name=available{{$}} // KEYWORD2-NEXT: Keyword/None: objc[#Func Attribute#]; name=objc{{$}} +// KEYWORD2-NEXT: Keyword/None: swift3_migration[#Func Attribute#]; name=swift3_migration{{$}} // KEYWORD2-NEXT: Keyword/None: noreturn[#Func Attribute#]; name=noreturn{{$}} // KEYWORD2-NEXT: Keyword/None: IBAction[#Func Attribute#]; name=IBAction{{$}} // KEYWORD2-NEXT: Keyword/None: NSManaged[#Func Attribute#]; name=NSManaged{{$}} @@ -58,9 +59,10 @@ func method(){} @#^KEYWORD3^# class C {} -// KEYWORD3: Begin completions, 7 items +// KEYWORD3: Begin completions, 8 items // KEYWORD3-NEXT: Keyword/None: available[#Class Attribute#]; name=available{{$}} // KEYWORD3-NEXT: Keyword/None: objc[#Class Attribute#]; name=objc{{$}} +// KEYWORD3-NEXT: Keyword/None: swift3_migration[#Class Attribute#]; name=swift3_migration{{$}} // KEYWORD3-NEXT: Keyword/None: IBDesignable[#Class Attribute#]; name=IBDesignable{{$}} // KEYWORD3-NEXT: Keyword/None: UIApplicationMain[#Class Attribute#]; name=UIApplicationMain{{$}} // KEYWORD3-NEXT: Keyword/None: requires_stored_property_inits[#Class Attribute#]; name=requires_stored_property_inits{{$}} @@ -70,24 +72,27 @@ class C {} @#^KEYWORD4^# enum E {} -// KEYWORD4: Begin completions, 2 items +// KEYWORD4: Begin completions, 3 items // KEYWORD4-NEXT: Keyword/None: available[#Enum Attribute#]; name=available{{$}} // KEYWORD4-NEXT: Keyword/None: objc[#Enum Attribute#]; name=objc{{$}} +// KEYWORD4-NEXT: Keyword/None: swift3_migration[#Enum Attribute#]; name=swift3_migration{{$}} // KEYWORD4-NEXT: End completions @#^KEYWORD5^# struct S{} -// KEYWORD5: Begin completions, 1 items +// KEYWORD5: Begin completions, 2 items // KEYWORD5-NEXT: Keyword/None: available[#Struct Attribute#]; name=available{{$}} +// KEYWORD5-NEXT: Keyword/None: swift3_migration[#Struct Attribute#]; name=swift3_migration{{$}} // KEYWORD5-NEXT: End completions @#^KEYWORD_LAST^# -// KEYWORD_LAST: Begin completions, 19 items +// KEYWORD_LAST: Begin completions, 20 items // KEYWORD_LAST-NEXT: Keyword/None: available[#Declaration Attribute#]; name=available{{$}} // KEYWORD_LAST-NEXT: Keyword/None: objc[#Declaration Attribute#]; name=objc{{$}} +// KEYWORD_LAST-NEXT: Keyword/None: swift3_migration[#Declaration Attribute#]; name=swift3_migration{{$}} // KEYWORD_LAST-NEXT: Keyword/None: noreturn[#Declaration Attribute#]; name=noreturn{{$}} // KEYWORD_LAST-NEXT: Keyword/None: NSCopying[#Declaration Attribute#]; name=NSCopying{{$}} // KEYWORD_LAST-NEXT: Keyword/None: IBAction[#Declaration Attribute#]; name=IBAction{{$}} diff --git a/test/IDE/complete_dynamic_lookup.swift b/test/IDE/complete_dynamic_lookup.swift index e849ad667cf6c..8ce42b41ac4f1 100644 --- a/test/IDE/complete_dynamic_lookup.swift +++ b/test/IDE/complete_dynamic_lookup.swift @@ -13,11 +13,6 @@ // RUN: FileCheck %s -check-prefix=DL_INSTANCE_DOT < %t.dl.txt // RUN: FileCheck %s -check-prefix=GLOBAL_NEGATIVE < %t.dl.txt -// FIXME: Redundant with above, except for -enable-swift-name-lookup-tables -// RUN: %target-swift-ide-test -code-completion -source-filename %s -I %t -disable-objc-attr-requires-foundation-module -code-completion-token=DL_FUNC_PARAM_DOT_1 -enable-swift-name-lookup-tables > %t.dl.txt -// RUN: FileCheck %s -check-prefix=DL_INSTANCE_DOT < %t.dl.txt -// RUN: FileCheck %s -check-prefix=GLOBAL_NEGATIVE < %t.dl.txt - // RUN: %target-swift-ide-test -code-completion -source-filename %s -I %t -disable-objc-attr-requires-foundation-module -code-completion-token=DL_VAR_NO_DOT_1 > %t.dl.txt // RUN: FileCheck %s -check-prefix=DL_INSTANCE_NO_DOT < %t.dl.txt // RUN: FileCheck %s -check-prefix=GLOBAL_NEGATIVE < %t.dl.txt diff --git a/test/IDE/complete_enum_elements.swift b/test/IDE/complete_enum_elements.swift index 4c6168876ab5f..f573c6ae10287 100644 --- a/test/IDE/complete_enum_elements.swift +++ b/test/IDE/complete_enum_elements.swift @@ -236,14 +236,14 @@ enum QuxEnum : Int { // QUX_ENUM_NO_DOT-NEXT: Decl[EnumElement]/CurrNominal: .Qux1[#QuxEnum#]{{; name=.+$}} // QUX_ENUM_NO_DOT-NEXT: Decl[EnumElement]/CurrNominal: .Qux2[#QuxEnum#]{{; name=.+$}} // QUX_ENUM_NO_DOT-NEXT: Decl[Constructor]/CurrNominal: ({#rawValue: Int#})[#QuxEnum?#]{{; name=.+$}} -// QUX_ENUM_NO_DOT-NEXT: Decl[TypeAlias]/Super: .RawValue[#Int#]{{; name=.+$}} +// QUX_ENUM_NO_DOT-NEXT: Decl[AssociatedType]/Super: .RawValue[#Int#]{{; name=.+$}} // QUX_ENUM_NO_DOT-NEXT: End completions // QUX_ENUM_DOT: Begin completions, 4 items // QUX_ENUM_DOT-NEXT: Decl[EnumElement]/CurrNominal: Qux1[#QuxEnum#]{{; name=.+$}} // QUX_ENUM_DOT-NEXT: Decl[EnumElement]/CurrNominal: Qux2[#QuxEnum#]{{; name=.+$}} // QUX_ENUM_DOT-NEXT: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#QuxEnum?#]{{; name=.+$}} -// QUX_ENUM_DOT-NEXT: Decl[TypeAlias]/Super: RawValue[#Int#]{{; name=.+$}} +// QUX_ENUM_DOT-NEXT: Decl[AssociatedType]/Super: RawValue[#Int#]{{; name=.+$}} // QUX_ENUM_DOT-NEXT: End completions func freeFunc() {} diff --git a/test/IDE/complete_expr_tuple.swift b/test/IDE/complete_expr_tuple.swift index 4ddf870c7c7e0..93e309ac9dae4 100644 --- a/test/IDE/complete_expr_tuple.swift +++ b/test/IDE/complete_expr_tuple.swift @@ -27,27 +27,45 @@ func testTupleNoDot1() { var t = (1, 2.0) t#^TUPLE_NO_DOT_1^# } -// TUPLE_NO_DOT_1: Begin completions, 2 items -// TUPLE_NO_DOT_1-NEXT: Pattern/CurrNominal: .0[#Int#]{{; name=.+$}} -// TUPLE_NO_DOT_1-NEXT: Pattern/CurrNominal: .1[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_1: Begin completions, 8 items +// TUPLE_NO_DOT_1-DAG: Pattern/CurrNominal: .0[#Int#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Pattern/CurrNominal: .1[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: == {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: <= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: >= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: < {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_1-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: > {#(Int, Double)#}[#Bool#]{{; name=.+$}} // TUPLE_NO_DOT_1-NEXT: End completions func testTupleNoDot2() { var t = (foo: 1, bar: 2.0) t#^TUPLE_NO_DOT_2^# } -// TUPLE_NO_DOT_2: Begin completions, 2 items -// TUPLE_NO_DOT_2-NEXT: Pattern/CurrNominal: .foo[#Int#]{{; name=.+$}} -// TUPLE_NO_DOT_2-NEXT: Pattern/CurrNominal: .bar[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_2: Begin completions, 8 items +// TUPLE_NO_DOT_2-DAG: Pattern/CurrNominal: .foo[#Int#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Pattern/CurrNominal: .bar[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: == {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: <= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: >= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: < {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_2-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: > {#(Int, Double)#}[#Bool#]{{; name=.+$}} // TUPLE_NO_DOT_2-NEXT: End completions func testTupleNoDot3() { var t = (foo: 1, 2.0) t#^TUPLE_NO_DOT_3^# } -// TUPLE_NO_DOT_3: Begin completions, 2 items -// TUPLE_NO_DOT_3-NEXT: Pattern/CurrNominal: .foo[#Int#]{{; name=.+$}} -// TUPLE_NO_DOT_3-NEXT: Pattern/CurrNominal: .1[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_3: Begin completions, 8 items +// TUPLE_NO_DOT_3-DAG: Pattern/CurrNominal: .foo[#Int#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Pattern/CurrNominal: .1[#Double#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: == {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: <= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: >= {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: < {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#(Int, Double)#}[#Bool#]{{; name=.+$}} +// TUPLE_NO_DOT_3-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: > {#(Int, Double)#}[#Bool#]{{; name=.+$}} // TUPLE_NO_DOT_3-NEXT: End completions func testTupleDot1() { diff --git a/test/IDE/complete_generic_param.swift b/test/IDE/complete_generic_param.swift new file mode 100644 index 0000000000000..e162a5ddecf36 --- /dev/null +++ b/test/IDE/complete_generic_param.swift @@ -0,0 +1,36 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT1 | FileCheck %s -check-prefix=INHERIT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT2 | FileCheck %s -check-prefix=INHERIT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT3 | FileCheck %s -check-prefix=INHERIT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT4 | FileCheck %s -check-prefix=INHERIT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT5 | FileCheck %s -check-prefix=INHERIT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INHERIT6 | FileCheck %s -check-prefix=INHERIT + +class C1{} +protocol P1{} +struct S1{} + +let ValueInt1 = 1 +let ValueString2 = "" +func TopLevelFunc() {} + +func f1(p : S) {} +func f2(p : S) {} + func f2(p : S1) {} + func f2 ()) {} -func closureTaker2(theFunc: (Value1:Int, Value2:Int) ->()) {} +func closureTaker2(theFunc: (Value1:Int, Value2:Int) -> ()) {} func testClosureParam1() { closureTaker { (theValue) -> () in #^CLOSURE_PARAM_1^# diff --git a/test/IDE/complete_lazy_initialized_var.swift b/test/IDE/complete_lazy_initialized_var.swift index f06316f50c0eb..c708b17cd8894 100644 --- a/test/IDE/complete_lazy_initialized_var.swift +++ b/test/IDE/complete_lazy_initialized_var.swift @@ -7,7 +7,7 @@ func lazyInClass1(a: FooClass1) { a.#^LAZY_IN_CLASS_1^# } -// This test checks that we don’t include extra hidden declarations into code completion results. If you add more declarations to the type, update this test properly. +// This test checks that we don't include extra hidden declarations into code completion results. If you add more declarations to the type, update this test properly. // LAZYVAR1: Begin completions, 1 items // LAZYVAR1-NEXT: Decl[InstanceVar]/CurrNominal: lazyVar1[#Int#]{{; name=.+$}} // LAZYVAR1-NEXT: End completions diff --git a/test/IDE/complete_literal.swift b/test/IDE/complete_literal.swift index 85b46a5231713..43a1e4e8c02c1 100644 --- a/test/IDE/complete_literal.swift +++ b/test/IDE/complete_literal.swift @@ -2,6 +2,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL2 | FileCheck %s -check-prefix=LITERAL2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL3 | FileCheck %s -check-prefix=LITERAL3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL4 | FileCheck %s -check-prefix=LITERAL4 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL5 | FileCheck %s -check-prefix=LITERAL5 { 1.#^LITERAL1^# @@ -48,3 +49,14 @@ // LITERAL4-DAG: Decl[InstanceMethod]/CurrNominal: insertContentsOf({#(newElements): S#}, {#at: Index#})[#Void#]; name=insertContentsOf(newElements: S, at: Index){{$}} // LITERAL4-DAG: Decl[InstanceMethod]/CurrNominal: removeAtIndex({#(i): Index#})[#Character#]; name=removeAtIndex(i: Index){{$}} // LITERAL4-DAG: Decl[InstanceVar]/CurrNominal: lowercaseString[#String#]; name=lowercaseString{{$}} + +func giveMeAString() -> Int { + // rdar://22637799 + return "Here's a string".#^LITERAL5^# // try .characters.count here +} + +// LITERAL5-DAG: Decl[InstanceVar]/CurrNominal: characters[#String.CharacterView#]{{; name=.+$}} +// LITERAL5-DAG: Decl[InstanceVar]/CurrNominal: endIndex[#Index#]{{; name=.+$}} +// LITERAL5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: reserveCapacity({#(n): Int#})[#Void#]{{; name=.+$}} +// LITERAL5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: append({#(c): Character#})[#Void#]{{; name=.+$}} +// LITERAL5-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: appendContentsOf({#(newElements): S#})[#Void#]{{; name=.+$}} diff --git a/test/IDE/complete_member_decls_from_parent_decl_context.swift b/test/IDE/complete_member_decls_from_parent_decl_context.swift index 804465bb01558..faeb1ef23eb27 100644 --- a/test/IDE/complete_member_decls_from_parent_decl_context.swift +++ b/test/IDE/complete_member_decls_from_parent_decl_context.swift @@ -59,7 +59,7 @@ class CodeCompletionInClassMethods1 { struct NestedStruct {} class NestedClass {} enum NestedEnum {} - // Can not declare a nested protocol. + // Cannot declare a nested protocol. // protocol NestedProtocol {} typealias NestedTypealias = Int @@ -162,7 +162,7 @@ struct CodeCompletionInStructMethods1 { struct NestedStruct {} class NestedClass {} enum NestedEnum {} - // Can not declare a nested protocol. + // Cannot declare a nested protocol. // protocol NestedProtocol {} typealias NestedTypealias = Int diff --git a/test/IDE/complete_pound_selector.swift b/test/IDE/complete_pound_selector.swift new file mode 100644 index 0000000000000..74fe893d977a5 --- /dev/null +++ b/test/IDE/complete_pound_selector.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AFTER_POUND | FileCheck %s + +// REQUIRES: objc_interop + +{ + if ##^AFTER_POUND^# +} + +// CHECK: Keyword/ExprSpecific: available({#Platform...#}, *); name=available(Platform..., *) +// CHECK: Keyword/ExprSpecific: selector({#@objc method#}); name=selector(@objc method) diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 7c938d0a96114..b8ff38cbfc753 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -49,7 +49,7 @@ enum SomeEnum3 { } struct NotOptions1 { - static let NotSet = 1; + static let NotSet = 1 } struct SomeOptions1 : OptionSetType { @@ -178,7 +178,7 @@ OptionSetTaker6(.Option4, .#^UNRESOLVED_17^#,) var a = {() in OptionSetTaker5([.#^UNRESOLVED_18^#], .Option4, .South, .West) } -var Containner = OptionTakerContainer1() +var Container = OptionTakerContainer1() Container.OptionSetTaker1(.#^UNRESOLVED_19^# Container.EnumTaker1(.#^UNRESOLVED_20^# diff --git a/test/IDE/complete_value_expr.swift b/test/IDE/complete_value_expr.swift index 514de091fcac0..b300a49231ae9 100644 --- a/test/IDE/complete_value_expr.swift +++ b/test/IDE/complete_value_expr.swift @@ -188,7 +188,7 @@ struct FooStruct { mutating func instanceFunc6() -> Int! {} mutating - func instanceFunc7(#a: Int) {} + func instanceFunc7(a a: Int) {} mutating func instanceFunc8(a: (Int, Int)) {} mutating @@ -271,7 +271,7 @@ struct FooStruct { struct NestedStruct {} class NestedClass {} enum NestedEnum {} - // Can not declare a nested protocol. + // Cannot declare a nested protocol. // protocol NestedProtocol {} typealias NestedTypealias = Int @@ -1683,7 +1683,7 @@ func testTypealias1() { S.#^PROTOCOL_EXT_TA_2^# } // PROTOCOL_EXT_TA: Begin completions -// PROTOCOL_EXT_TA-DAG: Decl[TypeAlias]/{{Super|CurrNominal}}: T +// PROTOCOL_EXT_TA_2-DAG: Decl[AssociatedType]/{{Super|CurrNominal}}: T // PROTOCOL_EXT_TA: End completions func testProtExtInit1() { diff --git a/test/IDE/complete_vararg.swift b/test/IDE/complete_vararg.swift index eeef80632b717..753452b39fdc2 100644 --- a/test/IDE/complete_vararg.swift +++ b/test/IDE/complete_vararg.swift @@ -11,23 +11,23 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GENERIC_FREE_FUNC_1 | FileCheck %s -check-prefix=GENERIC_FREE_FUNC_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INTERESTING_TYPE_1 | FileCheck %s -check-prefix=INTERESTING_TYPE_1 -func freeFunc1(#x: Int...) { } -func freeFunc2(#x: Int, #y: Int...) { } -func freeFunc3(#w: Int...)(#x: Int...) { } +func freeFunc1(x x: Int...) { } +func freeFunc2(x x: Int, y y: Int...) { } +func freeFunc3(w w: Int...)(x x: Int...) { } class C { init(x: Int...) { } - func method1(#x: Int...) { } - func method2(#x: Int, y: Int...) { } - func method3(#w: Int...)(#x: Int...) { } - func method4(#`do` : Int...) {} + func method1(x x: Int...) { } + func method2(x x: Int, y: Int...) { } + func method3(w w: Int...)(x x: Int...) { } + func method4(`do` `do` : Int...) {} func method5(`class` : Int...) {} func method6(`class` `protocol`: Int...) {} subscript(i: Int...) -> Int { return 0 } } -func genericFreeFunc1(#t: T...) { } -func interestingType1(#x: (Int, (Int, String))...) { } +func genericFreeFunc1(t t: T...) { } +func interestingType1(x x: (Int, (Int, String))...) { } func testTopLevel() { #^TOP_LEVEL_1^# diff --git a/test/IDE/complete_where_clause.swift b/test/IDE/complete_where_clause.swift new file mode 100644 index 0000000000000..67cd2a43498c7 --- /dev/null +++ b/test/IDE/complete_where_clause.swift @@ -0,0 +1,38 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP1 | FileCheck %s -check-prefix=A1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP2 | FileCheck %s -check-prefix=A1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP3 | FileCheck %s -check-prefix=A1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP4 | FileCheck %s -check-prefix=TYPE1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GP5 | FileCheck %s -check-prefix=TYPE1 + +class A1 {} + +class A2 {} + +protocol P1 {} + +extension A1 where #^GP1^#{} + +extension A1 where T1 : P1, #^GP2^# {} + +extension A1 where T1 : P1, #^GP3^# + +extension A1 where T1 : #^GP4^# + +extension A1 where T1 : P1, T2 : #^GP5^# + +// A1: Begin completions +// A1-DAG: Decl[GenericTypeParam]/Local: T1[#T1#]; name=T1 +// A1-DAG: Decl[GenericTypeParam]/Local: T2[#T2#]; name=T2 +// A1-DAG: Decl[GenericTypeParam]/Local: T3[#T3#]; name=T3 +// A1-NOT: T4 +// A1-NOT: T5 + +// TYPE1: Begin completions +// TYPE1-DAG: Decl[Protocol]/CurrModule: P1[#P1#]; name=P1 +// TYPE1-DAG: Decl[Class]/CurrModule: A1[#A1#]; name=A1 +// TYPE1-DAG: Decl[Class]/CurrModule: A2[#A2#]; name=A2 +// TYPE1-NOT: T1 +// TYPE1-NOT: T2 +// TYPE1-NOT: T3 +// TYPE1-NOT: T4 +// TYPE1-NOT: T5 diff --git a/test/IDE/dump_api.swift b/test/IDE/dump_api.swift deleted file mode 100644 index f1adbd2c98770..0000000000000 --- a/test/IDE/dump_api.swift +++ /dev/null @@ -1,1005 +0,0 @@ -//===--- dump_api.swift ---------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// RUN: %target-swift-ide-test -dump-api -source-filename %s > %t.swift -// RUN: diff -du %S/Inputs/dumped_api.swift %t.swift - -//===--- Definitions needed only while experimental -----------------------===// -internal typealias _ContiguousArrayStorageBase = AnyObject -public struct _Distance {} -public struct _InitializeTo {} -extension _InitializeTo { init() {} } -extension _ContiguousArrayBuffer { - var _storage: _ContiguousArrayStorageBase { return owner } - init(_ owner: _ContiguousArrayStorageBase) { - self = unsafeBitCast(owner, _ContiguousArrayBuffer.self) - } -} - -//===----------------------------------------------------------------------===// - - -@noreturn @inline(never) -internal func _abstract(file: StaticString = __FILE__, line: UWord = __LINE__) { - fatalError("Method must be overridden", file: file, line: line) -} - -//===--- Generator --------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -public class _AnyGeneratorBase {} - -/// An abstract `GeneratorType` base class over `T` elements. -/// -/// Use this as a `Sequence`'s associated `Generator` type when you -/// don't want to expose details of the concrete generator, a subclass. -/// -/// It is an error to create instances of `AnyGenerator` that are not -/// also instances of an `AnyGenerator` subclass. -/// -/// See also: -/// -/// struct AnySequence -/// func anyGenerator(base: G) -> AnyGenerator -/// func anyGenerator(nextImplementation: ()->T?) -> AnyGenerator -public class AnyGenerator : _AnyGeneratorBase, GeneratorType { - /// Initialize the instance. May only be called from a subclass - /// initializer. - override public init() { - super.init() - _debugPrecondition( - _typeID(self) != unsafeBitCast(AnyGenerator.self, ObjectIdentifier.self), - "AnyGenerator instances can not be created; create a subclass instance instead." - ) - } - - /// Advance to the next element and return it, or `nil` if no next - /// element exists. - /// - /// Note: subclasses must override this method. - public func next() -> T? {_abstract()} -} - -/// Every `GeneratorType` can also be a `SequenceType`. Note that -/// traversing the sequence consumes the generator. -extension AnyGenerator : SequenceType { - /// Returns `self`. - public func generate() -> AnyGenerator { return self } -} - -/// Return a `GeneratorType` instance that wraps `base` but whose type -/// depends only on the type of `G.Element`. -/// -/// Example: -/// -/// func countStrings() -> AnyGenerator { -/// let lazyStrings = lazy(0..<10).map { String($0) } -/// -/// // This is a really complicated type of no interest to our -/// // clients. -/// let g: MapSequenceGenerator, String> -/// = lazyStrings.generate() -/// return anyGenerator(g) -/// } -public func anyGenerator(base: G) -> AnyGenerator { - return _GeneratorBox(base) -} - -internal class _FunctionGenerator : AnyGenerator { - init(_ nextImplementation: ()->T?) { - self.nextImplementation = nextImplementation - } - override func next() -> T? { return nextImplementation() } - let nextImplementation: ()->T? -} - -/// Return a `GeneratorType` instance whose `next` method invokes -/// `nextImplementation` and returns the result. -/// -/// Example: -/// -/// var x = 7 -/// let g = anyGenerator { x < 15 ? x++ : nil } -/// let a = Array(g) // [ 7, 8, 9, 10, 11, 12, 13, 14 ] -public func anyGenerator(nextImplementation: ()->T?) -> AnyGenerator { - return _FunctionGenerator(nextImplementation) -} - -internal final class _GeneratorBox< - Base: GeneratorType -> : AnyGenerator { - init(_ base: Base) { self.base = base } - override func next() -> Base.Element? { return base.next() } - var base: Base -} - -internal func _typeID(instance: AnyObject) -> ObjectIdentifier { - return ObjectIdentifier(instance.dynamicType) -} - -//===--- Sequence ---------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -internal class _AnySequenceBox { - // FIXME: can't make _AnySequenceBox generic and return - // _AnyGenerator here due to - func generate() -> _AnyGeneratorBase {_abstract()} - - func _underestimateCount() -> Int {_abstract()} - // FIXME: can't traffic in UnsafeMutablePointer and - // _ContiguousArrayBuffer here due to - func _initializeTo(ptr: UnsafeMutablePointer) {_abstract()} - func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase {_abstract()} -} - -internal class _AnyCollectionBoxBase : _AnySequenceBox { - init(startIndex: _ForwardIndexBoxType, endIndex: _ForwardIndexBoxType) { - self.startIndex = startIndex - self.endIndex = endIndex - } - let startIndex: _ForwardIndexBoxType - let endIndex: _ForwardIndexBoxType -} - -// FIXME: can't make this a protocol due to -internal class _SequenceBox - : _AnySequenceBox { - typealias Element = S.Generator.Element - - override func generate() -> _AnyGeneratorBase { - return _GeneratorBox(_base.generate()) - } - override func _underestimateCount() -> Int { - return Swift.underestimateCount(_base) - } - override func _initializeTo(ptr: UnsafeMutablePointer) { - _base~>(_InitializeTo(), UnsafeMutablePointer(ptr)) - } - override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { - return _base._copyToNativeArrayBuffer()._storage - } - init(_ base: S) { - self._base = base - } - internal var _base: S -} -// FIXME: can't make this a protocol due to -internal class _CollectionBox - : _AnyCollectionBox { - typealias Element = S.Generator.Element - - override func generate() -> _AnyGeneratorBase { - fatalError("") - } - override func _underestimateCount() -> Int { - return Swift.underestimateCount(_base) - } - override func _initializeTo(ptr: UnsafeMutablePointer) { - _base~>(_InitializeTo(), UnsafeMutablePointer(ptr)) - } - override func _copyToNativeArrayBuffer() -> _ContiguousArrayStorageBase { - return _base._copyToNativeArrayBuffer()._storage - } - override func _count() -> IntMax { - return 0 - } - override subscript(position: _ForwardIndexBoxType) -> Element { - if let i = position._unbox() as S.Index? { - return _base[i] - } - fatalError("Index type mismatch!") - } - init( - _ base: S, - startIndex: _ForwardIndexBoxType, - endIndex: _ForwardIndexBoxType - ) { - self._base = base - super.init(startIndex: startIndex, endIndex: endIndex) - } - internal var _base: S -} - -/// A type-erased sequence. -/// -/// Forwards operations to an arbitrary underlying sequence having the -/// same `Element` type, hiding the specifics of the underlying -/// `SequenceType`. -/// -/// See also: `AnyGenerator`. -public struct AnySequence : SequenceType { - typealias Element = T - - /// Wrap and forward operations to to `base` - public init(_ base: S) { - _box = _SequenceBox(base) - } - - /// Return a *generator* over the elements of this *sequence*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator { - return unsafeDowncast(_box.generate()) - } - - internal let _box: _AnySequenceBox -} - -public func ~> ( - source: AnySequence, - ptr: (_InitializeTo, UnsafeMutablePointer) -) { - source._box._initializeTo(UnsafeMutablePointer(ptr.1)) -} - -extension AnySequence { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { - return _ContiguousArrayBuffer(self._box._copyToNativeArrayBuffer()) - } -} - -public func ~> ( - source: AnyForwardCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) { - source._box._initializeTo(UnsafeMutablePointer(ptr.1)) -} - -extension AnyForwardCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { - return _ContiguousArrayBuffer(self._box._copyToNativeArrayBuffer()) - } -} - -public func ~> ( - source: AnyBidirectionalCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) { - source._box._initializeTo(UnsafeMutablePointer(ptr.1)) -} - -extension AnyBidirectionalCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { - return _ContiguousArrayBuffer(self._box._copyToNativeArrayBuffer()) - } -} - -public func ~> ( - source: AnyRandomAccessCollection, - ptr: (_InitializeTo, UnsafeMutablePointer) -) { - source._box._initializeTo(UnsafeMutablePointer(ptr.1)) -} - -extension AnyRandomAccessCollection { - public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { - return _ContiguousArrayBuffer(self._box._copyToNativeArrayBuffer()) - } -} - -//===--- ForwardIndex -----------------------------------------------------===// -//===----------------------------------------------------------------------===// - -internal protocol _ForwardIndexBoxType : class { - var typeID: ObjectIdentifier {get} - func successor() -> _ForwardIndexBoxType - func equals(other: _ForwardIndexBoxType) -> Bool - func _unbox() -> T? - func _distanceTo(other: _ForwardIndexBoxType) -> AnyForwardIndex.Distance - // FIXME: Can't return Self from _advancedBy pending - func _advancedBy(distance: AnyForwardIndex.Distance) -> _ForwardIndexBoxType - func _advancedBy( - distance: AnyForwardIndex.Distance, - _ limit: _ForwardIndexBoxType - ) -> _ForwardIndexBoxType -} - -internal class _ForwardIndexBox< - BaseIndex: ForwardIndexType -> : _ForwardIndexBoxType { - required init(_ base: BaseIndex) { - self.base = base - } - - func successor() -> _ForwardIndexBoxType { - return self.dynamicType(self.base.successor()) - } - - func unsafeUnbox(other: _ForwardIndexBoxType) -> BaseIndex { - return (unsafeDowncast(other) as _ForwardIndexBox).base - } - - func equals(other: _ForwardIndexBoxType) -> Bool { - return base == unsafeUnbox(other) - } - - func _distanceTo(other: _ForwardIndexBoxType) -> AnyForwardIndex.Distance { - return numericCast(distance(base, unsafeUnbox(other))) - } - - func _advancedBy(n: AnyForwardIndex.Distance) -> _ForwardIndexBoxType { - return self.dynamicType(advance(base, numericCast(n))) - } - - func _advancedBy( - n: AnyForwardIndex.Distance, - _ limit: _ForwardIndexBoxType - ) -> _ForwardIndexBoxType { - return self.dynamicType(advance(base, numericCast(n), unsafeUnbox(limit))) - } - - func _unbox() -> T? { - if T.self is BaseIndex.Type { - _sanityCheck(BaseIndex.self is T.Type) - // This bit cast is really nothing as we have proven they are - // the same type. - return unsafeBitCast(base, T.self) - } - return nil - } - - var typeID: ObjectIdentifier { return _typeID(self) } - - internal // private - let base: BaseIndex -} - -//===--- BidirectionalIndex -----------------------------------------------===// -//===----------------------------------------------------------------------===// - -internal protocol _BidirectionalIndexBoxType : _ForwardIndexBoxType { - func predecessor() -> _BidirectionalIndexBoxType -} - -internal class _BidirectionalIndexBox< - BaseIndex: BidirectionalIndexType -> : _ForwardIndexBox, _BidirectionalIndexBoxType { - required init(_ base: BaseIndex) { - super.init(base) - } - - override func successor() -> _ForwardIndexBoxType { - return self.dynamicType(self.base.successor()) - } - - func predecessor() -> _BidirectionalIndexBoxType { - return self.dynamicType(self.base.predecessor()) - } -} - -//===--- RandomAccessIndex -----------------------------------------------===// -//===----------------------------------------------------------------------===// - -internal protocol _RandomAccessIndexBoxType : _BidirectionalIndexBoxType {} - -internal final class _RandomAccessIndexBox< - BaseIndex: RandomAccessIndexType -> : _BidirectionalIndexBox, _RandomAccessIndexBoxType { - required init(_ base: BaseIndex) { - super.init(base) - } -} - -//===--- All Index Protocols ----------------------------------------------===// -//===----------------------------------------------------------------------===// - - -/// A wrapper over an underlying `ForwardIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyForwardCollection` -public struct AnyForwardIndex : ForwardIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) { - _box = _ForwardIndexBox(base) - } - - /// Return the next consecutive value in a discrete sequence of - /// `AnyForwardIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyForwardIndex { - return AnyForwardIndex(_box.successor()) - } - - - - //===--- private --------------------------------------------------------===// - - internal var _typeID: ObjectIdentifier { - return _box.typeID - } - - internal init(_ box: _ForwardIndexBoxType) { - self._box = box - } - - internal let _box: _ForwardIndexBoxType -} - -public func ~> ( - start: AnyForwardIndex, other : (_Distance, AnyForwardIndex) -) -> AnyForwardIndex.Distance { - precondition( - start._typeID == other.1._typeID, - "distance: base index types differ.") - return start._box._distanceTo(other.1._box) -} - -public func ~> ( - start: AnyForwardIndex, distance : (_Advance, AnyForwardIndex.Distance) -) -> AnyForwardIndex { - return AnyForwardIndex(start._box._advancedBy(distance.1)) -} - -public func ~> ( - start: AnyForwardIndex, - args: (_Advance, (AnyForwardIndex.Distance, AnyForwardIndex)) -) -> AnyForwardIndex { - precondition( - start._typeID == args.1.1._typeID, "advance: base index types differ.") - return AnyForwardIndex(start._box._advancedBy(args.1.0, args.1.1._box)) -} - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyForwardIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyForwardIndex, rhs: AnyForwardIndex) -> Bool { - precondition(lhs._typeID == rhs._typeID, "base index types differ.") - return lhs._box.equals(rhs._box) -} - -/// A wrapper over an underlying `BidirectionalIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyBidirectionalCollection` -public struct AnyBidirectionalIndex : BidirectionalIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) { - _box = _BidirectionalIndexBox(base) - } - - /// Return the next consecutive value in a discrete sequence of - /// `AnyBidirectionalIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyBidirectionalIndex { - return AnyBidirectionalIndex(_box.successor()) - } - - /// Return the previous consecutive value in a discrete sequence of - /// `AnyBidirectionalIndex` values. - /// - /// Requires: `self` has a well-defined predecessor. - public func predecessor() -> AnyBidirectionalIndex { - return AnyBidirectionalIndex(_box.predecessor()) - } - - - //===--- private --------------------------------------------------------===// - - internal var _typeID: ObjectIdentifier { - return _box.typeID - } - - internal init(_ box: _ForwardIndexBoxType) { - self._box = box as! _BidirectionalIndexBoxType - } - - internal let _box: _BidirectionalIndexBoxType -} - -public func ~> ( - start: AnyBidirectionalIndex, other : (_Distance, AnyBidirectionalIndex) -) -> AnyBidirectionalIndex.Distance { - precondition( - start._typeID == other.1._typeID, - "distance: base index types differ.") - return start._box._distanceTo(other.1._box) -} - -public func ~> ( - start: AnyBidirectionalIndex, distance : (_Advance, AnyBidirectionalIndex.Distance) -) -> AnyBidirectionalIndex { - return AnyBidirectionalIndex(start._box._advancedBy(distance.1)) -} - -public func ~> ( - start: AnyBidirectionalIndex, - args: (_Advance, (AnyBidirectionalIndex.Distance, AnyBidirectionalIndex)) -) -> AnyBidirectionalIndex { - precondition( - start._typeID == args.1.1._typeID, "advance: base index types differ.") - return AnyBidirectionalIndex(start._box._advancedBy(args.1.0, args.1.1._box)) -} - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyBidirectionalIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyBidirectionalIndex, rhs: AnyBidirectionalIndex) -> Bool { - precondition(lhs._typeID == rhs._typeID, "base index types differ.") - return lhs._box.equals(rhs._box) -} - -/// A wrapper over an underlying `RandomAccessIndexType` that hides -/// the specific underlying type. -/// -/// See also: `AnyRandomAccessCollection` -public struct AnyRandomAccessIndex : RandomAccessIndexType { - public typealias Distance = IntMax - - /// Wrap and forward operations to `base`. - public init(_ base: BaseIndex) { - _box = _RandomAccessIndexBox(base) - } - - /// Return the next consecutive value in a discrete sequence of - /// `AnyRandomAccessIndex` values. - /// - /// Requires: `self` has a well-defined successor. - public func successor() -> AnyRandomAccessIndex { - return AnyRandomAccessIndex(_box.successor()) - } - - /// Return the previous consecutive value in a discrete sequence of - /// `AnyRandomAccessIndex` values. - /// - /// Requires: `self` has a well-defined predecessor. - public func predecessor() -> AnyRandomAccessIndex { - return AnyRandomAccessIndex(_box.predecessor()) - } - - /// Return the minimum number of applications of `successor` or - /// `predecessor` required to reach `other` from `self`. - /// - /// Requires: `self` and `other` wrap instances of the same type. - public func distanceTo(other: AnyRandomAccessIndex) -> Distance { - return _box._distanceTo(other._box) - } - - /// Return `self` offset by `n` steps. - /// - /// - Returns: If `n > 0`, the result of applying `successor` to - /// `self` `n` times. If `n < 0`, the result of applying - /// `predecessor` to `self` `n` times. Otherwise, `self`. - public func advancedBy(amount: Distance) -> AnyRandomAccessIndex { - return AnyRandomAccessIndex(_box._advancedBy(amount)) - } - - //===--- private --------------------------------------------------------===// - - internal var _typeID: ObjectIdentifier { - return _box.typeID - } - - internal init(_ box: _ForwardIndexBoxType) { - self._box = box as! _RandomAccessIndexBoxType - } - - internal let _box: _RandomAccessIndexBoxType -} - -public func ~> ( - start: AnyRandomAccessIndex, other : (_Distance, AnyRandomAccessIndex) -) -> AnyRandomAccessIndex.Distance { - precondition( - start._typeID == other.1._typeID, - "distance: base index types differ.") - return start._box._distanceTo(other.1._box) -} - -public func ~> ( - start: AnyRandomAccessIndex, distance : (_Advance, AnyRandomAccessIndex.Distance) -) -> AnyRandomAccessIndex { - return AnyRandomAccessIndex(start._box._advancedBy(distance.1)) -} - -public func ~> ( - start: AnyRandomAccessIndex, - args: (_Advance, (AnyRandomAccessIndex.Distance, AnyRandomAccessIndex)) -) -> AnyRandomAccessIndex { - precondition( - start._typeID == args.1.1._typeID, "advance: base index types differ.") - return AnyRandomAccessIndex(start._box._advancedBy(args.1.0, args.1.1._box)) -} - -/// Return true iff `lhs` and `rhs` wrap equal underlying -/// `AnyRandomAccessIndex`s. -/// -/// Requires: the types of indices wrapped by `lhs` and `rhs` are -/// identical. -public func == (lhs: AnyRandomAccessIndex, rhs: AnyRandomAccessIndex) -> Bool { - precondition(lhs._typeID == rhs._typeID, "base index types differ.") - return lhs._box.equals(rhs._box) -} - -//===--- Collections ------------------------------------------------------===// -//===----------------------------------------------------------------------===// - -internal class _AnyCollectionBox : _AnyCollectionBoxBase { - subscript(_ForwardIndexBoxType) -> Element {_abstract()} - func _count() -> IntMax {_abstract()} - - // FIXME: should be inherited, but a known bug prevents it since - // this class is generic. - override init( - startIndex: _ForwardIndexBoxType, - endIndex: _ForwardIndexBoxType - ) { - super.init(startIndex: startIndex, endIndex: endIndex) - } -} - -/// A protocol for `AnyForwardCollection`, -/// `AnyBidirectionalCollection`, and -/// `AnyRandomAccessCollection`. -/// -/// This protocol can be considered an implementation detail of the -/// `===` and `!==` implementations for these types. -public protocol AnyCollectionType : CollectionType { - /// Identifies the underlying collection stored by `self`. Instances - /// copied from one another have the same `underlyingCollectionID`. - var underlyingCollectionID: ObjectIdentifier {get} -} - -/// Return true iff `lhs` and `rhs` store the same underlying collection. -public func === < - L: AnyCollectionType, R: AnyCollectionType ->(lhs: L, rhs: R) -> Bool { - return lhs.underlyingCollectionID == rhs.underlyingCollectionID -} - -/// Return false iff `lhs` and `rhs` store the same underlying collection. -public func !== < - L: AnyCollectionType, R: AnyCollectionType ->(lhs: L, rhs: R) -> Bool { - return lhs.underlyingCollectionID != rhs.underlyingCollectionID -} - -/// A type-erased wrapper over any collection with at least -/// forward indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyBidirectionalType`, `AnyRandomAccessType` -public struct AnyForwardCollection : AnyCollectionType { - typealias Box = _AnyCollectionBox - - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: ForwardIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _ForwardIndexBox(base.startIndex), - endIndex: _ForwardIndexBox(base.endIndex)) - } - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyForwardCollection) { - self._box = other._box - } - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: BidirectionalIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _BidirectionalIndexBox(base.startIndex), - endIndex: _BidirectionalIndexBox(base.endIndex)) - } - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyBidirectionalCollection) { - self._box = other._box - } - /// Create an `AnyForwardCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _RandomAccessIndexBox(base.startIndex), - endIndex: _RandomAccessIndexBox(base.endIndex)) - } - - /// Create an `AnyForwardCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) { - self._box = other._box - } - - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator { - return unsafeDowncast(_box.generate()) - } - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyForwardIndex { - return AnyForwardIndex(_box.startIndex) - } - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyForwardIndex { - return AnyForwardIndex(_box.endIndex) - } - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyForwardIndex) -> Element { - return _box[position._box] - } - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier { - return ObjectIdentifier(_box) - } - - internal let _box: Box -} -/// A type-erased wrapper over any collection with at least -/// bidirectional indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyRandomAccessType`, `AnyForwardType` -public struct AnyBidirectionalCollection : AnyCollectionType { - typealias Box = _AnyCollectionBox - - /// Create an `AnyBidirectionalCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: BidirectionalIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _BidirectionalIndexBox(base.startIndex), - endIndex: _BidirectionalIndexBox(base.endIndex)) - } - - /// Create an `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyBidirectionalCollection) { - self._box = other._box - } - /// Create an `AnyBidirectionalCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _RandomAccessIndexBox(base.startIndex), - endIndex: _RandomAccessIndexBox(base.endIndex)) - } - - /// Create an `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) { - self._box = other._box - } - - /// If the indices of the underlying collection stored by `other` - /// satisfy `BidirectionalIndexType`, create an - /// `AnyBidirectionalCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyForwardCollection) { - if !(other._box.startIndex is _BidirectionalIndexBoxType) { - return nil - } - _sanityCheck(other._box.endIndex is _BidirectionalIndexBoxType) - self._box = other._box - } - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator { - return unsafeDowncast(_box.generate()) - } - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyBidirectionalIndex { - return AnyBidirectionalIndex(_box.startIndex) - } - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyBidirectionalIndex { - return AnyBidirectionalIndex(_box.endIndex) - } - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyBidirectionalIndex) -> Element { - return _box[position._box] - } - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier { - return ObjectIdentifier(_box) - } - - internal let _box: Box -} -/// A type-erased wrapper over any collection with at least -/// randomaccess indices. -/// -/// Forwards operations to an arbitrary underlying collection having the -/// same `Element` type, hiding the specifics of the underlying -/// `CollectionType`. -/// -/// See also: `AnyForwardType`, `AnyBidirectionalType` -public struct AnyRandomAccessCollection : AnyCollectionType { - typealias Box = _AnyCollectionBox - - /// Create an `AnyRandomAccessCollection` that stores `base` as its - /// underlying collection. - /// - /// Complexity: O(1) - public init< - C: CollectionType - where C.Index: RandomAccessIndexType, C.Generator.Element == Element - >(_ base: C) { - self._box = _CollectionBox( - base, - startIndex: _RandomAccessIndexBox(base.startIndex), - endIndex: _RandomAccessIndexBox(base.endIndex)) - } - - /// Create an `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. - /// - /// Postcondition: the result is `===` to `other`. - /// - /// Complexity: O(1) - public init(_ other: AnyRandomAccessCollection) { - self._box = other._box - } - - /// If the indices of the underlying collection stored by `other` - /// satisfy `RandomAccessIndexType`, create an - /// `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyForwardCollection) { - if !(other._box.startIndex is _RandomAccessIndexBoxType) { - return nil - } - _sanityCheck(other._box.endIndex is _RandomAccessIndexBoxType) - self._box = other._box - } - /// If the indices of the underlying collection stored by `other` - /// satisfy `RandomAccessIndexType`, create an - /// `AnyRandomAccessCollection` having the same underlying - /// collection as `other`. Otherwise, the result is `nil`. - /// - /// Complexity: O(1) - public init?(_ other: AnyBidirectionalCollection) { - if !(other._box.startIndex is _RandomAccessIndexBoxType) { - return nil - } - _sanityCheck(other._box.endIndex is _RandomAccessIndexBoxType) - self._box = other._box - } - - /// Return a *generator* over the elements of this *collection*. - /// - /// Complexity: O(1) - public func generate() -> AnyGenerator { - return unsafeDowncast(_box.generate()) - } - - /// The position of the first element in a non-empty collection. - /// - /// Identical to `endIndex` in an empty collection. - public var startIndex: AnyRandomAccessIndex { - return AnyRandomAccessIndex(_box.startIndex) - } - - /// The collection's "past the end" position. - /// - /// `endIndex` is not a valid argument to `subscript`, and is always - /// reachable from `startIndex` by zero or more applications of - /// `successor()`. - public var endIndex: AnyRandomAccessIndex { - return AnyRandomAccessIndex(_box.endIndex) - } - - /// Access the element indicated by `position`. - /// - /// Requires: `position` indicates a valid position in `self` and - /// `position != endIndex`. - public subscript(position: AnyRandomAccessIndex) -> Element { - return _box[position._box] - } - - /// Uniquely identifies the stored underlying collection. - public var underlyingCollectionID: ObjectIdentifier { - return ObjectIdentifier(_box) - } - - internal let _box: Box -} - diff --git a/test/IDE/dump_swift_lookup_tables.swift b/test/IDE/dump_swift_lookup_tables.swift index e3ae6150a8bd6..ee4403964fe2c 100644 --- a/test/IDE/dump_swift_lookup_tables.swift +++ b/test/IDE/dump_swift_lookup_tables.swift @@ -27,6 +27,8 @@ // CHECK-NEXT: TU: SNSomeStruct // CHECK-NEXT: __SNTransposeInPlace: // CHECK-NEXT: TU: SNTransposeInPlace +// CHECK-NEXT: __swift: +// CHECK-NEXT: TU: __swift // CHECK-NEXT: makeSomeStruct: // CHECK-NEXT: TU: SNMakeSomeStruct, SNMakeSomeStructForX // CHECK-NEXT: x: diff --git a/test/IDE/dump_swift_lookup_tables_objc.swift b/test/IDE/dump_swift_lookup_tables_objc.swift index eb8d8ad64eb8e..fd5faa4893915 100644 --- a/test/IDE/dump_swift_lookup_tables_objc.swift +++ b/test/IDE/dump_swift_lookup_tables_objc.swift @@ -6,6 +6,9 @@ // REQUIRES: objc_interop +// CHECK-LABEL: <> +// CHECK: Categories:{{.*}}NSValue(NSValueCreation){{.*}} + // CHECK-LABEL: <> // CHECK-NEXT: Base name -> entry mappings: // CHECK-NOT: lookup table @@ -44,6 +47,8 @@ // CHECK-NEXT: TU: UIActionSheet // CHECK-NEXT: __CCItem: // CHECK-NEXT: TU: __CCItem +// CHECK-NEXT: __swift: +// CHECK-NEXT: TU: __swift // CHECK-NEXT: accessibilityFloat: // CHECK-NEXT: NSAccessibility: -[NSAccessibility accessibilityFloat] // CHECK-NEXT: categoryMethodWithX: @@ -66,13 +71,24 @@ // CHECK-NEXT: NSErrorImports: -[NSErrorImports methodWithFloat:error:] // CHECK-NEXT: objectAtIndexedSubscript: // CHECK-NEXT: SNSomeClass: -[SNSomeClass objectAtIndexedSubscript:] +// CHECK-NEXT: optSetter: +// CHECK-NEXT: SNCollision: SNCollision.optSetter // CHECK-NEXT: protoInstanceMethodWithX: // CHECK-NEXT: SNSomeProtocol: -[SNSomeProtocol protoInstanceMethodWithX:y:] +// CHECK-NEXT: reqSetter: +// CHECK-NEXT: SNCollision: SNCollision.reqSetter // CHECK-NEXT: setAccessibilityFloat: // CHECK-NEXT: NSAccessibility: -[NSAccessibility setAccessibilityFloat:] // CHECK-NEXT: subscript: // CHECK-NEXT: SNSomeClass: -[SNSomeClass objectAtIndexedSubscript:] +// CHECK: Categories: SNSomeClass(), SNSomeClass(Category1) + +// CHECK-OMIT-NEEDLESS-WORDS: <> +// CHECK-OMIT-NEEDLESS-WORDS-NOT: lookup table +// CHECK-OMIT-NEEDLESS-WORDS: respondsTo: +// CHECK-OMIT-NEEDLESS-WORDS-NEXT: -[NSObject respondsToSelector:] + // CHECK-OMIT-NEEDLESS-WORDS: Base name -> entry mappings: // CHECK-OMIT-NEEDLESS-WORDS: methodWith: // CHECK-OMIT-NEEDLESS-WORDS: NSErrorImports: -[NSErrorImports methodWithFloat:error:] diff --git a/test/IDE/print_ast_tc_decls.swift b/test/IDE/print_ast_tc_decls.swift index 674a9d1a838b4..f0ca3c88c136f 100644 --- a/test/IDE/print_ast_tc_decls.swift +++ b/test/IDE/print_ast_tc_decls.swift @@ -91,7 +91,7 @@ protocol FooProtocol {} protocol BarProtocol {} protocol BazProtocol { func baz() } protocol QuxProtocol { - typealias Qux + associatedtype Qux } protocol SubFooProtocol : FooProtocol { } @@ -177,30 +177,6 @@ struct d0100_FooStruct { } // PASS_COMMON-NEXT: {{^}} subscript (i: Int, j: Int) -> Double { get }{{$}} - func curriedVoidFunc1()() {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedVoidFunc1()(){{$}} - - func curriedVoidFunc2()(a: Int) {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedVoidFunc2()(a: Int){{$}} - - func curriedVoidFunc3(a: Int)() {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedVoidFunc3(a: Int)(){{$}} - - func curriedVoidFunc4(a: Int)(b: Int) {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedVoidFunc4(a: Int)(b: Int){{$}} - - func curriedStringFunc1()() -> String { return "" } // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedStringFunc1()() -> String{{$}} - - func curriedStringFunc2()(a: Int) -> String { return "" } // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedStringFunc2()(a: Int) -> String{{$}} - - func curriedStringFunc3(a: Int)() -> String { return "" } // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedStringFunc3(a: Int)() -> String{{$}} - - func curriedStringFunc4(a: Int)(b: Int) -> String { return "" } // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} -// PASS_COMMON-NEXT: {{^}} func curriedStringFunc4(a: Int)(b: Int) -> String{{$}} - func bodyNameVoidFunc1(a: Int, b x: Float) {} // PASS_COMMON-NEXT: {{^}} func bodyNameVoidFunc1(a: Int, b x: Float){{$}} @@ -228,7 +204,7 @@ struct d0100_FooStruct { // PASS_COMMON-NEXT: {{^}} enum NestedEnum {{{$}} // PASS_COMMON-NEXT: {{^}} }{{$}} - // Can not declare a nested protocol. + // Cannot declare a nested protocol. // protocol NestedProtocol {} typealias NestedTypealias = Int @@ -470,8 +446,8 @@ class d0121_TestClassDerived : d0120_TestClassBase { protocol d0130_TestProtocol { // PASS_COMMON-LABEL: {{^}}protocol d0130_TestProtocol {{{$}} - typealias NestedTypealias -// PASS_COMMON-NEXT: {{^}} typealias NestedTypealias{{$}} + associatedtype NestedTypealias +// PASS_COMMON-NEXT: {{^}} associatedtype NestedTypealias{{$}} var property1: Int { get } // PASS_COMMON-NEXT: {{^}} var property1: Int { get }{{$}} @@ -629,8 +605,8 @@ struct d0200_EscapedIdentifiers { // PASS_COMMON-NEXT: {{^}} }{{$}} func `func`<`let`: `protocol`, `where` where `where` : `protocol`>( - `class`: Int, `struct`: `protocol`, `foo`: `let`, `bar`: `where`) {} -// PASS_COMMON-NEXT: {{^}} func `func`<`let` : `protocol`, `where` where `where` : `protocol`>(`class`: Int, `struct`: `protocol`, foo: `let`, bar: `where`){{$}} + class: Int, struct: `protocol`, foo: `let`, bar: `where`) {} +// PASS_COMMON-NEXT: {{^}} func `func`<`let` : `protocol`, `where` where `where` : `protocol`>(class: Int, struct: `protocol`, foo: `let`, bar: `where`){{$}} var `var`: `struct` = `struct`() // PASS_COMMON-NEXT: {{^}} var `var`: {{(d0200_EscapedIdentifiers.)?}}`struct`{{$}} @@ -644,8 +620,8 @@ struct d0200_EscapedIdentifiers { } // PASS_COMMON-NEXT: {{^}} var accessors1: Int{{( { get set })?}}{{$}} - static func `static`(`protocol`: Int) {} -// PASS_COMMON-NEXT: {{^}} static func `static`(`protocol`: Int){{$}} + static func `static`(protocol: Int) {} +// PASS_COMMON-NEXT: {{^}} static func `static`(protocol: Int){{$}} // PASS_COMMON-NEXT: {{^}} init(`var`: {{(d0200_EscapedIdentifiers.)?}}`struct`, tupleType: (`var`: Int, `let`: {{(d0200_EscapedIdentifiers.)?}}`struct`)){{$}} // PASS_COMMON-NEXT: {{^}}}{{$}} @@ -879,14 +855,14 @@ typealias SimpleTypealias1 = FooProtocol // Associated types. protocol AssociatedType1 { - typealias AssociatedTypeDecl1 = Int -// PASS_ONE_LINE-DAG: {{^}} typealias AssociatedTypeDecl1 = Int{{$}} + associatedtype AssociatedTypeDecl1 = Int +// PASS_ONE_LINE-DAG: {{^}} associatedtype AssociatedTypeDecl1 = Int{{$}} - typealias AssociatedTypeDecl2 : FooProtocol -// PASS_ONE_LINE-DAG: {{^}} typealias AssociatedTypeDecl2 : FooProtocol{{$}} + associatedtype AssociatedTypeDecl2 : FooProtocol +// PASS_ONE_LINE-DAG: {{^}} associatedtype AssociatedTypeDecl2 : FooProtocol{{$}} - typealias AssociatedTypeDecl3 : FooProtocol, BarProtocol -// PASS_ONE_LINE_TYPEREPR-DAG: {{^}} typealias AssociatedTypeDecl3 : FooProtocol, BarProtocol{{$}} + associatedtype AssociatedTypeDecl3 : FooProtocol, BarProtocol +// PASS_ONE_LINE_TYPEREPR-DAG: {{^}} associatedtype AssociatedTypeDecl3 : FooProtocol, BarProtocol{{$}} } //===--- @@ -1157,12 +1133,12 @@ infix operator %%<> { //===--- protocol d2700_ProtocolWithAssociatedType1 { - typealias TA1 + associatedtype TA1 func returnsTA1() -> TA1 } // PASS_COMMON: {{^}}protocol d2700_ProtocolWithAssociatedType1 {{{$}} -// PASS_COMMON-NEXT: {{^}} typealias TA1{{$}} +// PASS_COMMON-NEXT: {{^}} associatedtype TA1{{$}} // PASS_COMMON-NEXT: {{^}} func returnsTA1() -> Self.TA1{{$}} // PASS_COMMON-NEXT: {{^}}}{{$}} @@ -1336,7 +1312,7 @@ public func ParamAttrs3(@noescape a : () -> ()) { // Protocol extensions protocol ProtocolToExtend { - typealias Assoc + associatedtype Assoc } extension ProtocolToExtend where Self.Assoc == Int {} diff --git a/test/IDE/print_ast_tc_decls_errors.swift b/test/IDE/print_ast_tc_decls_errors.swift index 5abbc2acdfdbb..2fa711ad649fc 100644 --- a/test/IDE/print_ast_tc_decls_errors.swift +++ b/test/IDE/print_ast_tc_decls_errors.swift @@ -21,7 +21,7 @@ protocol FooProtocol {} protocol BarProtocol {} protocol BazProtocol { func baz() } protocol QuxProtocol { - typealias Qux + associatedtype Qux } class FooProtocolImpl : FooProtocol {} @@ -168,27 +168,30 @@ typealias Typealias1 = FooNonExistentProtocol // expected-error {{use of undecla // NO-TYREPR: {{^}}typealias Typealias1 = <>{{$}} // TYREPR: {{^}}typealias Typealias1 = FooNonExistentProtocol{{$}} +// sr-197 +func foo(bar: Typealias1) {} // Should not generate error "cannot specialize non-generic type '<>'" + // Associated types. protocol AssociatedType1 { // CHECK-LABEL: AssociatedType1 { - typealias AssociatedTypeDecl1 : FooProtocol = FooClass -// CHECK: {{^}} typealias AssociatedTypeDecl1 : FooProtocol = FooClass{{$}} + associatedtype AssociatedTypeDecl1 : FooProtocol = FooClass +// CHECK: {{^}} associatedtype AssociatedTypeDecl1 : FooProtocol = FooClass{{$}} - typealias AssociatedTypeDecl2 : BazProtocol = FooClass -// CHECK: {{^}} typealias AssociatedTypeDecl2 : BazProtocol = FooClass{{$}} + associatedtype AssociatedTypeDecl2 : BazProtocol = FooClass +// CHECK: {{^}} associatedtype AssociatedTypeDecl2 : BazProtocol = FooClass{{$}} - typealias AssociatedTypeDecl3 : FooNonExistentProtocol // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} -// NO-TYREPR: {{^}} typealias AssociatedTypeDecl3 : <>{{$}} -// TYREPR: {{^}} typealias AssociatedTypeDecl3 : FooNonExistentProtocol{{$}} + associatedtype AssociatedTypeDecl3 : FooNonExistentProtocol // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} +// NO-TYREPR: {{^}} associatedtype AssociatedTypeDecl3 : <>{{$}} +// TYREPR: {{^}} associatedtype AssociatedTypeDecl3 : FooNonExistentProtocol{{$}} - typealias AssociatedTypeDecl4 : FooNonExistentProtocol, BarNonExistentProtocol // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} expected-error {{use of undeclared type 'BarNonExistentProtocol'}} -// NO-TYREPR: {{^}} typealias AssociatedTypeDecl4 : <>, <>{{$}} -// TYREPR: {{^}} typealias AssociatedTypeDecl4 : FooNonExistentProtocol, BarNonExistentProtocol{{$}} + associatedtype AssociatedTypeDecl4 : FooNonExistentProtocol, BarNonExistentProtocol // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} expected-error {{use of undeclared type 'BarNonExistentProtocol'}} +// NO-TYREPR: {{^}} associatedtype AssociatedTypeDecl4 : <>, <>{{$}} +// TYREPR: {{^}} associatedtype AssociatedTypeDecl4 : FooNonExistentProtocol, BarNonExistentProtocol{{$}} - typealias AssociatedTypeDecl5 : FooClass -// CHECK: {{^}} typealias AssociatedTypeDecl5 : FooClass{{$}} + associatedtype AssociatedTypeDecl5 : FooClass +// CHECK: {{^}} associatedtype AssociatedTypeDecl5 : FooClass{{$}} } //===--- @@ -201,7 +204,7 @@ var topLevelVar1 = 42 // CHECK: class C1 class C1 { - // CHECK: init(data: ) + // CHECK: init(data: <>) init(data:) // expected-error {{expected parameter type following ':'}} } diff --git a/test/IDE/print_clang_framework.swift b/test/IDE/print_clang_framework.swift index f7d5be5c292ea..bf741f2bc21ce 100644 --- a/test/IDE/print_clang_framework.swift +++ b/test/IDE/print_clang_framework.swift @@ -37,11 +37,11 @@ // // REQUIRES: OS=macosx -// FOUNDATION-LABEL: {{^}}/// Aaa. NSAvailableOnOSX10_10AndIOS8_0. Bbb. -// FOUNDATION-NEXT: {{^}}@available(OSX 10.10, *){{$}} +// FOUNDATION-LABEL: {{^}}/// Aaa. NSAvailableOnOSX10_51AndIOS8_0. Bbb. +// FOUNDATION-NEXT: {{^}}@available(OSX 10.51, *){{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. NSPotentiallyUnavailableOptions. Bbb. -// FOUNDATION-NEXT: {{^}}@available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}}@available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}}struct NSPotentiallyUnavailableOptions : OptionSetType {{{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. NSOptionsWithUnavailableElement. Bbb. @@ -50,11 +50,11 @@ // FOUNDATION-NEXT: {{^}} let rawValue: UInt{{$}} // FOUNDATION-NEXT: {{^}} static var First: NSOptionsWithUnavailableElement { get }{{$}} // FOUNDATION-NEXT: {{^}} static var Second: NSOptionsWithUnavailableElement { get }{{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} static var Third: NSOptionsWithUnavailableElement { get }{{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. NSUnavailableEnum. Bbb. -// FOUNDATION-NEXT: {{^}}@available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}}@available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}}enum NSUnavailableEnum : UInt {{{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. NSEnumWithUnavailableElement. Bbb. @@ -63,25 +63,25 @@ // FOUNDATION-NEXT: {{^}} var rawValue: UInt { get }{{$}} // FOUNDATION-NEXT: {{^}} case First{{$}} // FOUNDATION-NEXT: {{^}} case Second{{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} case Third{{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. UnannotatedFrameworkProtocol. Bbb. // FOUNDATION-NEXT: {{^}}protocol UnannotatedFrameworkProtocol {{{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass?){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithNonNullableClass(k: AnnotatedFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithIUOClass(k: AnnotatedFrameworkClass!){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func returnSomething() -> AnnotatedFrameworkClass?{{$}} // FOUNDATION-NEXT: {{^}} func noUnavailableTypesInSignature(){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass, andLaterClass lk: AnnotatedLaterFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.12, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.53, *) // FOUNDATION-NEXT: {{^}} func someMethodWithAvailability() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} var someProperty: AnnotatedFrameworkClass { get set }{{$}} // FOUNDATION-LABEL: {{^}}/// Aaa. AnnotatedFrameworkProtocol. Bbb. @@ -92,56 +92,56 @@ // FOUNDATION-LABEL: /// Aaa. FrameworkClassConformingToUnannotatedFrameworkProtocol. Bbb. // FOUNDATION-NEXT: {{^}}class FrameworkClassConformingToUnannotatedFrameworkProtocol : NSObject, UnannotatedFrameworkProtocol {{{$}} // FOUNDATION-NEXT: {{^}} init(){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass?){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithNonNullableClass(k: AnnotatedFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithIUOClass(k: AnnotatedFrameworkClass!){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} func returnSomething() -> AnnotatedFrameworkClass?{{$}} // FOUNDATION-NEXT: {{^}} func noUnavailableTypesInSignature(){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass, andLaterClass lk: AnnotatedLaterFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.12, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.53, *) // FOUNDATION-NEXT: {{^}} func someMethodWithAvailability() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.10, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.51, *){{$}} // FOUNDATION-NEXT: {{^}} var someProperty: AnnotatedFrameworkClass{{$}} // FOUNDATION-LABEL: /// Aaa. LaterFrameworkClassConformingToUnannotatedFrameworkProtocol. Bbb. -// FOUNDATION-NEXT: {{^}}@available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}}@available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}}class LaterFrameworkClassConformingToUnannotatedFrameworkProtocol : NSObject, UnannotatedFrameworkProtocol {{{$}} // FOUNDATION-NEXT: {{^}} init(){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass?){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithNonNullableClass(k: AnnotatedFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithIUOClass(k: AnnotatedFrameworkClass!){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func returnSomething() -> AnnotatedFrameworkClass?{{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func noUnavailableTypesInSignature(){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass, andLaterClass lk: AnnotatedLaterFrameworkClass){{$}} -// FOUNDATION-NEXT: {{^}} @available(OSX 10.12, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.53, *) // FOUNDATION-NEXT: {{^}} func someMethodWithAvailability() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *){{$}} +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *){{$}} // FOUNDATION-NEXT: {{^}} var someProperty: AnnotatedFrameworkClass{{$}} } // FOUNDATION-LABEL: /// Aaa. FrameworkClassConformingToLaterAnnotatedFrameworkProtocol. Bbb. // FOUNDATION-NEXT: {{^}}class FrameworkClassConformingToLaterAnnotatedFrameworkProtocol : NSObject, LaterAnnotatedFrameworkProtocol { // FOUNDATION-NEXT: {{^}} init() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *) // FOUNDATION-NEXT: {{^}} func returnSomething() -> AnnotatedFrameworkClass? -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *) // FOUNDATION-NEXT: {{^}} func doSomethingWithClass(k: AnnotatedFrameworkClass, andLaterClass lk: AnnotatedLaterFrameworkClass) -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *) // FOUNDATION-NEXT: {{^}} func noUnavailableTypesInSignature() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.12, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.53, *) // FOUNDATION-NEXT: {{^}} func someMethodWithAvailability() -// FOUNDATION-NEXT: {{^}} @available(OSX 10.11, *) +// FOUNDATION-NEXT: {{^}} @available(OSX 10.52, *) // FOUNDATION-NEXT: {{^}} var someProperty: AnnotatedFrameworkClass } diff --git a/test/IDE/print_clang_header.swift b/test/IDE/print_clang_header.swift index dd3df16341615..ae6634906a358 100644 --- a/test/IDE/print_clang_header.swift +++ b/test/IDE/print_clang_header.swift @@ -23,7 +23,3 @@ // Test header interface printing from a clang module, with the preprocessing record enabled by the CC args. // RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments --cc-args %target-cc-options -isysroot %clang-importer-sdk-path -fsyntax-only %t.framework.m -F %t -ivfsoverlay %t.yaml -Xclang -detailed-preprocessing-record > %t.module2.txt // RUN: diff -u %S/Inputs/print_clang_header/header-to-print.h.module.printed.txt %t.module2.txt - -// RUN: echo '#include "header-to-print.h"' > %t.i386.m -// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt -// RUN: diff -u %S/Inputs/print_clang_header/header-to-print.h.printed.txt %t.i386.txt diff --git a/test/IDE/print_clang_header_i386.swift b/test/IDE/print_clang_header_i386.swift new file mode 100644 index 0000000000000..c147acc994612 --- /dev/null +++ b/test/IDE/print_clang_header_i386.swift @@ -0,0 +1,7 @@ +// REQUIRES: OS=macosx +// FIXME: rdar://problem/19648117 Needs splitting objc parts out +// XFAIL: linux + +// RUN: echo '#include "header-to-print.h"' > %t.i386.m +// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt +// RUN: diff -u %S/Inputs/print_clang_header/header-to-print.h.printed.txt %t.i386.txt diff --git a/test/IDE/print_clang_header_swift_name.swift b/test/IDE/print_clang_header_swift_name.swift new file mode 100644 index 0000000000000..9afc97c9e5750 --- /dev/null +++ b/test/IDE/print_clang_header_swift_name.swift @@ -0,0 +1,27 @@ +// RUN: echo '#include "print_clang_header_swift_name.h"' > %t.m +// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print \ +// RUN: %S/Inputs/print_clang_header_swift_name.h --cc-args %target-cc-options \ +// RUN: -isysroot %clang-importer-sdk-path -fsyntax-only %t.m -I %S/Inputs | FileCheck %s + +// REQUIRES: objc_interop + +// CHECK: enum Normal : Int { +// CHECK-NOT: {{^}}} +// CHECK: case One +// CHECK-NEXT: case Two +// CHECK-NEXT: case Three +// CHECK-NEXT: } + +// CHECK: enum SwiftEnum : Int { +// CHECK-NOT: {{^}}} +// CHECK: case One +// CHECK-NEXT: case Two +// CHECK-NEXT: case Three +// CHECK-NEXT: } + +// CHECK: enum SwiftEnumTwo : Int { +// CHECK-NOT: {{^}}} +// CHECK: case SwiftEnumTwoA +// CHECK-NEXT: case SwiftEnumTwoB +// CHECK-NEXT: case SwiftEnumTwoC +// CHECK-NEXT: } diff --git a/test/IDE/print_module_without_deinit.swift b/test/IDE/print_module_without_deinit.swift index db09119283ce8..1b6bde828dcf6 100644 --- a/test/IDE/print_module_without_deinit.swift +++ b/test/IDE/print_module_without_deinit.swift @@ -39,7 +39,7 @@ public class ImplicitOptionalInitContainer { // ATTR1: class AttributeContainer1 { public class AttributeContainer1 { // ATTR1: func m1(@autoclosure a: () -> Int) - public func m1(@autoclosure a : ()->Int) {} + public func m1(@autoclosure a : () -> Int) {} // ATTR1: func m2(@noescape a: () -> Int) - public func m2(@noescape a : ()->Int) {} + public func m2(@noescape a : () -> Int) {} } diff --git a/test/IDE/print_omit_needless_words.swift b/test/IDE/print_omit_needless_words.swift index ddf0a5625194e..1a327d306930e 100644 --- a/test/IDE/print_omit_needless_words.swift +++ b/test/IDE/print_omit_needless_words.swift @@ -3,11 +3,11 @@ // REQUIRES: objc_interop -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules-without-ns/ObjectiveC.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules-without-ns/CoreGraphics.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules-without-ns/Foundation.swift -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules/AppKit.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -enable-omit-needless-words %S/../Inputs/clang-importer-sdk/swift-modules-without-ns/AppKit.swift // RUN: %target-swift-ide-test(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -print-module -source-filename %s -module-to-print=ObjectiveC -function-definitions=false -prefer-type-repr=true -enable-omit-needless-words -enable-infer-default-arguments > %t.ObjectiveC.txt // RUN: FileCheck %s -check-prefix=CHECK-OBJECTIVEC -strict-whitespace < %t.ObjectiveC.txt @@ -21,6 +21,9 @@ // RUN: %target-swift-ide-test(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t -I %S/../ClangModules/Inputs/custom-modules) -print-module -source-filename %s -module-to-print=CoreCooling -function-definitions=false -prefer-type-repr=true -enable-omit-needless-words -skip-parameter-names -enable-infer-default-arguments > %t.CoreCooling.txt // RUN: FileCheck %s -check-prefix=CHECK-CORECOOLING -strict-whitespace < %t.CoreCooling.txt +// RUN: %target-swift-ide-test(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -print-module -source-filename %s -module-to-print=errors -function-definitions=false -prefer-type-repr=true -enable-omit-needless-words -skip-parameter-names -enable-infer-default-arguments > %t.errors.txt +// RUN: FileCheck %s -check-prefix=CHECK-ERRORS -strict-whitespace < %t.errors.txt + // Note: SEL -> "Selector" // CHECK-FOUNDATION: func makeObjectsPerform(_: Selector) @@ -37,41 +40,44 @@ // Note: Pointer-to-struct name matching; "with" splits the first // piece, then the "with" is dropped. // -// CHECK-FOUNDATION: func copy(zone _: NSZone = nil) -> AnyObject! +// CHECK-FOUNDATION: func copy(zone _: Zone = nil) -> AnyObject! // Note: Objective-C type parameter names. -// CHECK-FOUNDATION: func objectFor(_: NSCopying) -> AnyObject? -// CHECK-FOUNDATION: func removeObjectFor(_: NSCopying) +// CHECK-FOUNDATION: func objectFor(_: Copying) -> AnyObject? +// CHECK-FOUNDATION: func removeObjectFor(_: Copying) // Note: Don't drop the name of the first parameter in an initializer entirely. // CHECK-FOUNDATION: init(array: [AnyObject]) // Note: struct name matching; don't drop "With". -// CHECK-FOUNDATION: class func withRange(_: NSRange) -> NSValue +// CHECK-FOUNDATION: class func withRange(_: NSRange) -> Value // Note: built-in types. -// CHECK-FOUNDATION: func add(_: Double) -> NSNumber +// CHECK-FOUNDATION: func add(_: Double) -> Number // Note: built-in types. -// CHECK-FOUNDATION: func add(_: Bool) -> NSNumber +// CHECK-FOUNDATION: func add(_: Bool) -> Number // Note: builtin-types. -// CHECK-FOUNDATION: func add(_: UInt16) -> NSNumber +// CHECK-FOUNDATION: func add(_: UInt16) -> Number // Note: builtin-types. -// CHECK-FOUNDATION: func add(_: Int32) -> NSNumber +// CHECK-FOUNDATION: func add(_: Int32) -> Number // Note: Typedefs with a "_t" suffix". -// CHECK-FOUNDATION: func subtract(_: Int32) -> NSNumber +// CHECK-FOUNDATION: func subtract(_: Int32) -> Number + +// Note: Respect the getter name for BOOL properties. +// CHECK-FOUNDATION: var isMakingHoney: Bool // Note: multi-word enum name matching; "with" splits the first piece. -// CHECK-FOUNDATION: func someMethod(deprecatedOptions _: NSDeprecatedOptions = []) +// CHECK-FOUNDATION: func someMethod(deprecatedOptions _: DeprecatedOptions = []) // Note: class name matching; don't drop "With". // CHECK-FOUNDATION: class func withString(_: String!) -> Self! // Note: Make sure NSURL works in various places -// CHECK-FOUNDATION: open(_: NSURL!, completionHandler: ((Bool) -> Void)!) +// CHECK-FOUNDATION: open(_: URL!, completionHandler: ((Bool) -> Void)!) // Note: property name stripping property type. // CHECK-FOUNDATION: var uppercase: String @@ -97,29 +103,29 @@ // CHECK-FOUNDATION: func withString(_: String) -> String // Note: Not splitting on "With". -// CHECK-FOUNDATION: func urlWithAddedString(_: String) -> NSURL? +// CHECK-FOUNDATION: func urlWithAddedString(_: String) -> URL? // Note: CalendarUnits is not a set of "Options". -// CHECK-FOUNDATION: class func forCalendarUnits(_: NSCalendarUnit) -> String! +// CHECK-FOUNDATION: class func forCalendarUnits(_: CalendarUnit) -> String! // Note: By --> . -// CHECK-FOUNDATION: var deletingLastPathComponent: NSURL? { get } +// CHECK-FOUNDATION: var deletingLastPathComponent: URL? { get } // Note: --> . -// CHECK-FOUNDATION: var withHTTPS: NSURL { get } +// CHECK-FOUNDATION: var withHTTPS: URL { get } // Note: usingBlock -> body // CHECK-FOUNDATION: func enumerateObjectsUsing(_: ((AnyObject!, Int, UnsafeMutablePointer) -> Void)!) -// CHECK-FOUNDATION: func enumerateObjects(options _: NSEnumerationOptions = [], usingBlock: ((AnyObject!, Int, UnsafeMutablePointer) -> Void)!) +// CHECK-FOUNDATION: func enumerateObjects(options _: EnumerationOptions = [], usingBlock: ((AnyObject!, Int, UnsafeMutablePointer) -> Void)!) // Note: WithBlock -> body, nullable closures default to nil. // CHECK-FOUNDATION: func enumerateObjectsRandomly(block _: ((AnyObject!, Int, UnsafeMutablePointer) -> Void)? = nil) // Note: id treated as "Proto". -// CHECK-FOUNDATION: func doSomethingWith(_: NSCopying) +// CHECK-FOUNDATION: func doSomethingWith(_: Copying) // Note: NSObject treated as "Proto". -// CHECK-FOUNDATION: func doSomethingElseWith(_: protocol) +// CHECK-FOUNDATION: func doSomethingElseWith(_: protocol) // Note: Function type -> "Function". // CHECK-FOUNDATION: func sortUsing(_: @convention(c) (AnyObject, AnyObject) -> Int) @@ -128,18 +134,18 @@ // CHECK-FOUNDATION: func remove(_: [AnyObject]) // Note: Skipping "Type" suffix. -// CHECK-FOUNDATION: func doSomethingWith(_: NSUnderlyingType) +// CHECK-FOUNDATION: func doSomethingWith(_: UnderlyingType) // Don't introduce default arguments for lone parameters to setters. -// CHECK-FOUNDATION: func setDefaultEnumerationOptions(_: NSEnumerationOptions) +// CHECK-FOUNDATION: func setDefaultEnumerationOptions(_: EnumerationOptions) // CHECK-FOUNDATION: func normalizingXMLPreservingComments(_: Bool) // Collection element types. -// CHECK-FOUNDATION: func adding(_: AnyObject) -> Set +// CHECK-FOUNDATION: func adding(_: AnyObject) -> Set -// Boolean properties get an "is" prefix. -// CHECK-FOUNDATION: var isEmpty: Bool { get } +// Boolean properties follow the getter. +// CHECK-FOUNDATION: var empty: Bool { get } // CHECK-FOUNDATION: func nonEmpty() -> Bool // CHECK-FOUNDATION: var isStringSet: Bool { get } // CHECK-FOUNDATION: var wantsAUnion: Bool { get } @@ -147,6 +153,16 @@ // CHECK-FOUNDATION: var appliesForAJob: Bool { get } // CHECK-FOUNDATION: var setShouldBeInfinite: Bool { get } +// "UTF8" initialisms. +// CHECK-FOUNDATION: init?(utf8String: UnsafePointer) + +// Lowercasing after prefix stripping. +// CHECK-FOUNDATION: let globalConstant: String +// CHECK-FOUNDATION: func globalFunction() + +// Lowercasing initialisms with plurals. +// CHECK-FOUNDATION: var urlsInText: [URL] { get } + // Note: class method name stripping context type. // CHECK-APPKIT: class func red() -> NSColor @@ -160,7 +176,7 @@ // CHECK-APPKIT: func drawInAirAt(_: Point3D) // Note: with -> -// CHECK-APPKIT: func drawAt(_: Point3D, withAttributes: [String : AnyObject]?) +// CHECK-APPKIT: func drawAt(_: Point3D, withAttributes: [String : AnyObject]? = [:]) // Note: Don't strip names that aren't preceded by a verb or preposition. // CHECK-APPKIT: func setTextColor(_: NSColor?) @@ -168,6 +184,10 @@ // Note: Splitting with default arguments. // CHECK-APPKIT: func drawIn(_: NSView?) +// Note: NSDictionary default arguments for "options" +// CHECK-APPKIT: func drawAnywhereIn(_: NSView?, options: [Object : AnyObject] = [:]) +// CHECK-APPKIT: func drawAnywhere(options _: [Object : AnyObject] = [:]) + // Note: Skipping over "Ref" // CHECK-CORECOOLING: func replace(_: CCPowerSupply!) @@ -203,5 +223,8 @@ // CHECK-APPKIT: func removeGestureRecognizer(_: NSGestureRecognizer) // CHECK-APPKIT: func favoriteViewFor(_: NSGestureRecognizer) -> NSView? // CHECK-APPKIT: func addLayoutConstraints(_: Set) -// CHECK-APPKIT: func add(_: NSRect) -// CHECK-APPKIT: class func conjureRect(_: NSRect) +// CHECK-APPKIT: func add(_: Rect) +// CHECK-APPKIT: class func conjureRect(_: Rect) + +// Don't drop the 'error'. +// CHECK-ERRORS: func tryAndReturnError(_: ()) throws diff --git a/test/IDE/print_types.swift b/test/IDE/print_types.swift index e2b806278dcfb..7bd70b81e464b 100644 --- a/test/IDE/print_types.swift +++ b/test/IDE/print_types.swift @@ -99,13 +99,13 @@ func testVariadicFuncType(a: Int, b: Float...) {} // CHECK: FuncDecl '''testVariadicFuncType''' (Int, b: Float...) -> (){{$}} // FULL: FuncDecl '''testVariadicFuncType''' (Swift.Int, b: Swift.Float...) -> (){{$}} -func testCurriedFuncType1(a: Int)(b: Float) {} // expected-warning{{curried function declaration syntax will be removed in a future version of Swift}} +func testCurriedFuncType1(a: Int) -> (b: Float) -> () {} // CHECK: FuncDecl '''testCurriedFuncType1''' (Int) -> (b: Float) -> (){{$}} // FULL: FuncDecl '''testCurriedFuncType1''' (Swift.Int) -> (b: Swift.Float) -> (){{$}} protocol FooProtocol {} protocol BarProtocol {} -protocol QuxProtocol { typealias Qux } +protocol QuxProtocol { associatedtype Qux } struct GenericStruct {} diff --git a/test/IDE/print_usrs.swift b/test/IDE/print_usrs.swift index b963a4d58ba84..9fbb6d132fbec 100644 --- a/test/IDE/print_usrs.swift +++ b/test/IDE/print_usrs.swift @@ -46,7 +46,7 @@ class GenericClass { } // CHECK: [[@LINE+2]]:3 s:iC14swift_ide_test12GenericClass9subscriptFSiSf{{$}} - // CHECK: [[@LINE+1]]:13 s:vC14swift_ide_test12GenericClass1iSi{{$}} + // CHECK: [[@LINE+1]]:13 s:vC14swift_ide_test12GenericClassL_1iSi{{$}} subscript(i: Int) -> Float { // CHECK: [[@LINE+1]]:5 s:FC14swift_ide_test12GenericClassg9subscriptFSiSf{{$}} get { return 0.0 } @@ -68,8 +68,8 @@ class GenericClass { // CHECK: [[@LINE+1]]:10 s:P14swift_ide_test4Prot{{$}} protocol Prot { - // CHECK: [[@LINE+1]]:13 s:P14swift_ide_test4Prot5Blarg{{$}} - typealias Blarg + // CHECK: [[@LINE+1]]:18 s:P14swift_ide_test4Prot5Blarg{{$}} + associatedtype Blarg // CHECK: [[@LINE+1]]:8 s:FP14swift_ide_test4Prot8protMethFwx5BlargwxS1_{{$}} func protMeth(x: Blarg) -> Blarg // CHECK: [[@LINE+2]]:7 s:vP14swift_ide_test4Prot17protocolProperty1Si{{$}} diff --git a/test/IDE/reconstruct_type_from_mangled_name.swift b/test/IDE/reconstruct_type_from_mangled_name.swift new file mode 100644 index 0000000000000..c7b5d556ab6d6 --- /dev/null +++ b/test/IDE/reconstruct_type_from_mangled_name.swift @@ -0,0 +1,47 @@ +// RUN: %target-swift-ide-test -reconstruct-type -source-filename %s | FileCheck %s + +class Mystruct1 { + func s1f1() -> Int { return 0 } + var intField = 3 +} + +class Myclass1 { + var intField = 4 +} + +func f1() { + var s1ins = Mystruct1() + s1ins.intField = 34 + +// CHECK: reconstructed type from usr for 's1ins' is 'Mystruct1' +// CHECK: reconstructed type from usr for 'intField' is 'Int' + var c1ins = Myclass1() + c1ins.intField = 3 + +// CHECK: reconstructed type from usr for 'c1ins' is 'Myclass1' +// CHECK: reconstructed type from usr for 'intField' is 'Int' + + s1ins.s1f1() +// CHECK: reconstructed type from usr for 's1ins' is 'Mystruct1' +// CHECK: reconstructed type from usr for 's1f1' is 'Mystruct1 -> () -> Int' +} + +class Myclass2 { + func f1() { + var arr1 = [1, 2] + arr1.append(1) + +// CHECK: reconstructed type from usr for 'arr1' is 'Array' +// CHECK: reconstructed type from usr for 'append' is '@lvalue Array -> Int -> ()' + + var arr2 : [Mystruct1] + arr2.append(Mystruct1()) +// CHECK: reconstructed type from usr for 'arr2' is 'Array' +// CHECK: reconstructed type from usr for 'append' is '@lvalue Array -> Mystruct1 -> ()' + + var arr3 : [Myclass1] + arr3.append(Myclass1()) +// CHECK: reconstructed type from usr for 'arr3' is 'Array' +// CHECK: reconstructed type from usr for 'append' is '@lvalue Array -> Myclass1 -> ()' + } +} diff --git a/test/IDE/structure.swift b/test/IDE/structure.swift index 666f683a7d16e..c038f26c1021e 100644 --- a/test/IDE/structure.swift +++ b/test/IDE/structure.swift @@ -9,7 +9,7 @@ class MyCls : OtherClass { var anotherBar : Int = 42 class var cbar : Int = 0 - // CHECK: func foo(arg1: Int, name: String, param par: String) { + // CHECK: func foo(arg1: Int, name: String, param par: String) { // CHECK: var abc // CHECK: if 1 { // CHECK: foo(1, name:"test", param:"test2") @@ -22,7 +22,7 @@ class MyCls : OtherClass { } } - // CHECK: init (x: Int) + // CHECK: init (x: Int) init (x: Int) // CHECK: class func cfoo() @@ -152,7 +152,7 @@ enum Rawness : Int { case Two = 2, Three = 3 } -// CHECK: func rethrowFunc(f: () throws -> ()) rethrows {} +// CHECK: func rethrowFunc(f: () throws -> ()) rethrows {} func rethrowFunc(f: () throws -> ()) rethrows {} class NestedPoundIf{ diff --git a/test/IDE/test-input-complete/test_input.swift b/test/IDE/test-input-complete/test_input.swift index 9060b11c61f3e..93c8585978008 100644 --- a/test/IDE/test-input-complete/test_input.swift +++ b/test/IDE/test-input-complete/test_input.swift @@ -22,11 +22,11 @@ // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/switch_incomplete3.swift | FileCheck %s -check-prefix=INCOMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_complete.swift | FileCheck %s -check-prefix=COMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete.swift | FileCheck %s -check-prefix=INCOMPLETE -// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete2.swift | FileCheck %s -check-prefix=INCOMPLETE -// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete3.swift | FileCheck %s -check-prefix=INCOMPLETE +// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete2.swift | FileCheck %s -check-prefix=COMPLETE +// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete3.swift | FileCheck %s -check-prefix=COMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete4.swift | FileCheck %s -check-prefix=INCOMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/toplevel_incomplete5.swift | FileCheck %s -check-prefix=INCOMPLETE -// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/type_incomplete1.swift | FileCheck %s -check-prefix=INCOMPLETE +// RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/type_incomplete1.swift | FileCheck %s -check-prefix=COMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/type_incomplete2.swift | FileCheck %s -check-prefix=INCOMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/type_incomplete3.swift | FileCheck %s -check-prefix=INCOMPLETE // RUN: %swift-ide-test -test-input-complete -source-filename %S/Inputs/type_incomplete4.swift | FileCheck %s -check-prefix=INCOMPLETE diff --git a/test/IRGen/Inputs/ObjcSuperClass.swift b/test/IRGen/Inputs/ObjcSuperClass.swift deleted file mode 100644 index cb3fcdf5a9791..0000000000000 --- a/test/IRGen/Inputs/ObjcSuperClass.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation - -public class ObjCSubclass : NSObject { - // This properties will have a non constant field access due to the objc super - // class. - public final var field : Int32 - - public override init () { - field = 10 - } - -}; diff --git a/test/IRGen/Inputs/report_dead_method_call/main.swift b/test/IRGen/Inputs/report_dead_method_call/main.swift index 962f09c1c5eac..6151ddb1f43ed 100644 --- a/test/IRGen/Inputs/report_dead_method_call/main.swift +++ b/test/IRGen/Inputs/report_dead_method_call/main.swift @@ -38,5 +38,5 @@ case 3: callPublicClass() default: - break; + break } diff --git a/test/IRGen/Inputs/usr/include/BridgeTestFoundation.h b/test/IRGen/Inputs/usr/include/BridgeTestFoundation.h index 054247a60f214..a50e30dd60811 100644 --- a/test/IRGen/Inputs/usr/include/BridgeTestFoundation.h +++ b/test/IRGen/Inputs/usr/include/BridgeTestFoundation.h @@ -52,7 +52,7 @@ typedef struct NSZone NSZone; typedef struct __CGImage *CGImageRef; -__attribute__((availability(macosx,introduced=10.10))) +__attribute__((availability(macosx,introduced=10.51))) @interface NSUserNotificationAction : NSObject @end diff --git a/test/IRGen/NonConstantAddressFieldAccess.swift b/test/IRGen/NonConstantAddressFieldAccess.swift deleted file mode 100644 index 2ec20e4aaf64e..0000000000000 --- a/test/IRGen/NonConstantAddressFieldAccess.swift +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %target-build-swift %S/Inputs/ObjcSuperClass.swift %s -module-name a -emit-ir 2>&1 | FileCheck %s -// REQUIRES: executable_test - -// REQUIRES: objc_interop - -// CHECK: @_TWvdvC1a12ObjCSubclass5fieldVs5Int32 = global i{{[0-9]+}} -// CHECK: @_TWvdvC1a12ObjCSubclass5fieldVs5Int32 = external global i{{[0-9]+}} - -func test(o: ObjCSubclass) { - o.field = 10 -} diff --git a/test/IRGen/UseObjCMethod.swift b/test/IRGen/UseObjCMethod.swift index 35d61b8f31ee0..b3522b913433f 100644 --- a/test/IRGen/UseObjCMethod.swift +++ b/test/IRGen/UseObjCMethod.swift @@ -21,7 +21,7 @@ func testDemo() { testDemo() -// Make sure the clang importer puts the selectors and co into the lllvm.compiler used variable. +// Make sure the clang importer puts the selectors and co into the llvm.compiler used variable. // CHECK: @llvm.compiler.used = appending global [{{.*}} x i8*] [{{.*}} @"OBJC_CLASSLIST_REFERENCES_$_"{{.*}}@OBJC_METH_VAR_NAME_{{.*}}@OBJC_SELECTOR_REFERENCES_{{.*}}@OBJC_METH_VAR_NAME_.1{{.*}}@OBJC_SELECTOR_REFERENCES_.2{{.*}}] diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift index faed12c278607..b03cfc02fb01d 100644 --- a/test/IRGen/abitypes.swift +++ b/test/IRGen/abitypes.swift @@ -61,7 +61,7 @@ class Foo { } // Call from Swift entrypoint with exploded Rect to @objc entrypoint - // with unexploaded ABI-coerced type. + // with unexploded ABI-coerced type. // x86_64-macosx: define hidden float @_TFC8abitypes3Foo17getXFromRectSwift{{.*}}(%VSC6MyRect* noalias nocapture dereferenceable({{.*}}), [[SELF:%.*]]*) {{.*}} { // x86_64-macosx: [[COERCED:%.*]] = alloca [[MYRECT:%.*MyRect.*]], align 4 // x86_64-macosx: [[SEL:%.*]] = load i8*, i8** @"\01L_selector(getXFromRect:)", align 8 @@ -103,7 +103,7 @@ class Foo { // Make sure the caller-side from Swift also uses indirect-byval for the argument // x86_64-macosx: define hidden float @_TFC8abitypes3Foo25getXFromRectIndirectSwift{{.*}}(%VSC6MyRect* noalias nocapture dereferenceable({{.*}}), %C8abitypes3Foo*) {{.*}} { func getXFromRectIndirectSwift(r: MyRect) -> Float { - let f : Float = 1.0; + let f : Float = 1.0 // x86_64-macosx: [[TEMP:%.*]] = alloca [[TEMPTYPE:%.*]], align 4 // x86_64-macosx: [[RESULT:%.*]] = call float bitcast (void ()* @objc_msgSend to float (i8*, i8*, float, float, float, float, float, float, float, [[TEMPTYPE]]*)*)(i8* %{{.*}}, i8* %{{.*}}, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, [[TEMPTYPE]]* byval align 4 [[TEMP]]) // x86_64-macosx: ret float [[RESULT]] @@ -172,9 +172,13 @@ class Foo { // x86_64-macosx: define hidden { i32, i32 } @_TFC8abitypes3Foo9getnested{{.*}}(%CSo13StructReturns*, %C8abitypes3Foo*) {{.*}} { // x86_64-macosx: call i64 bitcast (void ()* @objc_msgSend to i64 ([[OPAQUE:.*]]*, i8*)*) + // x86_64-macosx-NEXT: bitcast + // x86_64-macosx-NEXT: llvm.lifetime.start // x86_64-macosx-NEXT: store i64 // x86_64-macosx-NEXT: bitcast i64* {{[^ ]*}} to { i32, i32 }* // x86_64-macosx-NEXT: load { i32, i32 }, { i32, i32 }* + // x86_64-macosx-NEXT: bitcast + // x86_64-macosx-NEXT: llvm.lifetime.end // x86_64-macosx: ret { i32, i32 } func getnested(p: StructReturns) -> NestedInts { return p.newNestedInts() @@ -427,7 +431,7 @@ class Foo { // Test that the makeOne() that we generate somewhere below doesn't // use arm_aapcscc for armv7. func callInline() -> Float { - return makeOne(3,5).second; + return makeOne(3,5).second } } diff --git a/test/IRGen/alignment.sil b/test/IRGen/alignment.sil index c637765c60337..b0b22c0df4608 100644 --- a/test/IRGen/alignment.sil +++ b/test/IRGen/alignment.sil @@ -27,52 +27,52 @@ entry: // CHECK: load float{{.*}}, align 4 // CHECK: load float{{.*}}, align 8 // CHECK: load float{{.*}}, align 4 - %z = load %a#1 : $*Foo + %z = load %a : $*Foo // CHECK: store float{{.*}}, align 16 // CHECK: store float{{.*}}, align 4 // CHECK: store float{{.*}}, align 8 // CHECK: store float{{.*}}, align 4 - store %z to %a#1 : $*Foo + store %z to %a : $*Foo // CHECK: load float{{.*}}, align 16 // CHECK: load float{{.*}}, align 4 // CHECK: load float{{.*}}, align 8 // CHECK: load float{{.*}}, align 4 - %y = load %b#1 : $*Singleton + %y = load %b : $*Singleton // CHECK: store float{{.*}}, align 16 // CHECK: store float{{.*}}, align 4 // CHECK: store float{{.*}}, align 8 // CHECK: store float{{.*}}, align 4 - store %y to %b#1 : $*Singleton + store %y to %b : $*Singleton - %x = load %c#1 : $*Empty - store %x to %c#1 : $*Empty + %x = load %c : $*Empty + store %x to %c : $*Empty // CHECK: load i2{{.*}}, align 16 - %w = load %d#1 : $*NoPayload + %w = load %d : $*NoPayload // CHECK: store i2{{.*}}, align 16 - store %w to %d#1 : $*NoPayload + store %w to %d : $*NoPayload // CHECK: load i32{{.*}}, align 16 // CHECK: load i1{{.*}}, align 4 - %v = load %e#1 : $*SinglePayload + %v = load %e : $*SinglePayload // CHECK: store i32{{.*}}, align 16 // CHECK: store i1{{.*}}, align 4 - store %v to %e#1 : $*SinglePayload + store %v to %e : $*SinglePayload // CHECK: load i32{{.*}}, align 16 // CHECK: load i2{{.*}}, align 4 - %u = load %f#1 : $*MultiPayload + %u = load %f : $*MultiPayload // CHECK: store i32{{.*}}, align 16 // CHECK: store i2{{.*}}, align 4 - store %u to %f#1 : $*MultiPayload + store %u to %f : $*MultiPayload - dealloc_stack %f#0 : $*@local_storage MultiPayload - dealloc_stack %e#0 : $*@local_storage SinglePayload - dealloc_stack %d#0 : $*@local_storage NoPayload - dealloc_stack %c#0 : $*@local_storage Empty - dealloc_stack %b#0 : $*@local_storage Singleton - dealloc_stack %a#0 : $*@local_storage Foo + dealloc_stack %f : $*MultiPayload + dealloc_stack %e : $*SinglePayload + dealloc_stack %d : $*NoPayload + dealloc_stack %c : $*Empty + dealloc_stack %b : $*Singleton + dealloc_stack %a : $*Foo return undef : $() } diff --git a/test/IRGen/array_value_witnesses.sil b/test/IRGen/array_value_witnesses.sil index 65df3cc8a9d15..06bcf66e03227 100644 --- a/test/IRGen/array_value_witnesses.sil +++ b/test/IRGen/array_value_witnesses.sil @@ -50,7 +50,7 @@ struct SomeWeak { // CHECK: @_TwtTV21array_value_witnesses8SomeWeak // CHECK-LABEL: define linkonce_odr hidden void @_TwXxV21array_value_witnesses8SomeWeak -// CHECK: (%swift.opaque* [[ARRAY_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %Self) {{.*}} { +// CHECK: (%swift.opaque* [[ARRAY_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %SomeWeak) {{.*}} { // CHECK: [[BEGIN:%.*]] = bitcast %swift.opaque* [[ARRAY_PTR]] to [[SOMEWEAK:%V21array_value_witnesses8SomeWeak]]* // CHECK: br label %iter // CHECK: iter: @@ -68,7 +68,7 @@ struct SomeWeak { // CHECK: ret // CHECK-LABEL: define linkonce_odr hidden %swift.opaque* @_TwCcV21array_value_witnesses8SomeWeak -// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %Self) {{.*}} { +// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %SomeWeak) {{.*}} { // CHECK: [[DEST_BEGIN:%.*]] = bitcast %swift.opaque* [[DEST_PTR]] to [[SOMEWEAK]]* // CHECK: [[SRC_BEGIN:%.*]] = bitcast %swift.opaque* [[SRC_PTR]] to [[SOMEWEAK]]* // CHECK: br label %iter @@ -90,7 +90,7 @@ struct SomeWeak { // CHECK: ret // CHECK-LABEL: define linkonce_odr hidden %swift.opaque* @_TwTtV21array_value_witnesses8SomeWeak -// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %Self) {{.*}} { +// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %SomeWeak) {{.*}} { // CHECK: [[DEST_BEGIN:%.*]] = bitcast %swift.opaque* [[DEST_PTR]] to [[SOMEWEAK]]* // CHECK: [[SRC_BEGIN:%.*]] = bitcast %swift.opaque* [[SRC_PTR]] to [[SOMEWEAK]]* // CHECK: br label %iter @@ -112,7 +112,7 @@ struct SomeWeak { // CHECK: ret // CHECK-LABEL: define linkonce_odr hidden %swift.opaque* @_TwtTV21array_value_witnesses8SomeWeak -// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %Self) {{.*}} { +// CHECK: (%swift.opaque* [[DEST_PTR:%.*]], %swift.opaque* [[SRC_PTR:%.*]], [[WORD:i[0-9]+]] [[COUNT:%.*]], %swift.type* %SomeWeak) {{.*}} { // CHECK: [[DEST_BEGIN:%.*]] = bitcast %swift.opaque* [[DEST_PTR]] to [[SOMEWEAK]]* // CHECK: [[SRC_BEGIN:%.*]] = bitcast %swift.opaque* [[SRC_PTR]] to [[SOMEWEAK]]* // CHECK: [[DEST_END:%.*]] = getelementptr inbounds [[SOMEWEAK]], [[SOMEWEAK]]* [[DEST_BEGIN]], [[WORD]] [[COUNT]] diff --git a/test/IRGen/associated_type_witness.swift b/test/IRGen/associated_type_witness.swift new file mode 100644 index 0000000000000..66593d1852c3e --- /dev/null +++ b/test/IRGen/associated_type_witness.swift @@ -0,0 +1,152 @@ +// RUN: %target-swift-frontend -primary-file %s -emit-ir > %t.ll +// RUN: FileCheck %s -check-prefix=GLOBAL < %t.ll +// RUN: FileCheck %s < %t.ll +// REQUIRES: CPU=x86_64 + +protocol P {} +protocol Q {} + +protocol Assocked { + typealias Assoc : P, Q +} + +struct Universal : P, Q {} + +// Witness table access functions for Universal : P and Universal : Q. +// CHECK-LABEL: define hidden i8** @_TWaV23associated_type_witness9UniversalS_1PS_() +// CHECK: ret i8** getelementptr inbounds ([0 x i8*], [0 x i8*]* @_TWPV23associated_type_witness9UniversalS_1PS_, i32 0, i32 0) +// CHECK-LABEL: define hidden i8** @_TWaV23associated_type_witness9UniversalS_1QS_() +// CHECK: ret i8** getelementptr inbounds ([0 x i8*], [0 x i8*]* @_TWPV23associated_type_witness9UniversalS_1QS_, i32 0, i32 0) + +// Witness table for WithUniversal : Assocked. +// GLOBAL-LABEL: @_TWPV23associated_type_witness13WithUniversalS_8AssockedS_ = hidden constant [3 x i8*] [ +// GLOBAL-SAME: i8* bitcast (%swift.type* ()* @_TMaV23associated_type_witness9Universal to i8*) +// GLOBAL-SAME: i8* bitcast (i8** ()* @_TWaV23associated_type_witness9UniversalS_1PS_ to i8*) +// GLOBAL-SAME: i8* bitcast (i8** ()* @_TWaV23associated_type_witness9UniversalS_1QS_ to i8*) +// GLOBAL-SAME: ] +struct WithUniversal : Assocked { + typealias Assoc = Universal +} + +// Witness table for GenericWithUniversal : Assocked. +// GLOBAL-LABEL: @_TWPurGV23associated_type_witness20GenericWithUniversalx_S_8AssockedS_ = hidden constant [3 x i8*] [ +// GLOBAL-SAME: i8* bitcast (%swift.type* ()* @_TMaV23associated_type_witness9Universal to i8*) +// GLOBAL-SAME: i8* bitcast (i8** ()* @_TWaV23associated_type_witness9UniversalS_1PS_ to i8*) +// GLOBAL-SAME: i8* bitcast (i8** ()* @_TWaV23associated_type_witness9UniversalS_1QS_ to i8*) +// GLOBAL-SAME: ] +struct GenericWithUniversal : Assocked { + typealias Assoc = Universal +} + +// Witness table for Fulfilled : Assocked. +// GLOBAL-LABEL: @_TWPuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_ = hidden constant [3 x i8*] [ +// GLOBAL-SAME: i8* bitcast (%swift.type* (%swift.type*, i8**)* @_TWtuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5Assoc to i8*) +// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_TWTuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5AssocPS_1P_ to i8*) +// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_TWTuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5AssocPS_1Q_ to i8*) +// GLOBAL-SAME: ] +struct Fulfilled > : Assocked { + typealias Assoc = T +} + +// Associated type metadata access function for Fulfilled.Assoc. +// CHECK-LABEL: define internal %swift.type* @_TWtuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5Assoc(%swift.type* %"Fulfilled", i8** %"Fulfilled.Assocked") +// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Fulfilled" to %swift.type** +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 3 +// CHECK-NEXT: [[T2:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load +// CHECK-NEXT: ret %swift.type* [[T2]] + +// Associated type witness table access function for Fulfilled.Assoc : P. +// CHECK-LABEL: define internal i8** @_TWTuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5AssocPS_1P_(%swift.type* %"Fulfilled.Assoc", %swift.type* %"Fulfilled", i8** %"Fulfilled.Assocked") +// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Fulfilled" to i8*** +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 4 +// CHECK-NEXT: [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load +// CHECK-NEXT: ret i8** [[T2]] + +// Associated type witness table access function for Fulfilled.Assoc : Q. +// CHECK-LABEL: define internal i8** @_TWTuRx23associated_type_witness1PxS_1QrGVS_9Fulfilledx_S_8AssockedS_5AssocPS_1Q_(%swift.type* %"Fulfilled.Assoc", %swift.type* %"Fulfilled", i8** %"Fulfilled.Assocked") +// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Fulfilled" to i8*** +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 5 +// CHECK-NEXT: [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load +// CHECK-NEXT: ret i8** [[T2]] + +struct Pair : P, Q {} + +// Generic witness table pattern for Computed : Assocked. +// GLOBAL-LABEL: @_TWPu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_ = hidden constant [3 x i8*] [ +// GLOBAL-SAME: i8* bitcast (%swift.type* (%swift.type*, i8**)* @_TWtu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_5Assoc to i8*) +// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_TWTu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_5AssocPS_1P_ to i8*) +// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_TWTu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_5AssocPS_1Q_ to i8*) +// GLOBAL-SAME: ] +// Generic witness table cache for Computed : Assocked. +// GLOBAL-LABEL: @_TWGu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_ = internal global %swift.generic_witness_table_cache { +// GLOBAL-SAME: i16 4, +// GLOBAL-SAME: i16 3, +// GLOBAL-SAME: i32 trunc (i64 sub (i64 ptrtoint ([3 x i8*]* @_TWPu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_ to i64), i64 ptrtoint (i32* getelementptr inbounds (%swift.generic_witness_table_cache, %swift.generic_witness_table_cache* @_TWGu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_, i32 0, i32 2) to i64)) to i32) +// GLOBAL-SAME: i32 0, +// GLOBAL-SAME: [16 x i8*] zeroinitializer +// GLOBAL-SAME: } +struct Computed : Assocked { + typealias Assoc = Pair +} + +// Associated type metadata access function for Computed.Assoc. +// CHECK-LABEL: define internal %swift.type* @_TWtu0_rGV23associated_type_witness8Computedxq__S_8AssockedS_5Assoc(%swift.type* %"Computed", i8** %"Computed.Assocked") +// CHECK: entry: +// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** %"Computed.Assocked", i32 3 +// CHECK-NEXT: [[CACHE:%.*]] = bitcast i8** [[T0]] to %swift.type** +// CHECK-NEXT: [[CACHE_RESULT:%.*]] = load %swift.type*, %swift.type** [[CACHE]], align 8 +// CHECK-NEXT: [[T1:%.*]] = icmp eq %swift.type* [[CACHE_RESULT]], null +// CHECK-NEXT: br i1 [[T1]], label %fetch, label %cont +// CHECK: cont: +// CHECK-NEXT: [[T0:%.*]] = phi %swift.type* [ [[CACHE_RESULT]], %entry ], [ [[FETCH_RESULT:%.*]], %fetch ] +// CHECK-NEXT: ret %swift.type* [[T0]] +// CHECK: fetch: +// CHECK-NEXT: [[T0:%.*]] = bitcast %swift.type* %"Computed" to %swift.type** +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 3 +// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load +// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Computed" to %swift.type** +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i64 4 +// CHECK-NEXT: [[U:%.*]] = load %swift.type*, %swift.type** [[T1]], align 8, !invariant.load +// CHECK-NEXT: [[FETCH_RESULT]] = call %swift.type* @_TMaV23associated_type_witness4Pair(%swift.type* [[T]], %swift.type* [[U]]) +// CHECK-NEXT: store atomic %swift.type* [[FETCH_RESULT]], %swift.type** [[CACHE]] release, align 8 +// CHECK-NEXT: br label %cont + +struct PBox {} +protocol HasSimpleAssoc { + typealias Assoc +} +protocol DerivedFromSimpleAssoc : HasSimpleAssoc {} + + +// Generic witness table pattern for GenericComputed : DerivedFromSimpleAssoc. +// GLOBAL-LABEL: @_TWPuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_ = hidden constant [1 x i8*] zeroinitializer +// Generic witness table cache for GenericComputed : DerivedFromSimpleAssoc. +// GLOBAL-LABEL: @_TWGuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_ = internal global %swift.generic_witness_table_cache { +// GLOBAL-SAME: i16 1, +// GLOBAL-SAME: i16 1, +// GLOBAL-SAME: i32 trunc (i64 sub (i64 ptrtoint ([1 x i8*]* @_TWPuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_ to i64), i64 ptrtoint (i32* getelementptr inbounds (%swift.generic_witness_table_cache, %swift.generic_witness_table_cache* @_TWGuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_, i32 0, i32 2) to i64)) to i32) +// GLOBAL-SAME: i32 trunc (i64 sub (i64 ptrtoint (void (i8**, %swift.type*, i8**)* @_TWIuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_ to i64), i64 ptrtoint (i32* getelementptr inbounds (%swift.generic_witness_table_cache, %swift.generic_witness_table_cache* @_TWGuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_, i32 0, i32 3) to i64)) to i32), +// GLOBAL-SAME: [16 x i8*] zeroinitializer +// GLOBAL-SAME: } +struct GenericComputed : DerivedFromSimpleAssoc { + typealias Assoc = PBox +} + +// Instantiation function for GenericComputed : DerivedFromSimpleAssoc. +// CHECK-LABEL: define internal void @_TWIuRx23associated_type_witness1PrGVS_15GenericComputedx_S_22DerivedFromSimpleAssocS_(i8**, %swift.type*, i8**) +// CHECK: [[T0:%.*]] = call i8** @_TWauRx23associated_type_witness1PrGVS_15GenericComputedx_S_14HasSimpleAssocS_(%swift.type* %1) +// CHECK-NEXT: [[T1:%.*]] = bitcast i8** [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8*, i8** %0, i32 0 +// CHECK-NEXT: store i8* [[T1]], i8** [[T2]], align 8 +// CHECK-NEXT: ret void + +protocol HasAssocked { + typealias Contents : Assocked +} +struct FulfilledFromAssociatedType : HasSimpleAssoc { + typealias Assoc = PBox +} + +struct UsesVoid : HasSimpleAssoc { + typealias Assoc = () +} diff --git a/test/IRGen/autorelease.sil b/test/IRGen/autorelease.sil index 60bcd16791c61..1cd35cd4e1f3e 100644 --- a/test/IRGen/autorelease.sil +++ b/test/IRGen/autorelease.sil @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-ir | FileCheck -check-prefix=%target-cpu %s +// REQUIRES: objc_interop // rdar://16565958 @@ -43,7 +44,6 @@ bb0(%0 : $C?): // armv7k: [[T0:%.*]] = tail call i32 bitcast ([[OBJC]]* ([[OBJC]]*)* @objc_autoreleaseReturnValue to i32 (i32)*)(i32 %0) // armv7k-NEXT: ret i32 [[T0]] - sil @bar : $@convention(thin) (@owned C?) -> @owned C? { bb0(%0 : $C?): %1 = function_ref @foo : $@convention(thin) (@owned C?) -> @autoreleased C? diff --git a/test/IRGen/bitcast.sil b/test/IRGen/bitcast.sil index c01fe621033dd..e225c9bfb465b 100644 --- a/test/IRGen/bitcast.sil +++ b/test/IRGen/bitcast.sil @@ -91,9 +91,9 @@ bb0(%0 : $ImplicitlyUnwrappedOptional): // CHECK-x86_64: store i64 %{{.*}}, i64* %bitcast.elt._value, align 8 // CHECK-x86_64: store i64 %{{.*}}, i64* %bitcast.elt1._value, align 8 // CHECK-x86_64-NEXT: %{{.*}} = bitcast <{ %Si, %Si }>* %bitcast to %Si* -// CHECK-x86_64-NEXT: [[VAL:%.*]] = getelementptr inbounds %Si, %Si* %2, i32 0, i32 0 +// CHECK-x86_64-NEXT: [[VAL:%.*]] = getelementptr inbounds %Si, %Si* %{{.*}}, i32 0, i32 0 // CHECK-x86_64-NEXT: [[RESULT:%.*]] = load i64, i64* [[VAL]], align 8 -// CHECK-x86_64-NEXT: ret i64 [[RESULT]] +// CHECK-x86_64: ret i64 [[RESULT]] // CHECK-x86_64-NEXT: } sil hidden @unchecked_bitwise_cast : $@convention(thin) (Int, Int) -> Int { bb0(%0 : $Int, %1 : $Int): @@ -120,9 +120,9 @@ bb0(%0 : $Int, %1 : $Int): sil @unchecked_ref_cast_addr : $@convention(thin) (@out U, @in T) -> () { bb0(%0 : $*U, %1 : $*T): %a = alloc_stack $T - copy_addr %1 to [initialization] %a#1 : $*T - unchecked_ref_cast_addr T in %a#1 : $*T to U in %0 : $*U - dealloc_stack %a#0 : $*@local_storage T + copy_addr %1 to [initialization] %a : $*T + unchecked_ref_cast_addr T in %a : $*T to U in %0 : $*U + dealloc_stack %a : $*T destroy_addr %1 : $*T %r = tuple () return %r : $() diff --git a/test/IRGen/bitcast_specialization.swift b/test/IRGen/bitcast_specialization.swift index 26618be64cab5..689e6a2f2616a 100644 --- a/test/IRGen/bitcast_specialization.swift +++ b/test/IRGen/bitcast_specialization.swift @@ -5,7 +5,7 @@ // specialized version fo myDictionaryBridge. // -// A miminized version of _dictionaryBridgeToObjectiveC in the stdlib +// A minimized version of _dictionaryBridgeToObjectiveC in the stdlib public func myDictionaryBridge< SrcType, DestType >( diff --git a/test/IRGen/boxed_existential.sil b/test/IRGen/boxed_existential.sil index f83ee3088298d..bbb5d21c02465 100644 --- a/test/IRGen/boxed_existential.sil +++ b/test/IRGen/boxed_existential.sil @@ -21,10 +21,11 @@ entry(%x : $*T): // CHECK: [[BOX:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 0 // CHECK: [[ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1 %b = alloc_existential_box $ErrorType, $T + %p = project_existential_box $T in %b : $ErrorType // CHECK: call %swift.opaque* %initializeWithTake(%swift.opaque* [[ADDR]], %swift.opaque* %0, %swift.type* %T) - copy_addr [take] %x to [initialization] %b#1 : $*T + copy_addr [take] %x to [initialization] %p : $*T // CHECK: ret %swift.error* [[BOX]] - return %b#0 : $ErrorType + return %b : $ErrorType } struct SomeError: ErrorType { @@ -40,9 +41,10 @@ entry(%x : $SomeError): // CHECK: [[OPAQUE_ADDR:%.*]] = extractvalue { %swift.error*, %swift.opaque* } [[BOX_PAIR]], 1 // CHECK: [[ADDR:%.*]] = bitcast %swift.opaque* [[OPAQUE_ADDR]] to %V17boxed_existential9SomeError* %b = alloc_existential_box $ErrorType, $SomeError - store %x to %b#1 : $*SomeError + %p = project_existential_box $SomeError in %b : $ErrorType + store %x to %p : $*SomeError // CHECK: ret %swift.error* [[BOX]] - return %b#0 : $ErrorType + return %b : $ErrorType } // CHECK-LABEL: define void @dealloc_boxed_existential(%swift.error*, %swift.type* %T, i8** %T.ErrorType) @@ -53,6 +55,26 @@ entry(%b : $ErrorType): return undef : $() } +// CHECK-LABEL: define {{i[0-9]+}} @project_boxed_existential(%swift.error*) +sil @project_boxed_existential : $@convention(thin) (@owned ErrorType) -> Int { +entry(%b : $ErrorType): + // CHECK: call void @swift_getErrorValue(%swift.error* %0, i8** {{%.*}}, [[TRIPLE:{ %swift.opaque\*, %swift.type\*, i8\*\* }]]* [[OUT:%.*]]) + // CHECK: [[OUT_ADDR:%.*]] = getelementptr inbounds {{.*}} [[OUT]], i32 0, i32 0 + // CHECK: [[ADDR:%.*]] = load {{.*}} [[OUT_ADDR]] + // CHECK: [[CADDR:%.*]] = bitcast %swift.opaque* %2 to [[TYPE:%[^*]*]]* + %a = project_existential_box $SomeError in %b : $ErrorType + + // CHECK: [[GEP1:%.*]] = getelementptr inbounds [[TYPE]], [[TYPE]]* [[CADDR]], i32 0, i32 1 + // CHECK: [[GEP2:%.*]] = getelementptr inbounds {{.*}} [[GEP1]], i32 0, i32 0 + %c = struct_element_addr %a : $*SomeError, #SomeError._code + + // CHECK: [[R:%.*]] = load {{i[0-9]+}}, {{i[0-9]+}}* [[GEP2]] + %l = load %c : $*Int + + // CHECK: ret {{i[0-9]+}} [[R]] + return %l : $Int +} + // CHECK-LABEL: define {{i[0-9]+}} @open_boxed_existential(%swift.error*) sil @open_boxed_existential : $@convention(thin) (@owned ErrorType) -> Int { entry(%b : $ErrorType): diff --git a/test/IRGen/c_functions.swift b/test/IRGen/c_functions.swift index 10f19c7dfcadb..91eebf6ccf7c9 100644 --- a/test/IRGen/c_functions.swift +++ b/test/IRGen/c_functions.swift @@ -7,6 +7,6 @@ func testOverloaded() { // CHECK: call void @_Z10overloadedv() overloaded() - // CHECK: call void @_Z10overloadedi(i32 42) + // CHECK: call void @_Z10overloadedi(i32{{( signext)?}} 42) overloaded(42) } // CHECK: {{^}$}} diff --git a/test/IRGen/class.sil b/test/IRGen/class.sil index d79646b635ec2..b36276fd7eb79 100644 --- a/test/IRGen/class.sil +++ b/test/IRGen/class.sil @@ -11,7 +11,6 @@ import Swift // CHECK: [[TYPE:%swift.type]] = type // CHECK: [[C_CLASS:%C5class1C]] = type // CHECK: [[REF:%swift.refcounted]] = type -// CHECK: [[D_CLASS:%C5class1D]] = type // CHECK: [[OBJCOBJ:%objc_object]] = type class C {} @@ -44,26 +43,6 @@ sil_vtable C {} // \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC5class1C to i64), i64 1) // \ CHECK: } -// CHECK: @_TMfC5class1D = internal global { {{.*}} } { -// \ CHECK: void ([[D_CLASS]]*)* @_TFC5class1DD, -// \ CHECK: i8** @_TWVBo, -// \ CHECK: i64 ptrtoint ([[OBJCCLASS]]* @_TMmC5class1D to i64), -// \ CHECK: [[OBJCCLASS]]* @"OBJC_CLASS_$_SwiftObject", -// \ CHECK: [[OPAQUE]]* @_objc_empty_cache, -// \ CHECK: [[OPAQUE]]* null, -// \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC5class1D to i64), i64 1), -// \ CHECK: i32 3, -// \ CHECK: i32 0, -// \ CHECK: i32 16, -// \ CHECK: i16 7, -// \ CHECK: i16 0, -// \ CHECK: i32 112, -// \ CHECK: i32 16, -// \ CHECK: {{.*}}* @_TMnC5class1D, -// \ CHECK: i8* null, -// \ CHECK: i32 (i16, i8, [[D_CLASS]]*)* @_TFC5class1D8multiplyfS0_fT1xBi8__FT1yBi16__Bi32_ -// \ CHECK: } - // Destroying destructor // CHECK: define [[REF]]* @_TFC5class1Cd([[C_CLASS]]*) {{.*}} { // CHECK-NEXT: entry: @@ -109,28 +88,6 @@ entry(%c : $C): return %r : $Builtin.UnknownObject } -// Part of rdar://16079147 -// vtable tested above -class D { - func multiply(x x : Builtin.Int8)(y : Builtin.Int16) -> Builtin.Int32 -} - -sil @_TFC5class1DD : $@convention(method) (@owned D) -> () { -bb0(%0 : $D): - %1 = tuple () - return %1 : $() -} - -sil hidden @_TFC5class1D8multiplyfS0_fT1xBi8__FT1yBi16__Bi32_ : $@convention(method) (Builtin.Int16, Builtin.Int8, @guaranteed D) -> Builtin.Int32 { -bb0(%0 : $Builtin.Int16, %1 : $Builtin.Int8, %2 : $D): - %3 = integer_literal $Builtin.Int32, 0 - return %3 : $Builtin.Int32 -} - -sil_vtable D { - #D.multiply!2: _TFC5class1D8multiplyfS0_fT1xBi8__FT1yBi16__Bi32_ -} - // CHECK-LABEL: define %C5class1C* @alloc_ref_dynamic(%swift.type*) sil @alloc_ref_dynamic : $@convention(thin) (@thick C.Type) -> @owned C { bb0(%0 : $@thick C.Type): diff --git a/test/IRGen/class_bounded_generics.swift b/test/IRGen/class_bounded_generics.swift index f6907441651f9..6df1d565b9381 100644 --- a/test/IRGen/class_bounded_generics.swift +++ b/test/IRGen/class_bounded_generics.swift @@ -56,8 +56,8 @@ class ClassProtocolFieldClass { } // CHECK: %C22class_bounded_generics22ClassGenericFieldClass = type <{ %swift.refcounted, %Si, %objc_object*, %Si }> -// CHECK: %V22class_bounded_generics24ClassProtocolFieldStruct = type <{ %Si, %P22class_bounded_generics10ClassBound_, %Si }> // CHECK: %V22class_bounded_generics23ClassGenericFieldStruct = type <{ %Si, %objc_object*, %Si }> +// CHECK: %V22class_bounded_generics24ClassProtocolFieldStruct = type <{ %Si, %P22class_bounded_generics10ClassBound_, %Si }> // CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics23class_bounded_archetype{{.*}}(%objc_object*, %swift.type* %T, i8** %T.ClassBound) func class_bounded_archetype(x: T) -> T { diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift index 03eaee43a2967..68685743758d3 100644 --- a/test/IRGen/class_resilience.swift +++ b/test/IRGen/class_resilience.swift @@ -1,75 +1,259 @@ -// RUN: %target-swift-frontend -I %S/../Inputs -enable-source-import -emit-ir -enable-resilience %s | FileCheck %s +// RUN: %target-swift-frontend -I %S/../Inputs -enable-source-import -emit-ir -enable-resilience %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime // RUN: %target-swift-frontend -I %S/../Inputs -enable-source-import -emit-ir -enable-resilience -O %s -// CHECK: %Si = type <{ [[INT:i32|i64]] }> +// CHECK: %swift.type = type { [[INT:i32|i64]] } +// CHECK: @_TWvdvC16class_resilience26ClassWithResilientProperty1sV16resilient_struct4Size = global [[INT]] 0 +// CHECK: @_TWvdvC16class_resilience26ClassWithResilientProperty5colorVs5Int32 = global [[INT]] 0 + +// CHECK: @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty1rV16resilient_struct9Rectangle = global [[INT]] 0 +// CHECK: @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty5colorVs5Int32 = global [[INT]] 0 + +// CHECK: @_TWvdvC16class_resilience14ResilientChild5fieldVs5Int32 = global [[INT]] {{12|16}} +// CHECK: @_TWvivC16class_resilience21ResilientGenericChild5fieldVs5Int32 = global [[INT]] {{56|88}} + +// CHECK: @_TWvdvC16class_resilience28ClassWithMyResilientProperty1rVS_17MyResilientStruct = constant [[INT]] {{12|16}} +// CHECK: @_TWvdvC16class_resilience28ClassWithMyResilientProperty5colorVs5Int32 = constant [[INT]] {{16|20}} + +// CHECK: @_TWvdvC16class_resilience30ClassWithIndirectResilientEnum1sO14resilient_enum10FunnyShape = constant [[INT]] {{12|16}} +// CHECK: @_TWvdvC16class_resilience30ClassWithIndirectResilientEnum5colorVs5Int32 = constant [[INT]] {{16|24}} + +import resilient_class import resilient_struct import resilient_enum + // Concrete class with resilient stored property -public class MyRectangle { +public class ClassWithResilientProperty { public let p: Point public let s: Size - public let color: Int + public let color: Int32 - public init(p: Point, s: Size, color: Int) { + public init(p: Point, s: Size, color: Int32) { self.p = p self.s = s self.color = color } } + // Concrete class with non-fixed size stored property -public class ClassWithResilientLayout { +public class ClassWithResilientlySizedProperty { public let r: Rectangle - public let color: Int + public let color: Int32 + + public init(r: Rectangle, color: Int32) { + self.r = r + self.color = color + } +} + + +// Concrete class with resilient stored property that +// is fixed-layout inside this resilience domain + +public struct MyResilientStruct { + public let x: Int32 +} + +public class ClassWithMyResilientProperty { + public let r: MyResilientStruct + public let color: Int32 - public init(r: Rectangle, color: Int) { + public init(r: MyResilientStruct, color: Int32) { self.r = r self.color = color } } + // Enums with indirect payloads are fixed-size public class ClassWithIndirectResilientEnum { public let s: FunnyShape - public let color: Int + public let color: Int32 - public init(s: FunnyShape, color: Int) { + public init(s: FunnyShape, color: Int32) { self.s = s self.color = color } } -// FIXME: This is bogus since we don't emit code to initialize the -// global ivar offsets yet. +// Superclass is resilient, so the number of fields and their +// offsets is not known at compile time + +public class ResilientChild : ResilientOutsideParent { + public let field: Int32 = 0 +} + + +// Superclass is resilient, so the number of fields and their +// offsets is not known at compile time + +public class ResilientGenericChild : ResilientGenericOutsideParent { + public let field: Int32 = 0 +} + + +// Superclass is resilient and has a resilient value type payload, +// but everything is in one module + + +public class MyResilientParent { + public let s: MyResilientStruct = MyResilientStruct(x: 0) +} + +public class MyResilientChild : MyResilientParent { + public let field: Int32 = 0 +} + + +// ClassWithResilientProperty metadata accessor -// CHECK-LABEL: define {{i32|i64}} @_TFC16class_resilience11MyRectangleg5colorSi(%C16class_resilience11MyRectangle*) -// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC16class_resilience11MyRectangle5colorSi -// CHECK-NEXT: [[PTR:%.*]] = bitcast %C16class_resilience11MyRectangle* %0 to i8* +// CHECK-LABEL: define %swift.type* @_TMaC16class_resilience26ClassWithResilientProperty() +// CHECK: [[CACHE:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty +// CHECK-NEXT: [[COND:%.*]] = icmp eq %swift.type* [[CACHE]], null +// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont + +// CHECK: cacheIsNull: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( +// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty +// CHECK-NEXT: br label %cont + +// CHECK: cont: +// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] +// CHECK-NEXT: ret %swift.type* [[RESULT]] + + +// ClassWithResilientProperty.color getter + +// CHECK-LABEL: define i32 @_TFC16class_resilience26ClassWithResilientPropertyg5colorVs5Int32(%C16class_resilience26ClassWithResilientProperty*) +// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC16class_resilience26ClassWithResilientProperty5colorVs5Int32 +// CHECK-NEXT: [[PTR:%.*]] = bitcast %C16class_resilience26ClassWithResilientProperty* %0 to i8* // CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[PTR]], [[INT]] [[OFFSET]] -// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %Si* -// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Si, %Si* [[FIELD_PTR]], i32 0, i32 0 -// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD]] -// CHECK-NEXT: ret [[INT]] [[FIELD_VALUE]] +// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load i32, i32* [[FIELD_PAYLOAD]] +// CHECK-NEXT: ret i32 [[FIELD_VALUE]] + + +// ClassWithResilientlySizedProperty metadata accessor + +// CHECK-LABEL: define %swift.type* @_TMaC16class_resilience33ClassWithResilientlySizedProperty() +// CHECK: [[CACHE:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty +// CHECK-NEXT: [[COND:%.*]] = icmp eq %swift.type* [[CACHE]], null +// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont + +// CHECK: cacheIsNull: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( +// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty +// CHECK-NEXT: br label %cont +// CHECK: cont: +// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] +// CHECK-NEXT: ret %swift.type* [[RESULT]] -// CHECK-LABEL: define {{i32|i64}} @_TFC16class_resilience24ClassWithResilientLayoutg5colorSi(%C16class_resilience24ClassWithResilientLayout*) -// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC16class_resilience24ClassWithResilientLayout5colorSi -// CHECK-NEXT: [[PTR:%.*]] = bitcast %C16class_resilience24ClassWithResilientLayout* %0 to i8* + +// ClassWithResilientlySizedProperty.color getter + +// CHECK-LABEL: define i32 @_TFC16class_resilience33ClassWithResilientlySizedPropertyg5colorVs5Int32(%C16class_resilience33ClassWithResilientlySizedProperty*) +// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty5colorVs5Int32 +// CHECK-NEXT: [[PTR:%.*]] = bitcast %C16class_resilience33ClassWithResilientlySizedProperty* %0 to i8* // CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[PTR]], [[INT]] [[OFFSET]] -// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %Si* -// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Si, %Si* %.color, i32 0, i32 0 -// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD]] -// CHECK-NEXT: ret [[INT]] [[FIELD_VALUE]] +// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load i32, i32* [[FIELD_PAYLOAD]] +// CHECK-NEXT: ret i32 [[FIELD_VALUE]] + + +// ClassWithIndirectResilientEnum.color getter + +// CHECK-LABEL: define i32 @_TFC16class_resilience30ClassWithIndirectResilientEnumg5colorVs5Int32(%C16class_resilience30ClassWithIndirectResilientEnum*) +// CHECK: [[FIELD_PTR:%.*]] = getelementptr inbounds %C16class_resilience30ClassWithIndirectResilientEnum, %C16class_resilience30ClassWithIndirectResilientEnum* %0, i32 0, i32 2 +// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load i32, i32* [[FIELD_PAYLOAD]] +// CHECK-NEXT: ret i32 [[FIELD_VALUE]] + + +// ResilientChild.field getter + +// CHECK-LABEL: define i32 @_TFC16class_resilience14ResilientChildg5fieldVs5Int32(%C16class_resilience14ResilientChild*) +// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC16class_resilience14ResilientChild5fieldVs5Int32 +// CHECK-NEXT: [[PTR:%.*]] = bitcast %C16class_resilience14ResilientChild* %0 to i8* +// CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[PTR]], [[INT]] [[OFFSET]] +// CHECK-NEXT: [[FIELD_PTR:%.*]] = bitcast i8* [[FIELD_ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load i32, i32* [[FIELD_PAYLOAD]] +// CHECK-NEXT: ret i32 [[FIELD_VALUE]] + + +// ResilientGenericChild.field getter + + +// CHECK-LABEL: define i32 @_TFC16class_resilience21ResilientGenericChildg5fieldVs5Int32(%C16class_resilience21ResilientGenericChild*) + +// FIXME: we could eliminate the unnecessary isa load by lazily emitting +// metadata sources in EmitPolymorphicParameters + +// CHECK: %T = load + +// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds %C16class_resilience21ResilientGenericChild, %C16class_resilience21ResilientGenericChild* %0, i32 0, i32 0, i32 0 +// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ADDR]] +// CHECK-NEXT: [[INDIRECT_OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvivC16class_resilience21ResilientGenericChild5fieldVs5Int32 +// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to i8* +// CHECK-NEXT: [[FIELD_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_ADDR]], [[INT]] [[INDIRECT_OFFSET]] +// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = bitcast i8* [[FIELD_OFFSET_TMP]] to [[INT]]* +// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_ADDR:%.*]] +// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %C16class_resilience21ResilientGenericChild* %0 to i8* +// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[FIELD_OFFSET]] +// CHECK-NEXT: [[FIELD_ADDR:%.*]] = bitcast i8* [[ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_ADDR]], i32 0, i32 0 +// CHECK-NEXT: [[RESULT:%.*]] = load i32, i32* [[PAYLOAD_ADDR]] +// CHECK-NEXT: ret i32 [[RESULT]] + + +// MyResilientChild.field getter + +// CHECK-LABEL: define i32 @_TFC16class_resilience16MyResilientChildg5fieldVs5Int32(%C16class_resilience16MyResilientChild*) +// CHECK: [[FIELD_ADDR:%.*]] = getelementptr inbounds %C16class_resilience16MyResilientChild, %C16class_resilience16MyResilientChild* %0, i32 0, i32 2 +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_ADDR]], i32 0, i32 0 +// CHECK-NEXT: [[RESULT:%.*]] = load i32, i32* [[PAYLOAD_ADDR]] +// CHECK-NEXT: ret i32 [[RESULT]] + + +// ClassWithResilientProperty metadata instantiation function + + +// CHECK-LABEL: define private %swift.type* @create_generic_metadata_ClassWithResilientProperty(%swift.type_pattern*, i8**) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata( +// CHECK: [[SIZE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct4Size() +// CHECK: call void @swift_initClassMetadata_UniversalStrategy( +// CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* +// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] 12 +// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience26ClassWithResilientProperty1sV16resilient_struct4Size +// CHECK-native-NEXT: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* +// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] 13 +// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience26ClassWithResilientProperty5colorVs5Int32 +// CHECK: ret %swift.type* [[METADATA]] + +// ClassWithResilientlySizedProperty metadata instantiation function -// CHECK-LABEL: define {{i32|i64}} @_TFC16class_resilience30ClassWithIndirectResilientEnumg5colorSi(%C16class_resilience30ClassWithIndirectResilientEnum*) -// CHECK: [[FIELD_PTR:%.*]] = getelementptr inbounds %C16class_resilience30ClassWithIndirectResilientEnum, %C16class_resilience30ClassWithIndirectResilientEnum* %0, i32 0, i32 2 -// CHECK-NEXT: [[FIELD_PAYLOAD:%.*]] = getelementptr inbounds %Si, %Si* [[FIELD_PTR]], i32 0, i32 0 -// CHECK-NEXT: [[FIELD_VALUE:%.*]] = load [[INT]], [[INT]]* [[FIELD_PAYLOAD]] -// CHECK-NEXT: ret [[INT]] [[FIELD_VALUE]] +// CHECK-LABEL: define private %swift.type* @create_generic_metadata_ClassWithResilientlySizedProperty(%swift.type_pattern*, i8**) +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata( +// CHECK: [[RECTANGLE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct9Rectangle() +// CHECK: call void @swift_initClassMetadata_UniversalStrategy( +// CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* +// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] 11 +// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty1rV16resilient_struct9Rectangle +// CHECK-native-NEXT: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* +// CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] 12 +// CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] +// CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty5colorVs5Int32 +// CHECK: ret %swift.type* [[METADATA]] diff --git a/test/IRGen/class_resilience_objc.swift b/test/IRGen/class_resilience_objc.swift new file mode 100644 index 0000000000000..a8a701b845a21 --- /dev/null +++ b/test/IRGen/class_resilience_objc.swift @@ -0,0 +1,84 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-ir -o - -primary-file %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize + +// REQUIRES: objc_interop + +// CHECK: %swift.type = type { [[INT:i32|i64]] } + +import Foundation + +public class FixedLayoutObjCSubclass : NSObject { + // This field uses constant direct access because NSObject has fixed layout. + public final var field: Int32 = 0 +}; + +// CHECK-LABEL: define hidden void @_TF21class_resilience_objc29testConstantDirectFieldAccessFCS_23FixedLayoutObjCSubclassT_(%C21class_resilience_objc23FixedLayoutObjCSubclass*) +// CHECK: [[FIELD_ADDR:%.*]] = getelementptr inbounds %C21class_resilience_objc23FixedLayoutObjCSubclass, %C21class_resilience_objc23FixedLayoutObjCSubclass* %0, i32 0, i32 1 +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* %1, i32 0, i32 0 +// CHECK-NEXT: store i32 10, i32* [[PAYLOAD_ADDR]] + +func testConstantDirectFieldAccess(o: FixedLayoutObjCSubclass) { + o.field = 10 +} + +public class NonFixedLayoutObjCSubclass : NSCoder { + // This field uses non-constant direct access because NSCoder has resilient + // layout. + public final var field: Int32 = 0 +} + +// CHECK-LABEL: define hidden void @_TF21class_resilience_objc32testNonConstantDirectFieldAccessFCS_26NonFixedLayoutObjCSubclassT_(%C21class_resilience_objc26NonFixedLayoutObjCSubclass*) +// CHECK: [[OFFSET:%.*]] = load [[INT]], [[INT]]* @_TWvdvC21class_resilience_objc26NonFixedLayoutObjCSubclass5fieldVs5Int32 +// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %C21class_resilience_objc26NonFixedLayoutObjCSubclass* %0 to i8* +// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[OFFSET]] +// CHECK-NEXT: [[FIELD_ADDR:%.*]] = bitcast i8* [[ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_ADDR]], i32 0, i32 0 +// CHECK-NEXT: store i32 10, i32* [[PAYLOAD_ADDR]] + +func testNonConstantDirectFieldAccess(o: NonFixedLayoutObjCSubclass) { + o.field = 10 +} + +public class GenericObjCSubclass : NSCoder { + public final var content: T + public final var field: Int32 = 0 + + public init(content: T) { + self.content = content + } +} + +// CHECK-LABEL: define hidden void @_TF21class_resilience_objc31testConstantIndirectFieldAccessurFGCS_19GenericObjCSubclassx_T_(%C21class_resilience_objc19GenericObjCSubclass*) + +// FIXME: we could eliminate the unnecessary isa load by lazily emitting +// metadata sources in EmitPolymorphicParameters + +// CHECK: %T = load + +// CHECK-32-NEXT: [[ADDR:%.*]] = bitcast %C21class_resilience_objc19GenericObjCSubclass* %0 to %swift.type** +// CHECK-32-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ADDR]] + +// CHECK-64-NEXT: [[ADDR:%.*]] = bitcast %C21class_resilience_objc19GenericObjCSubclass* %0 to [[INT]]* +// CHECK-64-NEXT: [[ISA:%.*]] = load [[INT]], [[INT]]* [[ADDR]] +// CHECK-64-NEXT: [[ISA_MASK:%.*]] = load [[INT]], [[INT]]* @swift_isaMask +// CHECK-64-NEXT: [[ISA_VALUE:%.*]] = and [[INT]] [[ISA]], [[ISA_MASK]] +// CHECK-64-NEXT: [[ISA:%.*]] = inttoptr [[INT]] [[ISA_VALUE]] to %swift.type* + +// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to [[INT]]* + +// CHECK-32-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[ISA_ADDR]], [[INT]] 16 + +// CHECK-64-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[ISA_ADDR]], [[INT]] 13 + +// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_ADDR:%.*]] +// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %C21class_resilience_objc19GenericObjCSubclass* %0 to i8* +// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[FIELD_OFFSET]] +// CHECK-NEXT: [[FIELD_ADDR:%.*]] = bitcast i8* [[ADDR]] to %Vs5Int32* +// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = getelementptr inbounds %Vs5Int32, %Vs5Int32* [[FIELD_ADDR]], i32 0, i32 0 +// CHECK-NEXT: store i32 10, i32* [[PAYLOAD_ADDR]] + +func testConstantIndirectFieldAccess(o: GenericObjCSubclass) { + // This field uses constant indirect access because NSCoder has resilient + // layout. Non-constant indirect is never needed for Objective-C classes + // because the field offset vector only contains Swift field offsets. + o.field = 10 +} diff --git a/test/IRGen/class_stack_alloc.sil b/test/IRGen/class_stack_alloc.sil index 0bbf36b515d00..65a2af2b6b0d1 100644 --- a/test/IRGen/class_stack_alloc.sil +++ b/test/IRGen/class_stack_alloc.sil @@ -54,9 +54,9 @@ bb0: %s1 = alloc_stack $TestStruct %f = function_ref @unknown_func : $@convention(thin) (@inout TestStruct) -> () - %a = apply %f(%s1#1) : $@convention(thin) (@inout TestStruct) -> () + %a = apply %f(%s1) : $@convention(thin) (@inout TestStruct) -> () - dealloc_stack %s1#0 : $*@local_storage TestStruct + dealloc_stack %s1 : $*TestStruct strong_release %o1 : $TestClass strong_release %o2 : $TestClass diff --git a/test/IRGen/concrete_inherits_generic_base.swift b/test/IRGen/concrete_inherits_generic_base.swift index 27140d9107b11..7a4a66123f6d3 100644 --- a/test/IRGen/concrete_inherits_generic_base.swift +++ b/test/IRGen/concrete_inherits_generic_base.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -use-native-super-method -module-name foo -emit-ir %s | FileCheck %s +// RUN: %target-swift-frontend -module-name foo -emit-ir %s | FileCheck %s // -- Classes with generic bases can't go in the @objc_classes list, since // they need runtime initialization before they're valid. @@ -18,14 +18,33 @@ class Base { } // CHECK-LABEL: define %swift.type* @_TMaC3foo12SuperDerived() -// CHECK: [[SUPER:%.*]] = call %swift.type* @_TMaC3foo7Derived() -// CHECK: call void @swift_initializeSuperclass({{.*}}@_TMfC3foo12SuperDerived{{.*}}, %swift.type* [[SUPER]]) +// CHECK: [[CACHE:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo12SuperDerived +// CHECK-NEXT: [[COND:%.*]] = icmp eq %swift.type* [[CACHE]], null +// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont + +// CHECK: cacheIsNull: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( +// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo12SuperDerived +// CHECK-NEXT: br label %cont +// CHECK: cont: +// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] +// CHECK-NEXT: ret %swift.type* [[RESULT]] + class SuperDerived: Derived { } // CHECK-LABEL: define %swift.type* @_TMaC3foo7Derived() -// CHECK: [[SUPER:%.*]] = call %swift.type* @_TMaGC3foo4BaseSS_() -// CHECK: call void @swift_initializeSuperclass({{.*}}@_TMfC3foo7Derived{{.*}}, %swift.type* [[SUPER]]) +// CHECK: [[CACHE:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo7Derived +// CHECK-NEXT: [[COND:%.*]] = icmp eq %swift.type* [[CACHE]], null +// CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont + +// CHECK: cacheIsNull: +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( +// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo7Derived +// CHECK-NEXT: br label %cont +// CHECK: cont: +// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] +// CHECK-NEXT: ret %swift.type* [[RESULT]] class Derived: Base { var third: String @@ -49,3 +68,10 @@ presentBase(SuperDerived(x: "two")) presentBase(Derived(x: "two")) presentBase(Base(x: "two")) presentBase(Base(x: 2)) + +// CHECK-LABEL: define private %swift.type* @create_generic_metadata_SuperDerived(%swift.type_pattern*, i8**) +// CHECK: [[TMP:%.*]] = call %swift.type* @_TMaC3foo7Derived() +// CHECK-NEXT: [[SUPER:%.*]] = bitcast %swift.type* [[TMP:%.*]] to %objc_class* +// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]]) +// CHECK: call void @swift_initializeSuperclass(%swift.type* [[METADATA]], i1 false) +// CHECK-NEXT: ret %swift.type* [[METADATA]] diff --git a/test/IRGen/dynamic_cast.sil b/test/IRGen/dynamic_cast.sil index e73a0a3094a86..4e0d7b26137c6 100644 --- a/test/IRGen/dynamic_cast.sil +++ b/test/IRGen/dynamic_cast.sil @@ -28,9 +28,9 @@ bb0(%0 : $*P): // CHECK: [[T3:%.*]] = call [[TYPE:%.*]]* @_TMaP12dynamic_cast1P_() // CHECK: call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 7) %1 = alloc_stack $S - unconditional_checked_cast_addr take_always P in %0 : $*P to S in %1#1 : $*S - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + unconditional_checked_cast_addr take_always P in %0 : $*P to S in %1 : $*S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } @@ -47,9 +47,9 @@ bb0(%0 : $*P): // CHECK: [[T3:%.*]] = call [[TYPE:%.*]]* @_TMaP12dynamic_cast1P_() // CHECK: call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 3) %1 = alloc_stack $S - unconditional_checked_cast_addr take_on_success P in %0 : $*P to S in %1#1 : $*S - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + unconditional_checked_cast_addr take_on_success P in %0 : $*P to S in %1 : $*S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } @@ -63,9 +63,9 @@ bb0(%0 : $*P): // CHECK: [[T3:%.*]] = call [[TYPE:%.*]]* @_TMaP12dynamic_cast1P_() // CHECK: call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 1) %1 = alloc_stack $S - unconditional_checked_cast_addr copy_on_success P in %0 : $*P to S in %1#1 : $*S - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + unconditional_checked_cast_addr copy_on_success P in %0 : $*P to S in %1 : $*S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } @@ -80,12 +80,12 @@ bb0(%0 : $*P): // CHECK: [[T4:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 6) // CHECK: br i1 [[T4]], %1 = alloc_stack $S - checked_cast_addr_br take_always P in %0 : $*P to S in %1#1 : $*S, bb1, bb2 + checked_cast_addr_br take_always P in %0 : $*P to S in %1 : $*S, bb1, bb2 bb1: br bb2 bb2: - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } @@ -100,12 +100,12 @@ bb0(%0 : $*P): // CHECK: [[T4:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 2) // CHECK: br i1 [[T4]], %1 = alloc_stack $S - checked_cast_addr_br take_on_success P in %0 : $*P to S in %1#1 : $*S, bb1, bb2 + checked_cast_addr_br take_on_success P in %0 : $*P to S in %1 : $*S, bb1, bb2 bb1: br bb2 bb2: - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } @@ -120,12 +120,12 @@ bb0(%0 : $*P): // CHECK: [[T4:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], [[TYPE]]* [[T3]], [[TYPE]]* {{.*}}, [[LLVM_PTRSIZE_INT]] 0) // CHECK: br i1 [[T4]], %1 = alloc_stack $S - checked_cast_addr_br copy_on_success P in %0 : $*P to S in %1#1 : $*S, bb1, bb2 + checked_cast_addr_br copy_on_success P in %0 : $*P to S in %1 : $*S, bb1, bb2 bb1: br bb2 bb2: - destroy_addr %1#1 : $*S - dealloc_stack %1#0 : $*@local_storage S + destroy_addr %1 : $*S + dealloc_stack %1 : $*S %2 = tuple () return %2 : $() } diff --git a/test/IRGen/dynamic_lookup.sil b/test/IRGen/dynamic_lookup.sil index 9aab8d395d326..00d73e4377645 100644 --- a/test/IRGen/dynamic_lookup.sil +++ b/test/IRGen/dynamic_lookup.sil @@ -55,15 +55,17 @@ bb0(%0 : $X): sil @dynamic_lookup_br : $@convention(thin) (AnyObject) -> () { bb0(%0 : $AnyObject): %1 = alloc_box $AnyObject - store %0 to %1#1 : $*AnyObject + %1a = project_box %1 : $@box AnyObject + store %0 to %1a : $*AnyObject %3 = alloc_box $Optional<() -> ()> - %4 = load %1#1 : $*AnyObject + %4 = load %1a : $*AnyObject strong_retain %4 : $AnyObject %6 = open_existential_ref %4 : $AnyObject to $@opened("01234567-89ab-cdef-0123-000000000000") AnyObject %7 = unchecked_ref_cast %6 : $@opened("01234567-89ab-cdef-0123-000000000000") AnyObject to $Builtin.UnknownObject - // CHECK: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(f)", align {{(4|8)}} - // CHECK: [[HAS_SEL:%[0-9]]] = call i1 @swift_objcRespondsToSelector(%objc_object* [[OBJECT:%[0-9]+]], i8* [[SEL]]) + // CHECK: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(f)" + // CHECK: [[RESPONDS:%[0-9]+]] = load i8*, i8** @"\01L_selector(respondsToSelector:)" + // CHECK: [[HAS_SEL:%[0-9]]] = call i1 {{.*}}@objc_msgSend {{.*}}(%objc_object* [[OBJECT:%[0-9]+]], i8* [[RESPONDS]], i8* [[SEL]]) // CHECK: br i1 [[HAS_SEL]] dynamic_method_br %7 : $Builtin.UnknownObject, #X.f!1.foreign, bb1, bb2 @@ -82,7 +84,8 @@ bb3: sil @dynamic_lookup_static_br : $@convention(thin) (@thick AnyObject.Type) -> () { bb0(%0 : $@thick AnyObject.Type): // CHECK: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(g)", align {{(4|8)}} - // CHECK: [[HAS_SEL:%[0-9]]] = call i1 @swift_objcRespondsToSelector(%objc_object* [[OBJECT:%[0-9]+]], i8* [[SEL]]) + // CHECK: [[RESPONDS:%[0-9]+]] = load i8*, i8** @"\01L_selector(respondsToSelector:)" + // CHECK: [[HAS_SEL:%[0-9]]] = call i1 {{.*}}@objc_msgSend {{.*}}(%objc_object* [[OBJECT:%[0-9]+]], i8* [[RESPONDS]], i8* [[SEL]]) // CHECK: br i1 [[HAS_SEL]] %1 = open_existential_metatype %0 : $@thick AnyObject.Type to $@thick (@opened("EF9BE7CA-DFBF-11E4-99CB-28CFE91AF28F") AnyObject).Type dynamic_method_br %1 : $@thick (@opened("EF9BE7CA-DFBF-11E4-99CB-28CFE91AF28F") AnyObject).Type, #X.g!1.foreign, bb1, bb2 @@ -101,8 +104,9 @@ bb3: sil @_T1t23dynamic_lookup_propertyFT1xPSo13AnyObject__T_ : $@convention(thin) (AnyObject) -> () { bb0(%0 : $AnyObject): %1 = alloc_box $AnyObject - store %0 to %1#1 : $*AnyObject - %6 = load %1#1 : $*AnyObject // users: %24, %8, %7 + %1a = project_box %1 : $@box AnyObject + store %0 to %1a : $*AnyObject + %6 = load %1a : $*AnyObject // users: %24, %8, %7 strong_retain %6 : $AnyObject %8 = open_existential_ref %6 : $AnyObject to $@opened("01234567-89ab-cdef-0123-111111111111") AnyObject // users: %11, %9 %9 = unchecked_ref_cast %8 : $@opened("01234567-89ab-cdef-0123-111111111111") AnyObject to $Builtin.UnknownObject @@ -123,22 +127,25 @@ bb3: sil @_T1t16opt_to_subscriptFT3objPSo13AnyObject_1iSi_T_ : $@convention(thin) (AnyObject, Int) -> () { bb0(%0 : $AnyObject, %1 : $Int): %2 = alloc_box $AnyObject + %2a = project_box %2 : $@box AnyObject %3 = alloc_box $Int - store %0 to %2#1 : $*AnyObject - store %1 to %3#1 : $*Int - %8 = load %2#1 : $*AnyObject + %3a = project_box %3 : $@box Int + store %0 to %2a : $*AnyObject + store %1 to %3a : $*Int + %8 = load %2a : $*AnyObject strong_retain %8 : $AnyObject %10 = open_existential_ref %8 : $AnyObject to $@opened("01234567-89ab-cdef-0123-111111111111") AnyObject %11 = unchecked_ref_cast %10 : $@opened("01234567-89ab-cdef-0123-111111111111") AnyObject to $Builtin.UnknownObject // CHECK: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(objectAtIndexedSubscript:)", align {{(4|8)}} - // CHECK-NEXT: [[HAS_SEL:%[0-9]+]] = call i1 @swift_objcRespondsToSelector(%objc_object* %0, i8* [[SEL]]) + // CHECK: [[RESPONDS:%[0-9]+]] = load i8*, i8** @"\01L_selector(respondsToSelector:)" + // CHECK-NEXT: [[HAS_SEL:%[0-9]]] = call i1 {{.*}}@objc_msgSend {{.*}}(%objc_object* [[OBJECT:%[0-9]+]], i8* [[RESPONDS]], i8* [[SEL]]) // CHECK-NEXT: br i1 [[HAS_SEL]], label [[HAS_METHOD:%[0-9]+]], label [[HAS_METHOD:%[0-9]+]] dynamic_method_br %11 : $Builtin.UnknownObject, #X.subscript!getter.1.foreign, bb1, bb2 bb1(%13 : $@convention(objc_method) (Int, Builtin.UnknownObject) -> Int): // Preds: bb0 %14 = partial_apply %13(%11) : $@convention(objc_method) (Int, Builtin.UnknownObject) -> Int - %15 = load %3#1 : $*Int + %15 = load %3a : $*Int %16 = apply %14(%15) : $@callee_owned Int -> Int br bb3 diff --git a/test/IRGen/dynamic_self.sil b/test/IRGen/dynamic_self.sil index c1eb378b9013d..981871540bb02 100644 --- a/test/IRGen/dynamic_self.sil +++ b/test/IRGen/dynamic_self.sil @@ -16,11 +16,11 @@ sil @_TF12dynamic_self23testExistentialDispatchFT1pPS_1P__T_ : $@convention(thin bb0(%0 : $*P): debug_value_addr %0 : $*P, let, name "p" // id: %1 %2 = alloc_stack $P // users: %3, %4, %12 - copy_addr %0 to [initialization] %2#1 : $*P // id: %3 + copy_addr %0 to [initialization] %2 : $*P // id: %3 // CHECK: call %swift.opaque* // CHECK: call %swift.opaque* - %4 = open_existential_addr %2#1 : $*P to $*@opened("01234567-89ab-cdef-0123-000000000000") P // users: %8, %10 - dealloc_stack %2#0 : $*@local_storage P // id: %12 + %4 = open_existential_addr %2 : $*P to $*@opened("01234567-89ab-cdef-0123-000000000000") P // users: %8, %10 + dealloc_stack %2 : $*P // id: %12 destroy_addr %0 : $*P // id: %13 %14 = tuple () // user: %15 return %14 : $() // id: %15 diff --git a/test/IRGen/dynamic_self_metadata.swift b/test/IRGen/dynamic_self_metadata.swift index 4e51c24c83049..0cdf7dbbb2d2f 100644 --- a/test/IRGen/dynamic_self_metadata.swift +++ b/test/IRGen/dynamic_self_metadata.swift @@ -37,7 +37,6 @@ class C { // CHECK-LABEL: define hidden i64 @_TFC21dynamic_self_metadata1C19dynamicSelfArgumentfT_GSqDS0__(%C21dynamic_self_metadata1C*) // CHECK: [[CAST1:%.+]] = bitcast %C21dynamic_self_metadata1C* %0 to [[METATYPE:%.+]] // CHECK: [[TYPE1:%.+]] = call %swift.type* @swift_getObjectType([[METATYPE]] [[CAST1]]) - // CHECK: [[CAST2:%.+]] = bitcast %swift.type* [[TYPE1]] to i8* - // CHECK: [[TYPE2:%.+]] = call %swift.type* @swift_getGenericMetadata1(%swift.type_pattern* @_TMPSq, i8* [[CAST2]]) + // CHECK: [[TYPE2:%.+]] = call %swift.type* @_TMaSq(%swift.type* [[TYPE1]]) // CHECK: call void @_TF21dynamic_self_metadata2idurFxx({{.*}}, %swift.type* [[TYPE2]]) } diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil index 1a1affa4898e0..bf49b7a17cc2e 100644 --- a/test/IRGen/enum.sil +++ b/test/IRGen/enum.sil @@ -101,12 +101,11 @@ import Swift // we fill in on instantiation. // The witness table pattern includes extra inhabitant witness // implementations which are used if the instance has extra inhabitants. -// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private unnamed_addr constant [7 x i8] c"value\00\00" -// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private unnamed_addr constant [25 x i8] c"O4enum16DynamicSingleton\00" +// FIXME: Strings should be unnamed_addr. rdar://problem/22674524 +// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00" +// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [25 x i8] c"O4enum16DynamicSingleton\00" // CHECK: @_TMnO4enum16DynamicSingleton = constant { {{.*}} i32 } { -// -- 2 = enum -// CHECK: [[WORD:i64|i32]] 2, -// CHECK: i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[DYNAMICSINGLETON_NAME]] +// CHECK: [25 x i8]* [[DYNAMICSINGLETON_NAME]] // -- One payload // CHECK: i32 1, // -- No empty cases @@ -133,7 +132,7 @@ import Swift // CHECK: @_TWVO4enum10NoPayloads = constant [26 x i8*] [ // -- ... // -- size -// CHECK: i8* inttoptr ([[WORD]] 1 to i8*), +// CHECK: i8* inttoptr ([[WORD:i32|i64]] 1 to i8*), // -- flags 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses // CHECK: i8* inttoptr ([[WORD]] 2359296 to i8*), // -- stride @@ -2617,7 +2616,7 @@ bb4: // CHECK: define private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} { // CHECK: call void @swift_initEnumValueWitnessTableSinglePayload -// CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %Self) +// CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %StructWithWeakVar) // -- TODO: some pointless masking here. // -- TODO: should use EnumPayload word-chunking. // CHECK-64: %1 = zext i32 %index to i128 diff --git a/test/IRGen/enum_dynamic_multi_payload.sil b/test/IRGen/enum_dynamic_multi_payload.sil index 8a8ce3ec03037..fb4ae50758e01 100644 --- a/test/IRGen/enum_dynamic_multi_payload.sil +++ b/test/IRGen/enum_dynamic_multi_payload.sil @@ -42,27 +42,29 @@ entry(%e : $Either<(), ()>): fix_lifetime %e : $Either<(), ()> // CHECK-NEXT: alloca + // CHECK-NEXT: bitcast + // CHECK-NEXT: llvm.lifetime.start %s = alloc_stack $Either<(), ()> %l = enum $Either<(), ()>, #Either.Left!enumelt.1, undef : $() - // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast {{.*}} to i1* // CHECK-NEXT: store i1 false - store %l to %s#1 : $*Either<(), ()> + store %l to %s : $*Either<(), ()> %r = enum $Either<(), ()>, #Either.Right!enumelt.1, undef : $() - // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast {{.*}} to i1* // CHECK-NEXT: store i1 true - store %r to %s#1 : $*Either<(), ()> + store %r to %s : $*Either<(), ()> %a = unchecked_enum_data %l : $Either<(), ()>, #Either.Left!enumelt.1 %b = unchecked_enum_data %r : $Either<(), ()>, #Either.Right!enumelt.1 // CHECK-NEXT: switch - // CHECK-NEXT: i1 false, label %5 - // CHECK-NEXT: i1 true, label %6 - // CHECK: